Documentation
¶
Overview ¶
Package spotlib provides a client implementation for the Spot secure messaging protocol.
Spotlib enables secure, end-to-end encrypted communication between clients through the Spot network. It handles connection management, cryptographic identity, message routing, and provides both request-response and fire-and-forget messaging patterns.
Basic Usage ¶
Create a new client with an optional private key for identity:
client, err := spotlib.New()
if err != nil {
log.Fatal(err)
}
defer client.Close()
Wait for the client to come online:
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
if err := client.WaitOnline(ctx); err != nil {
log.Fatal(err)
}
Sending Messages ¶
Send an encrypted query and wait for a response:
response, err := client.Query(ctx, "k.targetID/endpoint", []byte("payload"))
Send a one-way encrypted message:
err := client.SendTo(ctx, "k.targetID/endpoint", []byte("payload"))
Receiving Messages ¶
Register a handler for incoming messages on an endpoint:
client.SetHandler("myendpoint", func(msg *spotproto.Message) ([]byte, error) {
// Process message and return response
return []byte("response"), nil
})
PacketConn Interface ¶
For UDP-like communication, use ListenPacket to get a net.PacketConn:
conn, err := client.ListenPacket("udp-endpoint")
if err != nil {
log.Fatal(err)
}
defer conn.Close()
Identity and Addressing ¶
Each client has a cryptographic identity represented by an IDCard. The client's address (TargetId) is derived from the SHA-256 hash of its public key and has the format "k.<base64url-encoded-hash>".
Messages to key-based addresses (starting with "k.") are automatically encrypted and signed. The recipient's public key is retrieved and cached automatically.
Index ¶
- func NewDiskStore() (*diskStore, error)
- func NewDiskStoreWithPath(path string) (*diskStore, error)
- func WithTimeout(ctx context.Context, timeout time.Duration, cb func(context.Context))
- type Client
- func (c *Client) Close() error
- func (c *Client) ConnectionCount() (uint32, uint32)
- func (c *Client) FetchBlob(ctx context.Context, key string) ([]byte, error)
- func (c *Client) GetGroupMembers(ctx context.Context, groupKey []byte) ([]string, error)
- func (c *Client) GetIDCard(ctx context.Context, h []byte) (*gobottle.IDCard, error)
- func (c *Client) GetIDCardBin(ctx context.Context, h []byte) ([]byte, error)
- func (c *Client) GetIDCardForRecipient(ctx context.Context, rcv string) (*gobottle.IDCard, error)
- func (c *Client) GetTime(ctx context.Context) (time.Time, error)
- func (c *Client) IDCard() *gobottle.IDCard
- func (c *Client) ListenPacket(name string) (net.PacketConn, error)
- func (c *Client) Query(ctx context.Context, target string, body []byte) ([]byte, error)
- func (c *Client) QueryTimeout(timeout time.Duration, target string, body []byte) ([]byte, error)
- func (c *Client) SendTo(ctx context.Context, target string, payload []byte) error
- func (c *Client) SendToWithFrom(ctx context.Context, target string, payload []byte, from string) error
- func (c *Client) SetHandler(endpoint string, handler MessageHandler)
- func (c *Client) StoreBlob(ctx context.Context, key string, value []byte) error
- func (c *Client) TargetId() string
- func (c *Client) WaitOnline(ctx context.Context) error
- type ClientData
- type InstantMessage
- type MessageHandler
- type SpotAddr
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func NewDiskStore ¶ added in v0.2.20
func NewDiskStore() (*diskStore, error)
NewDiskStore creates a new disk-based store for client data. Data is stored in filepath.Join(os.UserConfigDir(), "spot"). If no keys exist, a new ECDSA P-256 key is generated automatically.
func NewDiskStoreWithPath ¶ added in v0.2.20
NewDiskStoreWithPath creates a new disk-based store at the specified path. If path is empty, it defaults to filepath.Join(os.UserConfigDir(), "spot"). If no keys exist, a new ECDSA P-256 key is generated automatically.
func WithTimeout ¶ added in v0.2.3
WithTimeout makes it easy to call a method that requires a context with a specified timeout without having to worry about calling the cancel() method. Go typically suggests using defer, however if processing after a given method is called continues, there is a risk the cancel method will be called much later.
This method on the other hand performs the defer of cancel, which means that cancel will be called properly even in case of a panic.
Usage:
spotlib.WithTimeout(nil, 30*time.Second, func(ctx context.Context) {
res, err = c.methodWithCtx(ctx)
}
if err := nil { ...
Types ¶
type Client ¶ added in v0.0.3
type Client struct {
Events *emitter.Hub // event hub for client events (online, offline, etc.)
// contains filtered or unexported fields
}
Client holds information about a client, including its connections to the spot servers. It manages cryptographic identity, connection state, message handlers, and provides high-level methods for secure communication through the Spot protocol.
func New ¶ added in v0.0.3
New starts a new Client and establishes connection to the Spot system. If any key is passed, the first key will be used as the main signing key.
Parameters can include: - gobottle.PrivateKey or *gobottle.Keychain: keys to use for signing/encryption - *emitter.Hub: event hub to use instead of creating a new one - map[string]MessageHandler: initial message handlers to register - map[string]string: metadata to include in the client ID card
func (*Client) Close ¶ added in v0.1.1
Close gracefully shuts down the client and all its connections. This method is idempotent and safe to call multiple times.
func (*Client) ConnectionCount ¶ added in v0.0.4
ConnectionCount returns the number of spot server connections, and the number of said connections which are online (ie. past the handshake step).
func (*Client) FetchBlob ¶ added in v0.2.9
FetchBlob fetches a blob previously stored with StoreBlob. The operation can be slow and is provided as best effort. The data will be decrypted and verified.
func (*Client) GetGroupMembers ¶ added in v0.1.3
GetGroupMembers retrieves a list of member IDs for the specified group key
func (*Client) GetIDCard ¶ added in v0.0.6
GetIDCard returns the ID card for the given hash It first checks the local cache, and if not found, fetches it from the server. Also automatically subscribes to updates for this ID card.
func (*Client) GetIDCardBin ¶ added in v0.0.6
GetIDCardBin returns the binary ID card for the given hash This also automatically subscribes the client to updates for this ID card
func (*Client) GetIDCardForRecipient ¶ added in v0.0.6
GetIDCardForRecipient returns the ID Card of a given recipient, if any
func (*Client) GetTime ¶ added in v0.2.3
GetTime queries the Spot server for its current time. This can be used for clock synchronization or to verify server connectivity.
func (*Client) IDCard ¶ added in v0.0.6
IDCard returns the client's own identity card containing its public key and metadata
func (*Client) ListenPacket ¶ added in v0.1.4
func (c *Client) ListenPacket(name string) (net.PacketConn, error)
ListenPacket returns a net.PacketConn object that can be used to easily exchange encrypted packets with other peers without having to think about the underlying protocol details.
The name parameter defines the endpoint that will receive messages. Messages are automatically encrypted and signatures are verified.
func (*Client) Query ¶ added in v0.0.3
Query sends a request & waits for the response. If the target is a key (starts with k.) the message will be encrypted & signed so only the recipient can open it.
This is a blocking call that returns the response body or an error. The context can be used to set a timeout or cancel the operation.
func (*Client) QueryTimeout ¶ added in v0.0.6
QueryTimeout calls Query with the specified timeout duration as a convenience wrapper
func (*Client) SendToWithFrom ¶ added in v0.1.4
func (c *Client) SendToWithFrom(ctx context.Context, target string, payload []byte, from string) error
SendToWithFrom encrypts and sends a payload to the given target, with the option to set the sender endpoint
func (*Client) SetHandler ¶ added in v0.0.6
func (c *Client) SetHandler(endpoint string, handler MessageHandler)
SetHandler registers a handler function for a specific endpoint If handler is nil, removes any existing handler for the endpoint
func (*Client) StoreBlob ¶ added in v0.2.9
StoreBlob stores the given value under the given key after encrypting it in a way that can only be retrieved by this client specifically, using the same private key. This can be useful to store some settings local to the node that may need to be re-obtained, however this method is to be considered best-effort and shouldn't be used for intensive storage activity. Note also that value will have a limit of slightly less than 49kB.
Data may also be purged after some time without access.
type ClientData ¶ added in v0.2.20
type ClientData interface {
// Keychain returns a keychain with at least one private key for client identity
Keychain() *gobottle.Keychain
}
ClientData is an interface for providing client identity data including cryptographic keys. Implementations should return a keychain containing at least one private key for signing.
type InstantMessage ¶ added in v0.0.3
type InstantMessage struct {
ID uuid.UUID // Unique message identifier
Flags uint64 // Message flags for special handling
Recipient string // Target recipient identifier
Sender string // Source sender identifier
Body []byte // Actual message content
Encrypted bool // Whether the message was encrypted
SignedBy [][]byte // Contains the public keys that signed the message when decoding
}
InstantMessage represents a message with metadata, content, and cryptographic information
func DecodeInstantMessage ¶ added in v0.0.3
func DecodeInstantMessage(buf []byte, res *gobottle.OpenResult, err error) (*InstantMessage, error)
DecodeInstantMessage extracts an InstantMessage from a cryptographic bottle It verifies the contents and populates metadata fields based on the bottle headers
func (*InstantMessage) Bottle ¶ added in v0.0.3
func (im *InstantMessage) Bottle() *gobottle.Bottle
Bottle converts the InstantMessage into a cryptographic bottle for secure transmission
func (*InstantMessage) Bytes ¶ added in v0.0.3
func (im *InstantMessage) Bytes() []byte
Bytes serializes the InstantMessage into a byte array for transmission
func (*InstantMessage) MarshalBinary ¶ added in v0.0.3
func (im *InstantMessage) MarshalBinary() ([]byte, error)
MarshalBinary implements the BinaryMarshaler interface for serialization
func (*InstantMessage) ReadFrom ¶ added in v0.0.3
func (im *InstantMessage) ReadFrom(r io.Reader) (int64, error)
ReadFrom implements the ReaderFrom interface for streaming deserialization
func (*InstantMessage) UnmarshalBinary ¶ added in v0.0.3
func (im *InstantMessage) UnmarshalBinary(r []byte) error
UnmarshalBinary implements the BinaryUnmarshaler interface for deserialization
type MessageHandler ¶ added in v0.0.6
MessageHandler is a function type that processes incoming messages and optionally returns a response If an error is returned, it will be converted to an error message and sent back to the sender
type SpotAddr ¶ added in v0.1.4
type SpotAddr string
SpotAddr is a type implementing net.Addr that represents a spot address (typically, k.xxx/yyy) This allows using standard Go networking patterns with the Spot protocol