gkpxc

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 14, 2022 License: MIT Imports: 10 Imported by: 1

README

KeepassXC RPC client for Go

Go Reference Go Test

This library allows to interact with KeepassXC Browser Integration server. It's protocol not documented well but can be found in source code. This repository also contains additional "adapter" utilities for storing credentials in KeepassXC database.

Additional utilities

Usage

Protocol uses "request-response" model but also contains some asynchronous notifications. Typical workflow: 0. Create client

  1. Request database hash using Client.GetDatabaseHash.
  2. Lookup association credentials by received hash and use it Client.SetAssociationCredentials.
  3. Request a new association if such credentials was not found on step 2 using Client.Associate. Then get them using Client.AssociationCredentials and store in safe place.
  4. Optionally subscribe to asynchronous events.
  5. Make requests.
  6. Close client.

Example

package main

import (
	"context"
	"fmt"

	"github.com/xakep666/gkpxc"
)

func main() {
	client, err := gkpxc.NewClient(context.Background(), gkpxc.WithLockChangeHandler(func(locked bool) {
		fmt.Printf("lock changed: %t\n", locked)
	}))
	if err != nil {
		panic(err)
    }
	
	defer client.Close()

	dbHash, err := client.GetDatabaseHash(context.Background(), false)
	if err != nil {
		panic(err)
	}
	
	fmt.Printf("KeepassXC version: %s, Database hash: %s\n", dbHash.Version, dbHash.Hash)
	
	err = client.Associate(context.Background())
	if err != nil {
		panic(err)
    }
	
	associationCreds := client.AssociationCredentials()
	// store them somewhere
	fmt.Printf("Association ID: %s, Association private key: %v\n", associationCreds.ID, associationCreds.PrivateKey)
	
	groups, err := client.GetDatabaseGroups(context.Background())
	if err != nil {
		panic(err)
    }
	
	for _, group := range groups.Groups.Groups {
		fmt.Printf("Group UUID: %s, name: %s\n", group.UUID, group.Name)
    }
}

Testing

This library contains two kind of tests: unit and integration.

Unit-tests runs with just go test.

