From 60b713114bc911012521ad7db8bae4eccc46f9c5 Mon Sep 17 00:00:00 2001 From: Virgil Date: Fri, 27 Mar 2026 19:30:16 +0000 Subject: [PATCH] docs: populate package specs Generate specs for every Go package by reading the current source tree and documenting exported types, functions, and methods in a mirrored specs/ layout. Co-Authored-By: Virgil --- specs/auth/README.md | 521 +++++++++++++++++++++++++++ specs/cmd/crypt/README.md | 20 ++ specs/cmd/testcmd/README.md | 20 ++ specs/crypt/README.md | 250 +++++++++++++ specs/crypt/chachapoly/README.md | 30 ++ specs/crypt/lthn/README.md | 63 ++++ specs/crypt/openpgp/README.md | 69 ++++ specs/crypt/pgp/README.md | 77 ++++ specs/crypt/rsa/README.md | 56 +++ specs/trust/README.md | 599 +++++++++++++++++++++++++++++++ 10 files changed, 1705 insertions(+) create mode 100644 specs/auth/README.md create mode 100644 specs/cmd/crypt/README.md create mode 100644 specs/cmd/testcmd/README.md create mode 100644 specs/crypt/README.md create mode 100644 specs/crypt/chachapoly/README.md create mode 100644 specs/crypt/lthn/README.md create mode 100644 specs/crypt/openpgp/README.md create mode 100644 specs/crypt/pgp/README.md create mode 100644 specs/crypt/rsa/README.md create mode 100644 specs/trust/README.md diff --git a/specs/auth/README.md b/specs/auth/README.md new file mode 100644 index 0000000..0ee6a29 --- /dev/null +++ b/specs/auth/README.md @@ -0,0 +1,521 @@ +# auth + +**Import:** `dappco.re/go/core/crypt/auth` + +**Files:** 4 + +## Types + +### `Authenticator` + +```go +type Authenticator struct { + medium io.Medium + store SessionStore + hardwareKey HardwareKey // optional hardware key (nil = software only) + challenges map[string]*Challenge // userID -> pending challenge + mu sync.RWMutex // protects challenges map only + challengeTTL time.Duration + sessionTTL time.Duration +} +``` + +Authenticator manages PGP-based challenge-response authentication. +All user data and keys are persisted through an io.Medium, which may +be backed by disk, memory (MockMedium), or any other storage backend. +Sessions are persisted via a SessionStore (in-memory by default, +optionally SQLite-backed for crash recovery). + +An optional HardwareKey can be provided via WithHardwareKey for +hardware-backed cryptographic operations (PKCS#11, YubiKey, etc.). +See auth/hardware.go for the interface definition and integration points. +Usage: create an Authenticator with New(...) and then call Register, Login, or CreateChallenge. + +#### Methods + +##### `CreateChallenge` + +```go +func (a *Authenticator) CreateChallenge(userID string) (*Challenge, error) +``` + +CreateChallenge generates a cryptographic challenge for the given user. +A random nonce is created and encrypted with the user's PGP public key. +The client must decrypt the nonce and sign it to prove key ownership. +Usage: call CreateChallenge(...) during the package's normal workflow. + +##### `DeleteUser` + +```go +func (a *Authenticator) DeleteUser(userID string) error +``` + +DeleteUser removes a user and all associated keys from storage. +The "server" user is protected and cannot be deleted (mirroring the +original TypeScript implementation's safeguard). +Usage: call DeleteUser(...) during the package's normal workflow. + +##### `IsRevoked` + +```go +func (a *Authenticator) IsRevoked(userID string) bool +``` + +IsRevoked checks whether a user's key has been revoked by inspecting the +.rev file. Returns true only if the file contains valid revocation JSON +(not the legacy "REVOCATION_PLACEHOLDER" string). +Usage: call IsRevoked(...) during the package's normal workflow. + +##### `Login` + +```go +func (a *Authenticator) Login(userID, password string) (*Session, error) +``` + +Login performs password-based authentication as a convenience method. +It verifies the password against the stored hash and, on success, +creates a new session. This bypasses the PGP challenge-response flow. + +Hash format detection: + - If a .hash file exists, its content starts with "$argon2id$" and is verified + using constant-time Argon2id comparison. + - Otherwise, falls back to legacy .lthn file with LTHN hash verification. + On successful legacy login, the password is re-hashed with Argon2id and + a .hash file is written (transparent migration). + +Usage: call Login(...) for password-based flows when challenge-response is not required. + +##### `ReadResponseFile` + +```go +func (a *Authenticator) ReadResponseFile(userID, path string) (*Session, error) +``` + +ReadResponseFile reads a signed response from a file and validates it, +completing the air-gapped authentication flow. The file must contain the +raw PGP signature bytes (armored). +Usage: call ReadResponseFile(...) during the package's normal workflow. + +##### `RefreshSession` + +```go +func (a *Authenticator) RefreshSession(token string) (*Session, error) +``` + +RefreshSession extends the expiry of an existing valid session. +Usage: call RefreshSession(...) during the package's normal workflow. + +##### `Register` + +```go +func (a *Authenticator) Register(username, password string) (*User, error) +``` + +Register creates a new user account. It hashes the username with LTHN to +produce a userID, generates a PGP keypair (protected by the given password), +and persists the public key, private key, revocation placeholder, password +hash (Argon2id), and encrypted metadata via the Medium. +Usage: call Register(...) during the package's normal workflow. + +##### `RevokeKey` + +```go +func (a *Authenticator) RevokeKey(userID, password, reason string) error +``` + +RevokeKey marks a user's key as revoked. It verifies the password first, +writes a JSON revocation record to the .rev file (replacing the placeholder), +and invalidates all sessions for the user. +Usage: call RevokeKey(...) during the package's normal workflow. + +##### `RevokeSession` + +```go +func (a *Authenticator) RevokeSession(token string) error +``` + +RevokeSession removes a session, invalidating the token immediately. +Usage: call RevokeSession(...) during the package's normal workflow. + +##### `RotateKeyPair` + +```go +func (a *Authenticator) RotateKeyPair(userID, oldPassword, newPassword string) (*User, error) +``` + +RotateKeyPair generates a new PGP keypair for the given user, re-encrypts +their metadata with the new key, updates the password hash, and invalidates +all existing sessions. The caller must provide the current password +(oldPassword) to decrypt existing metadata and the new password (newPassword) +to protect the new keypair. +Usage: call RotateKeyPair(...) during the package's normal workflow. + +##### `StartCleanup` + +```go +func (a *Authenticator) StartCleanup(ctx context.Context, interval time.Duration) +``` + +StartCleanup runs a background goroutine that periodically removes expired +sessions from the store. It stops when the context is cancelled. +Usage: call StartCleanup(...) during the package's normal workflow. + +##### `ValidateResponse` + +```go +func (a *Authenticator) ValidateResponse(userID string, signedNonce []byte) (*Session, error) +``` + +ValidateResponse verifies a signed nonce from the client. The client must +have decrypted the challenge nonce and signed it with their private key. +On success, a new session is created and returned. +Usage: call ValidateResponse(...) during the package's normal workflow. + +##### `ValidateSession` + +```go +func (a *Authenticator) ValidateSession(token string) (*Session, error) +``` + +ValidateSession checks whether a token maps to a valid, non-expired session. +Usage: call ValidateSession(...) during the package's normal workflow. + +##### `WriteChallengeFile` + +```go +func (a *Authenticator) WriteChallengeFile(userID, path string) error +``` + +WriteChallengeFile writes an encrypted challenge to a file for air-gapped +(courier) transport. The challenge is created and then its encrypted nonce +is written to the specified path on the Medium. +Usage: call WriteChallengeFile(...) during the package's normal workflow. + + +### `Challenge` + +```go +type Challenge struct { + Nonce []byte `json:"nonce"` + Encrypted string `json:"encrypted"` // PGP-encrypted nonce (armored) + ExpiresAt time.Time `json:"expires_at"` +} +``` + +Challenge is a PGP-encrypted nonce sent to a client during authentication. +Usage: use Challenge with the other exported helpers in this package. + + +### `HardwareKey` + +```go +type HardwareKey interface { + // Sign produces a cryptographic signature over the given data using the + // hardware-stored private key. The signature format depends on the + // underlying device (e.g. ECDSA, RSA-PSS, EdDSA). + Sign(data []byte) ([]byte, error) + + // Decrypt decrypts ciphertext using the hardware-stored private key. + // The ciphertext format must match what the device expects (e.g. RSA-OAEP). + Decrypt(ciphertext []byte) ([]byte, error) + + // GetPublicKey returns the PEM or armored public key corresponding to the + // hardware-stored private key. + GetPublicKey() (string, error) + + // IsAvailable reports whether the hardware key device is currently + // connected and operational. Callers should check this before attempting + // Sign or Decrypt to provide graceful fallback behaviour. + IsAvailable() bool +} +``` + +HardwareKey defines the contract for hardware-backed cryptographic operations. +Implementations should wrap PKCS#11 tokens, YubiKeys, TPM modules, or +similar tamper-resistant devices. + +All methods must be safe for concurrent use. +Usage: implement HardwareKey and pass it to WithHardwareKey(...) to wire hardware-backed auth into New(...). + + +### `MemorySessionStore` + +```go +type MemorySessionStore struct { + mu sync.RWMutex + sessions map[string]*Session +} +``` + +MemorySessionStore is an in-memory SessionStore backed by a map. +Usage: use MemorySessionStore with the other exported helpers in this package. + +#### Methods + +##### `Cleanup` + +```go +func (m *MemorySessionStore) Cleanup() (int, error) +``` + +Cleanup removes all expired sessions and returns the count removed. +Usage: call Cleanup(...) during the package's normal workflow. + +##### `Delete` + +```go +func (m *MemorySessionStore) Delete(token string) error +``` + +Delete removes a session by token. +Usage: call Delete(...) during the package's normal workflow. + +##### `DeleteByUser` + +```go +func (m *MemorySessionStore) DeleteByUser(userID string) error +``` + +DeleteByUser removes all sessions belonging to the given user. +Usage: call DeleteByUser(...) during the package's normal workflow. + +##### `Get` + +```go +func (m *MemorySessionStore) Get(token string) (*Session, error) +``` + +Get retrieves a session by token. +Usage: call Get(...) during the package's normal workflow. + +##### `Set` + +```go +func (m *MemorySessionStore) Set(session *Session) error +``` + +Set stores a session, keyed by its token. +Usage: call Set(...) during the package's normal workflow. + + +### `Option` + +```go +type Option func(*Authenticator) +``` + +Option configures an Authenticator. +Usage: use Option with the other exported helpers in this package. + + +### `Revocation` + +```go +type Revocation struct { + UserID string `json:"user_id"` + Reason string `json:"reason"` + RevokedAt time.Time `json:"revoked_at"` +} +``` + +Revocation records the details of a revoked user key. +Stored as JSON in the user's .rev file, replacing the legacy placeholder. +Usage: use Revocation with the other exported helpers in this package. + + +### `SQLiteSessionStore` + +```go +type SQLiteSessionStore struct { + mu sync.Mutex + store *store.Store +} +``` + +SQLiteSessionStore is a SessionStore backed by core/store (SQLite KV). +A mutex serialises all operations because SQLite is single-writer. +Usage: use SQLiteSessionStore with the other exported helpers in this package. + +#### Methods + +##### `Cleanup` + +```go +func (s *SQLiteSessionStore) Cleanup() (int, error) +``` + +Cleanup removes all expired sessions and returns the count removed. +Usage: call Cleanup(...) during the package's normal workflow. + +##### `Close` + +```go +func (s *SQLiteSessionStore) Close() error +``` + +Close closes the underlying SQLite store. +Usage: call Close(...) during the package's normal workflow. + +##### `Delete` + +```go +func (s *SQLiteSessionStore) Delete(token string) error +``` + +Delete removes a session by token from SQLite. +Usage: call Delete(...) during the package's normal workflow. + +##### `DeleteByUser` + +```go +func (s *SQLiteSessionStore) DeleteByUser(userID string) error +``` + +DeleteByUser removes all sessions belonging to the given user. +Usage: call DeleteByUser(...) during the package's normal workflow. + +##### `Get` + +```go +func (s *SQLiteSessionStore) Get(token string) (*Session, error) +``` + +Get retrieves a session by token from SQLite. +Usage: call Get(...) during the package's normal workflow. + +##### `Set` + +```go +func (s *SQLiteSessionStore) Set(session *Session) error +``` + +Set stores a session in SQLite, keyed by its token. +Usage: call Set(...) during the package's normal workflow. + + +### `Session` + +```go +type Session struct { + Token string `json:"token"` + UserID string `json:"user_id"` + ExpiresAt time.Time `json:"expires_at"` +} +``` + +Session represents an authenticated session. +Usage: use Session with the other exported helpers in this package. + + +### `SessionStore` + +```go +type SessionStore interface { + Get(token string) (*Session, error) + Set(session *Session) error + Delete(token string) error + DeleteByUser(userID string) error + Cleanup() (int, error) // Remove expired sessions, return count removed +} +``` + +SessionStore abstracts session persistence. +Usage: use SessionStore with the other exported helpers in this package. + + +### `User` + +```go +type User struct { + PublicKey string `json:"public_key"` + KeyID string `json:"key_id"` + Fingerprint string `json:"fingerprint"` + PasswordHash string `json:"password_hash"` // Argon2id (new) or LTHN (legacy) + Created time.Time `json:"created"` + LastLogin time.Time `json:"last_login"` +} +``` + +User represents a registered user with PGP credentials. +Usage: use User with the other exported helpers in this package. + +## Functions + +### `New` + +```go +func New(m io.Medium, opts ...Option) *Authenticator +``` + +New creates an Authenticator that persists user data via the given Medium. +By default, sessions are stored in memory. Use WithSessionStore to provide +a persistent implementation (e.g. SQLiteSessionStore). +Usage: call New(...) to create a ready-to-use value. + + +### `NewMemorySessionStore` + +```go +func NewMemorySessionStore() *MemorySessionStore +``` + +NewMemorySessionStore creates a new in-memory session store. +Usage: call NewMemorySessionStore(...) to create a ready-to-use value. + + +### `NewSQLiteSessionStore` + +```go +func NewSQLiteSessionStore(dbPath string) (*SQLiteSessionStore, error) +``` + +NewSQLiteSessionStore creates a new SQLite-backed session store. +Use ":memory:" for testing or a file path for persistent storage. +Usage: call NewSQLiteSessionStore(...) to create a ready-to-use value. + + +### `WithChallengeTTL` + +```go +func WithChallengeTTL(d time.Duration) Option +``` + +WithChallengeTTL sets the lifetime of a challenge before it expires. +Usage: pass WithChallengeTTL(...) into the related constructor to adjust the default behaviour. + + +### `WithHardwareKey` + +```go +func WithHardwareKey(hk HardwareKey) Option +``` + +WithHardwareKey configures the Authenticator to use a hardware key for +cryptographic operations where supported. When set, the Authenticator may +delegate signing, decryption, and public key retrieval to the hardware +device instead of using software PGP keys. + +This is a forward-looking option — integration points are documented in +auth.go but not yet wired up. +Usage: pass WithHardwareKey(...) into New(...) to enable a HardwareKey implementation. + + +### `WithSessionStore` + +```go +func WithSessionStore(s SessionStore) Option +``` + +WithSessionStore sets the SessionStore implementation. +If not provided, an in-memory store is used (sessions lost on restart). +Usage: pass WithSessionStore(...) into the related constructor to adjust the default behaviour. + + +### `WithSessionTTL` + +```go +func WithSessionTTL(d time.Duration) Option +``` + +WithSessionTTL sets the lifetime of a session before it expires. +Usage: pass WithSessionTTL(...) into the related constructor to adjust the default behaviour. \ No newline at end of file diff --git a/specs/cmd/crypt/README.md b/specs/cmd/crypt/README.md new file mode 100644 index 0000000..6a28c64 --- /dev/null +++ b/specs/cmd/crypt/README.md @@ -0,0 +1,20 @@ +# crypt + +**Import:** `dappco.re/go/core/crypt/cmd/crypt` + +**Files:** 5 + +## Types + +None. + +## Functions + +### `AddCryptCommands` + +```go +func AddCryptCommands(root *cli.Command) +``` + +AddCryptCommands registers the 'crypt' command group and all subcommands. +Usage: call AddCryptCommands(...) during the package's normal workflow. \ No newline at end of file diff --git a/specs/cmd/testcmd/README.md b/specs/cmd/testcmd/README.md new file mode 100644 index 0000000..3963d38 --- /dev/null +++ b/specs/cmd/testcmd/README.md @@ -0,0 +1,20 @@ +# testcmd + +**Import:** `dappco.re/go/core/crypt/cmd/testcmd` + +**Files:** 4 + +## Types + +None. + +## Functions + +### `AddTestCommands` + +```go +func AddTestCommands(root *cli.Command) +``` + +AddTestCommands registers the 'test' command and all subcommands. +Usage: call AddTestCommands(...) during the package's normal workflow. \ No newline at end of file diff --git a/specs/crypt/README.md b/specs/crypt/README.md new file mode 100644 index 0000000..254737c --- /dev/null +++ b/specs/crypt/README.md @@ -0,0 +1,250 @@ +# crypt + +**Import:** `dappco.re/go/core/crypt/crypt` + +**Files:** 6 + +## Types + +None. + +## Functions + +### `AESGCMDecrypt` + +```go +func AESGCMDecrypt(ciphertext, key []byte) ([]byte, error) +``` + +AESGCMDecrypt decrypts ciphertext encrypted with AESGCMEncrypt. +The key must be 32 bytes. Expects the nonce prepended to the ciphertext. +Usage: call AESGCMDecrypt(...) during the package's normal workflow. + + +### `AESGCMEncrypt` + +```go +func AESGCMEncrypt(plaintext, key []byte) ([]byte, error) +``` + +AESGCMEncrypt encrypts plaintext using AES-256-GCM. +The key must be 32 bytes. The nonce is randomly generated and prepended +to the ciphertext. +Usage: call AESGCMEncrypt(...) during the package's normal workflow. + + +### `ChaCha20Decrypt` + +```go +func ChaCha20Decrypt(ciphertext, key []byte) ([]byte, error) +``` + +ChaCha20Decrypt decrypts ciphertext encrypted with ChaCha20Encrypt. +The key must be 32 bytes. Expects the nonce prepended to the ciphertext. +Usage: call ChaCha20Decrypt(...) during the package's normal workflow. + + +### `ChaCha20Encrypt` + +```go +func ChaCha20Encrypt(plaintext, key []byte) ([]byte, error) +``` + +ChaCha20Encrypt encrypts plaintext using ChaCha20-Poly1305. +The key must be 32 bytes. The nonce is randomly generated and prepended +to the ciphertext. +Usage: call ChaCha20Encrypt(...) during the package's normal workflow. + + +### `Decrypt` + +```go +func Decrypt(ciphertext, passphrase []byte) ([]byte, error) +``` + +Decrypt decrypts data encrypted with Encrypt. +Expects format: salt (16 bytes) + nonce (24 bytes) + ciphertext. +Usage: call Decrypt(...) during the package's normal workflow. + + +### `DecryptAES` + +```go +func DecryptAES(ciphertext, passphrase []byte) ([]byte, error) +``` + +DecryptAES decrypts data encrypted with EncryptAES. +Expects format: salt (16 bytes) + nonce (12 bytes) + ciphertext. +Usage: call DecryptAES(...) during the package's normal workflow. + + +### `DeriveKey` + +```go +func DeriveKey(passphrase, salt []byte, keyLen uint32) []byte +``` + +DeriveKey derives a key from a passphrase using Argon2id with default parameters. +The salt must be argon2SaltLen bytes. keyLen specifies the desired key length. +Usage: call DeriveKey(...) during the package's normal workflow. + + +### `DeriveKeyScrypt` + +```go +func DeriveKeyScrypt(passphrase, salt []byte, keyLen int) ([]byte, error) +``` + +DeriveKeyScrypt derives a key from a passphrase using scrypt. +Uses recommended parameters: N=32768, r=8, p=1. +Usage: call DeriveKeyScrypt(...) during the package's normal workflow. + + +### `Encrypt` + +```go +func Encrypt(plaintext, passphrase []byte) ([]byte, error) +``` + +Encrypt encrypts data with a passphrase using ChaCha20-Poly1305. +A random salt is generated and prepended to the output. +Format: salt (16 bytes) + nonce (24 bytes) + ciphertext. +Usage: call Encrypt(...) during the package's normal workflow. + + +### `EncryptAES` + +```go +func EncryptAES(plaintext, passphrase []byte) ([]byte, error) +``` + +EncryptAES encrypts data using AES-256-GCM with a passphrase. +A random salt is generated and prepended to the output. +Format: salt (16 bytes) + nonce (12 bytes) + ciphertext. +Usage: call EncryptAES(...) during the package's normal workflow. + + +### `HKDF` + +```go +func HKDF(secret, salt, info []byte, keyLen int) ([]byte, error) +``` + +HKDF derives a key using HKDF-SHA256. +secret is the input keying material, salt is optional (can be nil), +info is optional context, and keyLen is the desired output length. +Usage: call HKDF(...) during the package's normal workflow. + + +### `HMACSHA256` + +```go +func HMACSHA256(message, key []byte) []byte +``` + +HMACSHA256 computes the HMAC-SHA256 of a message using the given key. +Usage: call HMACSHA256(...) during the package's normal workflow. + + +### `HMACSHA512` + +```go +func HMACSHA512(message, key []byte) []byte +``` + +HMACSHA512 computes the HMAC-SHA512 of a message using the given key. +Usage: call HMACSHA512(...) during the package's normal workflow. + + +### `HashBcrypt` + +```go +func HashBcrypt(password string, cost int) (string, error) +``` + +HashBcrypt hashes a password using bcrypt with the given cost. +Cost must be between bcrypt.MinCost and bcrypt.MaxCost. +Usage: call HashBcrypt(...) during the package's normal workflow. + + +### `HashPassword` + +```go +func HashPassword(password string) (string, error) +``` + +HashPassword hashes a password using Argon2id with default parameters. +Returns a string in the format: $argon2id$v=19$m=65536,t=3,p=4$$ +Usage: call HashPassword(...) during the package's normal workflow. + + +### `SHA256File` + +```go +func SHA256File(path string) (string, error) +``` + +SHA256File computes the SHA-256 checksum of a file and returns it as a hex string. +Usage: call SHA256File(...) during the package's normal workflow. + + +### `SHA256Sum` + +```go +func SHA256Sum(data []byte) string +``` + +SHA256Sum computes the SHA-256 checksum of data and returns it as a hex string. +Usage: call SHA256Sum(...) during the package's normal workflow. + + +### `SHA512File` + +```go +func SHA512File(path string) (string, error) +``` + +SHA512File computes the SHA-512 checksum of a file and returns it as a hex string. +Usage: call SHA512File(...) during the package's normal workflow. + + +### `SHA512Sum` + +```go +func SHA512Sum(data []byte) string +``` + +SHA512Sum computes the SHA-512 checksum of data and returns it as a hex string. +Usage: call SHA512Sum(...) during the package's normal workflow. + + +### `VerifyBcrypt` + +```go +func VerifyBcrypt(password, hash string) (bool, error) +``` + +VerifyBcrypt verifies a password against a bcrypt hash. +Usage: call VerifyBcrypt(...) during the package's normal workflow. + + +### `VerifyHMAC` + +```go +func VerifyHMAC(message, key, mac []byte, hashFunc func() hash.Hash) bool +``` + +VerifyHMAC verifies an HMAC using constant-time comparison. +hashFunc should be sha256.New, sha512.New, etc. +Usage: call VerifyHMAC(...) during the package's normal workflow. + + +### `VerifyPassword` + +```go +func VerifyPassword(password, hash string) (bool, error) +``` + +VerifyPassword verifies a password against an Argon2id hash string. +The hash must be in the format produced by HashPassword. +Usage: call VerifyPassword(...) during the package's normal workflow. \ No newline at end of file diff --git a/specs/crypt/chachapoly/README.md b/specs/crypt/chachapoly/README.md new file mode 100644 index 0000000..8f081c9 --- /dev/null +++ b/specs/crypt/chachapoly/README.md @@ -0,0 +1,30 @@ +# chachapoly + +**Import:** `dappco.re/go/core/crypt/crypt/chachapoly` + +**Files:** 1 + +## Types + +None. + +## Functions + +### `Decrypt` + +```go +func Decrypt(ciphertext []byte, key []byte) ([]byte, error) +``` + +Decrypt decrypts data using ChaCha20-Poly1305. +Usage: call Decrypt(...) during the package's normal workflow. + + +### `Encrypt` + +```go +func Encrypt(plaintext []byte, key []byte) ([]byte, error) +``` + +Encrypt encrypts data using ChaCha20-Poly1305. +Usage: call Encrypt(...) during the package's normal workflow. \ No newline at end of file diff --git a/specs/crypt/lthn/README.md b/specs/crypt/lthn/README.md new file mode 100644 index 0000000..63516f0 --- /dev/null +++ b/specs/crypt/lthn/README.md @@ -0,0 +1,63 @@ +# lthn + +**Import:** `dappco.re/go/core/crypt/crypt/lthn` + +**Files:** 1 + +## Types + +None. + +## Functions + +### `GetKeyMap` + +```go +func GetKeyMap() map[rune]rune +``` + +GetKeyMap returns the current character substitution map. +Usage: call GetKeyMap(...) during the package's normal workflow. + + +### `Hash` + +```go +func Hash(input string) string +``` + +Hash computes the LTHN hash of the input string. + +The algorithm: + 1. Derive a quasi-salt by reversing the input and applying character substitutions + 2. Concatenate: input + salt + 3. Compute SHA-256 of the concatenated string + 4. Return the hex-encoded digest (64 characters, lowercase) + +The same input always produces the same hash, enabling verification +without storing a separate salt value. +Usage: call Hash(...) when you need a deterministic content-style digest rather than a password hash. + + +### `SetKeyMap` + +```go +func SetKeyMap(newKeyMap map[rune]rune) +``` + +SetKeyMap replaces the default character substitution map. +Use this to customize the quasi-salt derivation for specific applications. +Changes affect all subsequent Hash and Verify calls. +Usage: call SetKeyMap(...) during the package's normal workflow. + + +### `Verify` + +```go +func Verify(input string, hash string) bool +``` + +Verify checks if an input string produces the given hash. +Returns true if Hash(input) equals the provided hash value. +Uses constant-time comparison to prevent timing attacks. +Usage: call Verify(...) during the package's normal workflow. \ No newline at end of file diff --git a/specs/crypt/openpgp/README.md b/specs/crypt/openpgp/README.md new file mode 100644 index 0000000..a327f34 --- /dev/null +++ b/specs/crypt/openpgp/README.md @@ -0,0 +1,69 @@ +# openpgp + +**Import:** `dappco.re/go/core/crypt/crypt/openpgp` + +**Files:** 1 + +## Types + +### `Service` + +```go +type Service struct { + core *framework.Core +} +``` + +Service provides OpenPGP cryptographic operations. +Usage: use Service with the other exported helpers in this package. + +#### Methods + +##### `CreateKeyPair` + +```go +func (s *Service) CreateKeyPair(name, passphrase string) (string, error) +``` + +CreateKeyPair generates a new RSA-4096 PGP keypair. +Returns the armored private key string. +Usage: call CreateKeyPair(...) during the package's normal workflow. + +##### `DecryptPGP` + +```go +func (s *Service) DecryptPGP(privateKey, message, passphrase string, opts ...any) (string, error) +``` + +DecryptPGP decrypts a PGP message using the provided armored private key and passphrase. +Usage: call DecryptPGP(...) during the package's normal workflow. + +##### `EncryptPGP` + +```go +func (s *Service) EncryptPGP(writer goio.Writer, recipientPath, data string, opts ...any) (string, error) +``` + +EncryptPGP encrypts data for a recipient identified by their public key (armored string in recipientPath). +The encrypted data is written to the provided writer and also returned as an armored string. +Usage: call EncryptPGP(...) during the package's normal workflow. + +##### `HandleIPCEvents` + +```go +func (s *Service) HandleIPCEvents(c *framework.Core, msg framework.Message) error +``` + +HandleIPCEvents handles PGP-related IPC messages. +Usage: call HandleIPCEvents(...) during the package's normal workflow. + +## Functions + +### `New` + +```go +func New(c *framework.Core) (any, error) +``` + +New creates a new OpenPGP service instance. +Usage: call New(...) to create a ready-to-use value. \ No newline at end of file diff --git a/specs/crypt/pgp/README.md b/specs/crypt/pgp/README.md new file mode 100644 index 0000000..0fdd157 --- /dev/null +++ b/specs/crypt/pgp/README.md @@ -0,0 +1,77 @@ +# pgp + +**Import:** `dappco.re/go/core/crypt/crypt/pgp` + +**Files:** 1 + +## Types + +### `KeyPair` + +```go +type KeyPair struct { + PublicKey string + PrivateKey string +} +``` + +KeyPair holds armored PGP public and private keys. +Usage: use KeyPair with the other exported helpers in this package. + +## Functions + +### `CreateKeyPair` + +```go +func CreateKeyPair(name, email, password string) (*KeyPair, error) +``` + +CreateKeyPair generates a new PGP key pair for the given identity. +If password is non-empty, the private key is encrypted with it. +Returns a KeyPair with armored public and private keys. +Usage: call CreateKeyPair(...) during the package's normal workflow. + + +### `Decrypt` + +```go +func Decrypt(data []byte, privateKeyArmor, password string) ([]byte, error) +``` + +Decrypt decrypts armored PGP data using the given armored private key. +If the private key is encrypted, the password is used to decrypt it first. +Usage: call Decrypt(...) during the package's normal workflow. + + +### `Encrypt` + +```go +func Encrypt(data []byte, publicKeyArmor string) ([]byte, error) +``` + +Encrypt encrypts data for the recipient identified by their armored public key. +Returns the encrypted data as armored PGP output. +Usage: call Encrypt(...) during the package's normal workflow. + + +### `Sign` + +```go +func Sign(data []byte, privateKeyArmor, password string) ([]byte, error) +``` + +Sign creates an armored detached signature for the given data using +the armored private key. If the key is encrypted, the password is used +to decrypt it first. +Usage: call Sign(...) during the package's normal workflow. + + +### `Verify` + +```go +func Verify(data, signature []byte, publicKeyArmor string) error +``` + +Verify verifies an armored detached signature against the given data +and armored public key. Returns nil if the signature is valid. +Usage: call Verify(...) during the package's normal workflow. \ No newline at end of file diff --git a/specs/crypt/rsa/README.md b/specs/crypt/rsa/README.md new file mode 100644 index 0000000..2ca7857 --- /dev/null +++ b/specs/crypt/rsa/README.md @@ -0,0 +1,56 @@ +# rsa + +**Import:** `dappco.re/go/core/crypt/crypt/rsa` + +**Files:** 1 + +## Types + +### `Service` + +```go +type Service struct{} +``` + +Service provides RSA functionality. +Usage: use Service with the other exported helpers in this package. + +#### Methods + +##### `Decrypt` + +```go +func (s *Service) Decrypt(privateKey, ciphertext, label []byte) ([]byte, error) +``` + +Decrypt decrypts data with a private key. +Usage: call Decrypt(...) during the package's normal workflow. + +##### `Encrypt` + +```go +func (s *Service) Encrypt(publicKey, data, label []byte) ([]byte, error) +``` + +Encrypt encrypts data with a public key. +Usage: call Encrypt(...) during the package's normal workflow. + +##### `GenerateKeyPair` + +```go +func (s *Service) GenerateKeyPair(bits int) (publicKey, privateKey []byte, err error) +``` + +GenerateKeyPair creates a new RSA key pair. +Usage: call GenerateKeyPair(...) during the package's normal workflow. + +## Functions + +### `NewService` + +```go +func NewService() *Service +``` + +NewService creates and returns a new Service instance for performing RSA-related operations. +Usage: call NewService(...) to create a ready-to-use value. \ No newline at end of file diff --git a/specs/trust/README.md b/specs/trust/README.md new file mode 100644 index 0000000..1b1b7d1 --- /dev/null +++ b/specs/trust/README.md @@ -0,0 +1,599 @@ +# trust + +**Import:** `dappco.re/go/core/crypt/trust` + +**Files:** 5 + +## Types + +### `Agent` + +```go +type Agent struct { + // Name is the unique identifier for the agent (e.g., "Athena", "Clotho"). + Name string + // Tier is the agent's trust level. + Tier Tier + // ScopedRepos limits repo access for Tier 2 agents. Empty means no repo access. + // Tier 3 agents ignore this field (they have access to all repos). + ScopedRepos []string + // RateLimit is the maximum requests per minute. 0 means unlimited. + RateLimit int + // TokenExpiresAt is when the agent's token expires. + TokenExpiresAt time.Time + // CreatedAt is when the agent was registered. + CreatedAt time.Time +} +``` + +Agent represents an agent identity in the trust system. +Usage: use Agent with the other exported helpers in this package. + + +### `ApprovalQueue` + +```go +type ApprovalQueue struct { + mu sync.RWMutex + requests map[string]*ApprovalRequest + nextID int +} +``` + +ApprovalQueue manages pending approval requests for NeedsApproval decisions. +Usage: use ApprovalQueue with the other exported helpers in this package. + +#### Methods + +##### `Approve` + +```go +func (q *ApprovalQueue) Approve(id string, reviewedBy string, reason string) error +``` + +Approve marks a pending request as approved. Returns an error if the +request is not found or is not in pending status. +Usage: call Approve(...) during the package's normal workflow. + +##### `Deny` + +```go +func (q *ApprovalQueue) Deny(id string, reviewedBy string, reason string) error +``` + +Deny marks a pending request as denied. Returns an error if the +request is not found or is not in pending status. +Usage: call Deny(...) during the package's normal workflow. + +##### `Get` + +```go +func (q *ApprovalQueue) Get(id string) *ApprovalRequest +``` + +Get returns the approval request with the given ID, or nil if not found. +Usage: call Get(...) during the package's normal workflow. + +##### `Len` + +```go +func (q *ApprovalQueue) Len() int +``` + +Len returns the total number of requests in the queue. +Usage: call Len(...) during the package's normal workflow. + +##### `Pending` + +```go +func (q *ApprovalQueue) Pending() []ApprovalRequest +``` + +Pending returns all requests with ApprovalPending status. +Usage: call Pending(...) during the package's normal workflow. + +##### `PendingSeq` + +```go +func (q *ApprovalQueue) PendingSeq() iter.Seq[ApprovalRequest] +``` + +PendingSeq returns an iterator over all requests with ApprovalPending status. +Usage: call PendingSeq(...) during the package's normal workflow. + +##### `Submit` + +```go +func (q *ApprovalQueue) Submit(agent string, cap Capability, repo string) (string, error) +``` + +Submit creates a new approval request and returns its ID. +Returns an error if the agent name or capability is empty. +Usage: call Submit(...) during the package's normal workflow. + + +### `ApprovalRequest` + +```go +type ApprovalRequest struct { + // ID is the unique identifier for this request. + ID string + // Agent is the name of the requesting agent. + Agent string + // Cap is the capability being requested. + Cap Capability + // Repo is the optional repo context for repo-scoped capabilities. + Repo string + // Status is the current approval status. + Status ApprovalStatus + // Reason is a human-readable explanation from the reviewer. + Reason string + // RequestedAt is when the request was created. + RequestedAt time.Time + // ReviewedAt is when the request was reviewed (zero if pending). + ReviewedAt time.Time + // ReviewedBy is the name of the admin who reviewed the request. + ReviewedBy string +} +``` + +ApprovalRequest represents a queued capability approval request. +Usage: use ApprovalRequest with the other exported helpers in this package. + + +### `ApprovalStatus` + +```go +type ApprovalStatus int +``` + +ApprovalStatus represents the state of an approval request. +Usage: use ApprovalStatus with the other exported helpers in this package. + +#### Methods + +##### `String` + +```go +func (s ApprovalStatus) String() string +``` + +String returns the human-readable name of the approval status. +Usage: call String(...) during the package's normal workflow. + + +### `AuditEntry` + +```go +type AuditEntry struct { + // Timestamp is when the evaluation occurred. + Timestamp time.Time `json:"timestamp"` + // Agent is the name of the agent being evaluated. + Agent string `json:"agent"` + // Cap is the capability that was evaluated. + Cap Capability `json:"capability"` + // Repo is the repo context (empty if not repo-scoped). + Repo string `json:"repo,omitempty"` + // Decision is the evaluation outcome. + Decision Decision `json:"decision"` + // Reason is the human-readable reason for the decision. + Reason string `json:"reason"` +} +``` + +AuditEntry records a single policy evaluation for compliance. +Usage: use AuditEntry with the other exported helpers in this package. + + +### `AuditLog` + +```go +type AuditLog struct { + mu sync.Mutex + entries []AuditEntry + writer io.Writer +} +``` + +AuditLog is an append-only log of policy evaluations. +Usage: use AuditLog with the other exported helpers in this package. + +#### Methods + +##### `Entries` + +```go +func (l *AuditLog) Entries() []AuditEntry +``` + +Entries returns a snapshot of all audit entries. +Usage: call Entries(...) during the package's normal workflow. + +##### `EntriesFor` + +```go +func (l *AuditLog) EntriesFor(agent string) []AuditEntry +``` + +EntriesFor returns all audit entries for a specific agent. +Usage: call EntriesFor(...) during the package's normal workflow. + +##### `EntriesForSeq` + +```go +func (l *AuditLog) EntriesForSeq(agent string) iter.Seq[AuditEntry] +``` + +EntriesForSeq returns an iterator over audit entries for a specific agent. +Usage: call EntriesForSeq(...) during the package's normal workflow. + +##### `EntriesSeq` + +```go +func (l *AuditLog) EntriesSeq() iter.Seq[AuditEntry] +``` + +EntriesSeq returns an iterator over all audit entries. +Usage: call EntriesSeq(...) during the package's normal workflow. + +##### `Len` + +```go +func (l *AuditLog) Len() int +``` + +Len returns the number of entries in the log. +Usage: call Len(...) during the package's normal workflow. + +##### `Record` + +```go +func (l *AuditLog) Record(result EvalResult, repo string) error +``` + +Record appends an evaluation result to the audit log. +Usage: call Record(...) during the package's normal workflow. + + +### `Capability` + +```go +type Capability string +``` + +Capability represents a specific action an agent can perform. +Usage: use Capability with the other exported helpers in this package. + + +### `Decision` + +```go +type Decision int +``` + +Decision is the result of a policy evaluation. +Usage: use Decision with the other exported helpers in this package. + +#### Methods + +##### `MarshalJSON` + +```go +func (d Decision) MarshalJSON() ([]byte, error) +``` + +MarshalJSON implements custom JSON encoding for Decision. +Usage: call MarshalJSON(...) during the package's normal workflow. + +##### `String` + +```go +func (d Decision) String() string +``` + +String returns the human-readable name of the decision. +Usage: call String(...) during the package's normal workflow. + +##### `UnmarshalJSON` + +```go +func (d *Decision) UnmarshalJSON(data []byte) error +``` + +UnmarshalJSON implements custom JSON decoding for Decision. +Usage: call UnmarshalJSON(...) during the package's normal workflow. + + +### `EvalResult` + +```go +type EvalResult struct { + Decision Decision + Agent string + Cap Capability + Reason string +} +``` + +EvalResult contains the outcome of a capability evaluation. +Usage: use EvalResult with the other exported helpers in this package. + + +### `PoliciesConfig` + +```go +type PoliciesConfig struct { + Policies []PolicyConfig `json:"policies"` +} +``` + +PoliciesConfig is the top-level configuration containing all tier policies. +Usage: use PoliciesConfig with the other exported helpers in this package. + + +### `Policy` + +```go +type Policy struct { + // Tier is the trust level this policy applies to. + Tier Tier + // Allowed lists the capabilities granted at this tier. + Allowed []Capability + // RequiresApproval lists capabilities that need human/higher-tier approval. + RequiresApproval []Capability + // Denied lists explicitly denied capabilities. + Denied []Capability +} +``` + +Policy defines the access rules for a given trust tier. +Usage: use Policy with the other exported helpers in this package. + + +### `PolicyConfig` + +```go +type PolicyConfig struct { + Tier int `json:"tier"` + Allowed []string `json:"allowed"` + RequiresApproval []string `json:"requires_approval,omitempty"` + Denied []string `json:"denied,omitempty"` +} +``` + +PolicyConfig is the JSON-serialisable representation of a trust policy. +Usage: use PolicyConfig with the other exported helpers in this package. + + +### `PolicyEngine` + +```go +type PolicyEngine struct { + registry *Registry + policies map[Tier]*Policy +} +``` + +PolicyEngine evaluates capability requests against registered policies. +Usage: use PolicyEngine with the other exported helpers in this package. + +#### Methods + +##### `ApplyPolicies` + +```go +func (pe *PolicyEngine) ApplyPolicies(r io.Reader) error +``` + +ApplyPolicies loads policies from a reader and sets them on the engine, +replacing any existing policies for the same tiers. +Usage: call ApplyPolicies(...) during the package's normal workflow. + +##### `ApplyPoliciesFromFile` + +```go +func (pe *PolicyEngine) ApplyPoliciesFromFile(path string) error +``` + +ApplyPoliciesFromFile loads policies from a JSON file and sets them on the engine. +Usage: call ApplyPoliciesFromFile(...) during the package's normal workflow. + +##### `Evaluate` + +```go +func (pe *PolicyEngine) Evaluate(agentName string, cap Capability, repo string) EvalResult +``` + +Evaluate checks whether the named agent can perform the given capability. +If the agent has scoped repos and the capability is repo-scoped, the repo +parameter is checked against the agent's allowed repos. +Usage: call Evaluate(...) during the package's normal workflow. + +##### `ExportPolicies` + +```go +func (pe *PolicyEngine) ExportPolicies(w io.Writer) error +``` + +ExportPolicies serialises the current policies as JSON to the given writer. +Usage: call ExportPolicies(...) during the package's normal workflow. + +##### `GetPolicy` + +```go +func (pe *PolicyEngine) GetPolicy(t Tier) *Policy +``` + +GetPolicy returns the policy for a tier, or nil if none is set. +Usage: call GetPolicy(...) during the package's normal workflow. + +##### `SetPolicy` + +```go +func (pe *PolicyEngine) SetPolicy(p Policy) error +``` + +SetPolicy replaces the policy for a given tier. +Usage: call SetPolicy(...) during the package's normal workflow. + + +### `Registry` + +```go +type Registry struct { + mu sync.RWMutex + agents map[string]*Agent +} +``` + +Registry manages agent identities and their trust tiers. +Usage: use Registry with the other exported helpers in this package. + +#### Methods + +##### `Get` + +```go +func (r *Registry) Get(name string) *Agent +``` + +Get returns the agent with the given name, or nil if not found. +Usage: call Get(...) during the package's normal workflow. + +##### `Len` + +```go +func (r *Registry) Len() int +``` + +Len returns the number of registered agents. +Usage: call Len(...) during the package's normal workflow. + +##### `List` + +```go +func (r *Registry) List() []Agent +``` + +List returns all registered agents. The returned slice is a snapshot. +Usage: call List(...) during the package's normal workflow. + +##### `ListSeq` + +```go +func (r *Registry) ListSeq() iter.Seq[Agent] +``` + +ListSeq returns an iterator over all registered agents. +Usage: call ListSeq(...) during the package's normal workflow. + +##### `Register` + +```go +func (r *Registry) Register(agent Agent) error +``` + +Register adds or updates an agent in the registry. +Returns an error if the agent name is empty or the tier is invalid. +Usage: call Register(...) during the package's normal workflow. + +##### `Remove` + +```go +func (r *Registry) Remove(name string) bool +``` + +Remove deletes an agent from the registry. +Usage: call Remove(...) during the package's normal workflow. + + +### `Tier` + +```go +type Tier int +``` + +Tier represents an agent's trust level in the system. +Usage: use Tier with the other exported helpers in this package. + +#### Methods + +##### `String` + +```go +func (t Tier) String() string +``` + +String returns the human-readable name of the tier. +Usage: call String(...) during the package's normal workflow. + +##### `Valid` + +```go +func (t Tier) Valid() bool +``` + +Valid returns true if the tier is a recognised trust level. +Usage: call Valid(...) during the package's normal workflow. + +## Functions + +### `LoadPolicies` + +```go +func LoadPolicies(r io.Reader) ([]Policy, error) +``` + +LoadPolicies reads JSON from a reader and returns parsed policies. +Usage: call LoadPolicies(...) during the package's normal workflow. + + +### `LoadPoliciesFromFile` + +```go +func LoadPoliciesFromFile(path string) ([]Policy, error) +``` + +LoadPoliciesFromFile reads a JSON file and returns parsed policies. +Usage: call LoadPoliciesFromFile(...) during the package's normal workflow. + + +### `NewApprovalQueue` + +```go +func NewApprovalQueue() *ApprovalQueue +``` + +NewApprovalQueue creates an empty approval queue. +Usage: call NewApprovalQueue(...) to create a ready-to-use value. + + +### `NewAuditLog` + +```go +func NewAuditLog(w io.Writer) *AuditLog +``` + +NewAuditLog creates an in-memory audit log. If a writer is provided, +each entry is also written as a JSON line to that writer (append-only). +Usage: call NewAuditLog(...) to create a ready-to-use value. + + +### `NewPolicyEngine` + +```go +func NewPolicyEngine(registry *Registry) *PolicyEngine +``` + +NewPolicyEngine creates a policy engine with the given registry and default policies. +Usage: call NewPolicyEngine(...) to create a ready-to-use value. + + +### `NewRegistry` + +```go +func NewRegistry() *Registry +``` + +NewRegistry creates an empty agent registry. +Usage: call NewRegistry(...) to create a ready-to-use value. \ No newline at end of file