spotproto

package module
v0.3.0 Latest Latest
Warning

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

Go to latest
Published: Dec 21, 2025 License: MIT Imports: 13 Imported by: 2

README

GoDoc

spotproto

Protocol definitions for Spot, a real-time messaging protocol between clients and servers. Messages are encrypted end-to-end between clients, ensuring that servers only relay opaque payloads without access to message contents.

Installation

go get github.com/KarpelesLab/spotproto

Overview

The protocol uses a simple packet format where the first byte encodes both the protocol version (upper 4 bits) and the packet type (lower 4 bits).

Packet Types
ID Type Description
0x0 PingPong Keep-alive packets, payload is echoed back
0x1 Handshake Authentication handshake (request/response)
0x2 InstantMsg Encrypted messages between clients
Handshake Flow
  1. Server sends HandshakeRequest containing server info, client ID, and a nonce
  2. Client responds with HandshakeResponse containing its public key and a signature over the request
  3. Server verifies the signature and completes the handshake
Message Format

Messages contain:

  • MessageID: 16-byte unique identifier
  • Flags: Control bits (response, error, encryption status)
  • Recipient/Sender: Client IDs in format type.server.target or type.target
  • Body: Message payload (encrypted end-to-end)
End-to-End Encryption

Message bodies are encrypted between clients using their exchanged public keys. The server acts only as a relay and cannot decrypt message contents. The MsgFlagNotBottle flag bypasses end-to-end encryption for cases where the payload is already encrypted by another protocol, or when performance is prioritized over E2E encryption (the connection to the server is still encrypted).

License

See LICENSE file.

Documentation

Overview

Package spotproto implements the spot protocol for real-time messaging between clients and servers.

Index

Constants

View Source
const (
	MsgFlagResponse  = 1 << iota // MsgFlagResponse indicates this is a response that must not trigger further responses
	MsgFlagError                 // MsgFlagError indicates the message body contains an error string
	MsgFlagNotBottle             // MsgFlagNotBottle bypasses E2E encryption (for pre-encrypted payloads or performance)
)

Message flags that control message handling behavior.

View Source
const (
	PingPong   = 0x0 // Ping/pong keep-alive packet
	Handshake  = 0x1 // Handshake request or response
	InstantMsg = 0x2 // Instant message packet
)

Packet type identifiers encoded in the lower 4 bits of the first byte.

Variables

View Source
var (
	// ErrEmptyBuf is returned when attempting to parse an empty buffer.
	ErrEmptyBuf = errors.New("empty buffer")
	// ErrInvalidVersion is returned when a packet has an unsupported protocol version.
	ErrInvalidVersion = errors.New("invalid packet version")
)

Sentinel errors returned by the protocol parser.

Functions

func VersionAndPacket

func VersionAndPacket(v byte) (byte, byte)

VersionAndPacket returns the version & packet ID for a given code byte

Types

type ClientId added in v0.2.0

type ClientId struct {
	Type     byte   // Type is the identifier type ('k' for key-based, 'c' for connection, etc.)
	ServerId string // ServerId is the server identifier (can be empty for global IDs)
	Target   string // Target is the specific identifier value (key hash, connection name, etc.)
}

ClientId represents a client identifier in the protocol. The format is "Type.ServerId.Target" or "Type.Target" if ServerId is empty.

func NewClientIdFromId added in v0.2.0

func NewClientIdFromId(id *gobottle.IDCard) *ClientId

NewClientIdFromId creates a new key-based ClientId from a cryptutil IDCard. The target is derived from the SHA-256 hash of the IDCard's public key.

func (*ClientId) String added in v0.2.0

func (c *ClientId) String() string

String returns the client ID in its canonical string format.

type HandshakeRequest added in v0.1.2

type HandshakeRequest struct {
	Ready      bool     `json:"rdy,omitempty"` // Ready indicates handshake completion when true
	ServerCode string   `json:"srv"`           // ServerCode is the short name of the server
	ClientId   string   `json:"cid"`           // ClientId is the assigned connection identifier
	Nonce      []byte   `json:"rnd"`           // Nonce is a random blob for authentication
	Groups     [][]byte `json:"grp"`           // Groups the client belongs to
	// contains filtered or unexported fields
}

HandshakeRequest is sent from server to client to initiate the handshake. It contains server identification and a nonce for authentication.

func (*HandshakeRequest) Bytes added in v0.1.2

func (p *HandshakeRequest) Bytes() []byte

Bytes serializes the handshake request to CBOR format.

func (*HandshakeRequest) Respond added in v0.1.2

func (p *HandshakeRequest) Respond(rawBuf []byte, s crypto.Signer) (*HandshakeResponse, error)

Respond generates a response to the current handshake start

type HandshakeResponse

type HandshakeResponse struct {
	ID  []byte `json:"id"`  // ID is an optional client identifier
	Key []byte `json:"key"` // Key is the client's PKIX-encoded public key
	Sig []byte `json:"sig"` // Sig is the signature over the request nonce
}

HandshakeResponse is sent from client to server in response to a HandshakeRequest. It contains the client's public key and a signature proving key ownership.

func (*HandshakeResponse) Bytes

func (p *HandshakeResponse) Bytes() []byte

Bytes serializes the handshake response to CBOR format.

type Message

type Message struct {
	MessageID [16]byte // MessageID is a unique identifier for the message
	Flags     uint64   // Flags control message handling (see MsgFlag* constants)
	Recipient string   // Recipient is the target client ID
	Sender    string   // Sender is the originating client ID
	Body      []byte   // Body contains the message payload
}

Message represents an instant message packet exchanged between clients.

func (*Message) Bytes

func (msg *Message) Bytes() []byte

Bytes serializes the message to its binary wire format.

func (*Message) IsEncrypted added in v0.1.7

func (msg *Message) IsEncrypted() bool

IsEncrypted returns if the message must be encrypted to be sent. This method can be used in handlers to ensure only encrypted messages are being handled.

func (*Message) ReadFrom

func (msg *Message) ReadFrom(r io.Reader) error

ReadFrom reads and decodes a message from the given reader.

func (*Message) UnmarshalBinary

func (msg *Message) UnmarshalBinary(b []byte) error

UnmarshalBinary decodes a message from its binary wire format.

type Packet

type Packet interface {
	// Bytes serializes the packet to its wire format.
	Bytes() []byte
}

Packet is the interface implemented by all protocol packet types.

func Parse

func Parse(buf []byte, isClient bool) (Packet, error)

Parse decodes a raw buffer into the appropriate Packet type. The isClient parameter indicates whether this is being parsed on the client side, which affects how handshake packets are interpreted.

type Ping

type Ping []byte

Ping represents a ping/pong packet used for connection keep-alive. The payload is echoed back unchanged.

func (Ping) Bytes

func (p Ping) Bytes() []byte

Bytes returns the raw ping payload.

Jump to

Keyboard shortcuts

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