Integration tests adds some requirements:

  • KeepassXC at least 2.7.0 installed on your system
  • KeepassXC is not running
  • Requirements for additional utilities (see in corresponding README's).

To specify custom KeepassXC executable location use KEEPASSXC_EXECUTABLE environment variable (i.e. testing.yml).

To run integration tests use go test -tags integration ./....

Note that some tests contain long sleeps used to wait for KeepassXC startup.

Documentation

Index

Constants

View Source
const (
	NonceSize = 24
	KeySize   = 32
)
View Source
const SocketName = "org.keepassxc.KeePassXC.BrowserServer"

SocketName is a standard KeepassXC socket name.

Variables

View Source
var (
	// ErrDecryptFailed returns when response can't be decrypted.
	ErrDecryptFailed = fmt.Errorf("response decrypt failed")

	// ErrInvalidNonce returned if invalid nonce received in response.
	ErrInvalidNonce = fmt.Errorf("invalid nonce")

	// ErrClosing may be sent if operation interrupted by closing.
	ErrClosing = fmt.Errorf("closing")

	// ErrNotAssociated returned if method requires association with database but no credentials present.
	// In this case Client.Associate or Client.SetAssociationCredentials must be used.
	ErrNotAssociated = fmt.Errorf("not associated")
)

Functions

This section is empty.

Types

type AssociateRequest

type AssociateRequest struct {
	// Key is a public key from handshake.
	Key []byte `json:"key"`

	// IDKey is a public key for association.
	IDKey []byte `json:"idKey"`
}

AssociateRequest represents new client association request.

func (AssociateRequest) Action

func (AssociateRequest) Action() string

type AssociateResponse

type AssociateResponse struct {
	ErrorFields

	ID      string `json:"id"`
	Hash    string `json:"hash"`
	Version string `json:"version"`
}

AssociateResponse returned on successful association.

type AssociationCredentials

type AssociationCredentials struct {
	ID, Hash, Version     string // returned from KeepassXC
	PrivateKey, PublicKey [KeySize]byte
}

AssociationCredentials holds KeepassXC association credentials.

type AutoTypeRequest

type AutoTypeRequest struct {
	// Search is a search string for entry (URL or TLD).
	Search string `json:"search"`
}

AutoTypeRequest requests auto type by URL.

func (AutoTypeRequest) Action

func (AutoTypeRequest) Action() string

type AutoTypeResponse

type AutoTypeResponse struct {
	ErrorFields
}

AutoTypeResponse returned on AutoTypeRequest.

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client is a KeepassXC protocol client.

func NewClient

func NewClient(ctx context.Context, opts ...ClientOption) (*Client, error)

NewClient creates KeepassXC client. By default, it connects to internal socket/pipe and associates as new client. Typical workflow:

  1. Request database hash using Client.GetDatabaseHash.
  2. Lookup association credentials by received hash and use it (Client.SetAssociationCredentials).
  3. Request a new association if such credentials was not found on step 2 using Client.Associate. Then get them using Client.AssociationCredentials and store in safe place.
  4. Optionally subscribe to asynchronous events.
  5. Make requests.
  6. Close client.

func (*Client) Associate

func (c *Client) Associate(ctx context.Context) error

Associate requests a new association from KeepassXC and saves credentials.

func (*Client) AssociationCredentials

func (c *Client) AssociationCredentials() *AssociationCredentials

AssociationCredentials returns stored associations credentials. They're valid only for one database.

func (*Client) Close

func (c *Client) Close() error

Close stops sending and receiving messages.

func (*Client) CreateNewGroup

CreateNewGroup creates new group and returns it's uuid. Association credentials must present.

func (*Client) DeleteEntry

func (c *Client) DeleteEntry(ctx context.Context, req DeleteEntryRequest) error

DeleteEntry deletes entry.

func (*Client) GeneratePassword

func (c *Client) GeneratePassword(ctx context.Context) error

GeneratePassword requests to show generate password dialog.

func (*Client) GetDatabaseGroups

func (c *Client) GetDatabaseGroups(ctx context.Context) (DatabaseGroupsResponse, error)

GetDatabaseGroups returns database groups. Association credentials must present.

func (*Client) GetDatabaseHash

func (c *Client) GetDatabaseHash(ctx context.Context, triggerUnlock bool) (GetDatabaseHashResponse, error)

GetDatabaseHash may be used to lookup existing association credentials for database.

func (*Client) GetLogins

func (c *Client) GetLogins(ctx context.Context, req GetLoginsRequest) (GetLoginsResponse, error)

GetLogins queries for database entries by URL.

func (*Client) GetTOTP

func (c *Client) GetTOTP(ctx context.Context, req GetTOTPRequest) (GetTOTPResponse, error)

GetTOTP requests current TOTP value for entry.

func (*Client) LockDatabase

func (c *Client) LockDatabase(ctx context.Context) error

LockDatabase locks current database.

func (*Client) RequestAutoType

func (c *Client) RequestAutoType(ctx context.Context, req AutoTypeRequest) error

RequestAutoType requests password auto type by URL or TLD.

func (*Client) SetAssociationCredentials

func (c *Client) SetAssociationCredentials(cred *AssociationCredentials)

SetAssociationCredentials can be used to set association existing association credentials.

func (*Client) SetLogin

func (c *Client) SetLogin(ctx context.Context, req SetLoginRequest) error

SetLogin creates or updates existing login.

func (*Client) TestAssociate

func (c *Client) TestAssociate(ctx context.Context) error

TestAssociate tests association with database. Association credentials must present.

type ClientOption

type ClientOption func(o *clientConfig)

func WithAsyncErrorHandler

func WithAsyncErrorHandler(handler func(err error)) ClientOption

WithAsyncErrorHandler adds async error handler. Such errors may occur on signal read.

func WithConn

func WithConn(conn net.Conn) ClientOption

WithConn sets custom connection for client. It will not be closed by Client.Close.

func WithLockChangeHandler

func WithLockChangeHandler(handler func(locked bool)) ClientOption

WithLockChangeHandler adds lock/unlock signal handler.

type CreateNewGroupRequest

type CreateNewGroupRequest struct {
	Name string `json:"groupName"`
}

CreateNewGroupRequest represents new group creation request.

func (CreateNewGroupRequest) Action

func (CreateNewGroupRequest) Action() string

type CreateNewGroupResponse

type CreateNewGroupResponse struct {
	ErrorFields

	Name string `json:"name"`
	UUID string `json:"uuid"`
}

CreateNewGroupResponse contains newly created group id.

type DatabaseGroup

type DatabaseGroup struct {
	Name     string          `json:"name"`
	UUID     string          `json:"uuid"`
	Children []DatabaseGroup `json:"children"`
}

DatabaseGroup is item of group hierarchy.

type DatabaseGroupsRequest

type DatabaseGroupsRequest struct{}

DatabaseGroupsRequest request list of group hierarchy.

func (DatabaseGroupsRequest) Action

func (DatabaseGroupsRequest) Action() string

type DatabaseGroupsResponse

type DatabaseGroupsResponse struct {
	ErrorFields

	DefaultGroup            string         `json:"defaultGroup"`
	DefaultGroupAlwaysAllow bool           `json:"defaultGroupAlwaysAllow"`
	Groups                  GroupsEmbedded `json:"groups"`
}

DatabaseGroupsResponse contains group hierarchy present in database.

type DeleteEntryRequest

type DeleteEntryRequest struct {
	UUID string `json:"uuid"`
}

DeleteEntryRequest requests deletion entry by uuid.

func (DeleteEntryRequest) Action

func (DeleteEntryRequest) Action() string

type DeleteEntryResponse

type DeleteEntryResponse struct {
	ErrorFields
}

DeleteEntryResponse returned on DeleteEntryRequest.

type ErrorFields

type ErrorFields struct {
	Success *bool  `json:"success,string,omitempty"` // sometimes omitted
	Text    string `json:"error,omitempty"`
	Code    int    `json:"errorCode,string,omitempty"`
}

type ErrorResponse

type ErrorResponse struct {
	Text string
	Code int
}

ErrorResponse returned as error if KeepassXC responds with error.

func (*ErrorResponse) Error

func (e *ErrorResponse) Error() string

type GeneratePasswordRequest

type GeneratePasswordRequest struct{}

GeneratePasswordRequest requests to show generate password dialog.

func (GeneratePasswordRequest) Action

type GeneratePasswordResponse

type GeneratePasswordResponse struct {
	ErrorFields
}

GeneratePasswordResponse returned on GeneratePasswordRequest.

type GetDatabaseHashRequest

type GetDatabaseHashRequest struct{}

GetDatabaseHashRequest represents request for database hash.

func (GetDatabaseHashRequest) Action

func (GetDatabaseHashRequest) Action() string

type GetDatabaseHashResponse

type GetDatabaseHashResponse struct {
	ErrorFields

	Hash    string `json:"hash"`
	Version string `json:"version"`
}

GetDatabaseHashResponse returned as response for GetDatabaseHashRequest.

type GetLoginsRequest

type GetLoginsRequest struct {
	// URL credentials looked for.
	URL string `json:"url"`

	SubmitURL string     `json:"submitUrl"`
	HTTPAuth  string     `json:"httpAuth"`
	Keys      []LoginKey `json:"keys"`
}

GetLoginsRequest represents request for logins.

func (GetLoginsRequest) Action

func (GetLoginsRequest) Action() string

type GetLoginsResponse

type GetLoginsResponse struct {
	ErrorFields

	Count   int          `json:"count"`
	Entries []LoginEntry `json:"entries"`
}

GetLoginsResponse contains found logins.

type GetTOTPRequest

type GetTOTPRequest struct {
	// UUID is entry uuid.
	UUID string `json:"uuid"`
}

GetTOTPRequest requests current TOTP for entry.

func (GetTOTPRequest) Action

func (GetTOTPRequest) Action() string

type GetTOTPResponse

type GetTOTPResponse struct {
	ErrorFields

	TOTP string `json:"totp"`
}

GetTOTPResponse contains current TOTP for entry.

type GroupsEmbedded

type GroupsEmbedded struct {
	Groups []DatabaseGroup `json:"groups"`
}

type LockDatabaseRequest

type LockDatabaseRequest struct{}

LockDatabaseRequest requests to lock database.

func (LockDatabaseRequest) Action

func (LockDatabaseRequest) Action() string

type LockDatabaseResponse

type LockDatabaseResponse struct {
	ErrorFields
}

LockDatabaseResponse returned on LockDatabaseRequest.

type LoginEntry

type LoginEntry struct {
	UUID string `json:"uuid"`

	// Name is how it named in database.
	Name string `json:"name"`

	// Login contains user name.
	Login string `json:"login"`

	// Password contains password.
	Password string `json:"password"`

	// Expired is set when password expired according to entry expiration time.
	Expired bool `json:"expired,string"`
}

LoginEntry is a single database entry.

type LoginKey

type LoginKey struct {
	// ID is client id from association.
	ID string `json:"id"`

	// Key is client public key used for association.
	Key []byte `json:"key"`
}

type Message

type Message struct {
	ErrorFields

	// Action is a message type. I.e. "change-public-keys", "associate", ...
	Action string `json:"action"`

	// Message is base64-encoded encrypted message.
	Message []byte `json:"message,omitempty"`

	// Nonce is base64-encoded nonce.
	Nonce []byte `json:"nonce"`

	// ClientID needed to identify client if multiple ones used.
	ClientID []byte `json:"clientID"`

	// Version is KeepassXC version.
	Version string `json:"version,omitempty"`

	// PublicKey is base64-encoded public key used during handshake (Action="change-public-keys").
	PublicKey []byte `json:"publicKey,omitempty"`

	// TriggerUnlock requests database unlock.
	TriggerUnlock bool `json:"triggerUnlock,omitempty,string"`
}

Message represents message used to talk with KeepassXC.

type SetLoginRequest

type SetLoginRequest struct {
	URL             string `json:"url"`
	SubmitURL       string `json:"submitUrl"`
	Login           string `json:"login"`
	Password        string `json:"password"`
	Group           string `json:"group"`
	GroupUUID       string `json:"groupUuid"`
	UUID            string `json:"uuid"` // create new if empty
	DownloadFavicon bool   `json:"downloadFavicon,string"`
}

SetLoginRequest represents create or update login request.

func (SetLoginRequest) Action

func (SetLoginRequest) Action() string

type SetLoginResponse

type SetLoginResponse struct {
	ErrorFields
}

SetLoginResponse returned on SetLoginRequest.

type TestAssociateRequest

type TestAssociateRequest struct {
	// ID is database id from association.
	ID string `json:"id"`

	// Key is a public key for association.
	Key []byte `json:"key"`
}

TestAssociateRequest represents client association test request.

func (TestAssociateRequest) Action

func (TestAssociateRequest) Action() string

type TestAssociateResponse

type TestAssociateResponse struct {
	ErrorFields

	ID      string `json:"id"`
	Hash    string `json:"hash"`
	Version string `json:"version"`
}

TestAssociateResponse returned on successful association test.

Directories

Path Synopsis
internal

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL