Documentation
¶
Overview ¶
Package protocol is the SyncMyEnv sync protocol: wire types shared by the CLI and the server, plus a small HTTP client.
It is public on purpose. The server imports it (so client and server can't drift), and anyone auditing the zero-knowledge claim can read exactly what crosses the wire: account metadata, ciphertext, and opaque IDs. Never a plaintext value, path, or key.
Model (works over any blob store; the server adds auth + push):
keyring the wrapped vault key (keys.json) — safe to store remotely
objects/<id> sealed revisions; id = hex(sha256(ciphertext)), immutable
log append-only entries, each written by exactly one device
(device_id, device_seq) → object + sealed metadata payload
Devices only ever append to their own sequence, so there are no write conflicts on the server; merging happens on the clients.
Index ¶
- Constants
- func Discover(ctx context.Context, raw string, hc *http.Client) (string, error)
- func IsStatus(err error, status int) bool
- func ObjectID(ciphertext []byte) string
- func SigningMessage(vaultID string, deviceSeq int64, objectID string, payload []byte) []byte
- func ValidateURL(raw string) (string, error)
- type APIError
- type AppendLogRequest
- type AppendLogResponse
- type Client
- func (c *Client) AppendLog(ctx context.Context, vault string, entries []LogEntry) error
- func (c *Client) CreateVault(ctx context.Context, name string) (*Vault, error)
- func (c *Client) DeviceCode(ctx context.Context, name string) (*DeviceCodeResponse, error)
- func (c *Client) DeviceToken(ctx context.Context, deviceCode string) (*DeviceTokenResponse, error)
- func (c *Client) GetKeyring(ctx context.Context, vault string) ([]byte, error)
- func (c *Client) GetObject(ctx context.Context, vault, id string) ([]byte, error)
- func (c *Client) Me(ctx context.Context) (*Me, error)
- func (c *Client) PutKeyring(ctx context.Context, vault string, keyfile []byte) error
- func (c *Client) PutObject(ctx context.Context, vault string, data []byte) (string, error)
- func (c *Client) ReadLog(ctx context.Context, vault string, since int64) (*ReadLogResponse, error)
- func (c *Client) RevokeSelf(ctx context.Context) error
- func (c *Client) Vaults(ctx context.Context) ([]Vault, error)
- type CreateVaultRequest
- type Device
- type DeviceCodeRequest
- type DeviceCodeResponse
- type DeviceTokenRequest
- type DeviceTokenResponse
- type EntryPayload
- type ErrorBody
- type LogEntry
- type Me
- type ReadLogResponse
- type StoredEntry
- type User
- type Vault
- type VaultList
Constants ¶
const ( MaxObjectSize = 2 << 20 // bytes of ciphertext MaxPayloadSize = 16 << 10 MaxLogBatch = 200 )
Limits enforced by the server (and respected by the client).
const Version = 1
Version of the protocol spoken by this package.
Variables ¶
This section is empty.
Functions ¶
func Discover ¶ added in v0.1.3
Discover turns what the user typed into the URL of a SyncMyEnv server that actually answers. With an explicit scheme it only validates. Without one it probes https:// first and, for local/LAN hosts only, falls back to http:// — so "localhost:8443" works whether that port speaks TLS or not.
func ObjectID ¶
ObjectID is the content address of a ciphertext blob. Hashing ciphertext reveals nothing: age output is randomized.
func SigningMessage ¶
SigningMessage binds a signature to the vault, the device's sequence number, the object and the exact sealed payload (no cut-and-paste between vaults, positions or objects).
func ValidateURL ¶
ValidateURL normalizes a server address and requires https, except for localhost / private LAN development. Without a scheme, a public domain ("env.example.com") means https://; a local or private address ("localhost:8080", "192.168.1.20:8080") means http://.
Types ¶
type AppendLogRequest ¶
type AppendLogRequest struct {
Entries []LogEntry `json:"entries"`
}
type AppendLogResponse ¶
type AppendLogResponse struct {
Accepted int `json:"accepted"`
}
type Client ¶
Client talks to a SyncMyEnv server. Token is a device token (sme_dev_…).
func (*Client) CreateVault ¶
func (*Client) DeviceCode ¶
func (*Client) DeviceToken ¶
DeviceToken polls once. While waiting it returns an *APIError whose Code is authorization_pending or slow_down.
func (*Client) GetKeyring ¶
func (*Client) PutKeyring ¶
func (*Client) RevokeSelf ¶
RevokeSelf revokes this device's own token (logout).
type CreateVaultRequest ¶
type CreateVaultRequest struct {
Name string `json:"name"`
}
type DeviceCodeRequest ¶
type DeviceCodeResponse ¶
type DeviceTokenRequest ¶
type DeviceTokenRequest struct {
DeviceCode string `json:"device_code"`
}
type DeviceTokenResponse ¶
type EntryPayload ¶
type EntryPayload struct {
V int `json:"v"`
Path string `json:"path"` // "~/Projects/app/.env" (home-relative when possible)
Project string `json:"project"` // display name
Size int `json:"size"`
Source string `json:"source"` // protect | snapshot | restore
Device string `json:"device"` // human device name
CreatedAt int64 `json:"created_at"`
}
EntryPayload is the plaintext inside LogEntry.Payload. The server never sees it.
type ErrorBody ¶
type ErrorBody struct {
Error struct {
Code string `json:"code"`
Message string `json:"message"`
} `json:"error"`
}
ErrorBody is the server's error shape: {"error": {"code", "message"}}.
type LogEntry ¶
type LogEntry struct {
DeviceSeq int64 `json:"device_seq"`
ObjectID string `json:"object_id"`
Payload []byte `json:"payload"` // sealed EntryPayload (base64 in JSON)
DeviceKey []byte `json:"device_key"` // ed25519 public key
DeviceCert []byte `json:"device_cert"` // HMAC(vault cert key, DeviceKey)
Signature []byte `json:"signature"` // ed25519 over SigningMessage
}
LogEntry is written by one device. Payload is sealed to the vault recipient; the server stores it opaquely.
Authenticity: sealing to the vault recipient is something anyone who knows the public key can do — including the server. So each entry is signed by the device's Ed25519 key (Signature over SigningMessage), and the device key carries a certificate (DeviceCert) that only vault-key holders can create or verify. Clients drop entries that fail either check.
type ReadLogResponse ¶
type ReadLogResponse struct {
Entries []StoredEntry `json:"entries"`
Next int64 `json:"next"` // pass as ?since= to continue
More bool `json:"more"`
}
type StoredEntry ¶
type StoredEntry struct {
ID int64 `json:"id"` // global cursor, strictly increasing per vault
DeviceID string `json:"device_id"`
DeviceSeq int64 `json:"device_seq"`
ObjectID string `json:"object_id"`
Payload []byte `json:"payload"`
DeviceKey []byte `json:"device_key"`
DeviceCert []byte `json:"device_cert"`
Signature []byte `json:"signature"`
CreatedAt int64 `json:"created_at"`
}
StoredEntry is a log entry as read back, with server-assigned ordering.