Documentation
¶
Overview ¶
Package crypto owns flue's Noise IK handshake, the secure channel framing, and the key material on the daemon side. Pure: no HTTP, no WebSockets, no knowledge of sessions or transports.
Index ¶
- func DeviceID(publicKey []byte) string
- func LoadOrCreateStaticKey(configDir string) (noise.DHKey, error)
- func Suite() noise.CipherSuite
- type Channel
- type Device
- type DeviceStore
- func (s *DeviceStore) Add(label string, publicKey []byte) (Device, error)
- func (s *DeviceStore) FindByKey(publicKey []byte) (Device, bool, error)
- func (s *DeviceStore) List() ([]Device, error)
- func (s *DeviceStore) Remove(id string) (Device, bool, error)
- func (s *DeviceStore) UpdateLastSeen(id string, now time.Time) (bool, error)
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func DeviceID ¶
DeviceID derives the identity from the key itself, so an entry cannot claim to be a key it does not hold.
func LoadOrCreateStaticKey ¶
LoadOrCreateStaticKey returns the daemon's static keypair, creating it on first run. A file that exists but cannot be parsed is an error, never a regenerate: a fresh key would silently invalidate every pairing.
func Suite ¶
func Suite() noise.CipherSuite
Suite is the one cipher suite flue speaks: Noise_IK_25519_ChaChaPoly_SHA256.
Types ¶
type Channel ¶
type Channel struct {
// contains filtered or unexported fields
}
Channel is one authenticated, ordered, end-to-end encrypted pipe. Nonces are the CipherStates' own strictly incrementing counters; the transport underneath is a WebSocket, which is ordered and reliable, so any Open failure means tampering or replay and the caller must tear the connection down — there is no recovery path by design.
func InitiatorHandshake ¶
func InitiatorHandshake(static noise.DHKey, peerStatic []byte, rng io.Reader, recv func() ([]byte, error), send func([]byte) error) (*Channel, error)
InitiatorHandshake runs the browser side of the handshake. It exists in Go for tests and the vector generator; production initiators are TypeScript. rng == nil means crypto/rand.
func ResponderHandshake ¶
func ResponderHandshake(static noise.DHKey, rng io.Reader, recv func() ([]byte, error), send func([]byte) error) (*Channel, []byte, error)
ResponderHandshake runs the daemon side. The returned public key is the initiator's static — the device identity the caller authorizes against the device store. Callers must treat an error as fatal to the connection and process no frames before the handshake completes.
type DeviceStore ¶
type DeviceStore struct {
// contains filtered or unexported fields
}
DeviceStore is the paired-device registry: devices.json in the config dir, 0600, re-read under the lock on every call so concurrent daemon paths (pairing, revocation, the devices op) serialize on the file's truth.
func NewDeviceStore ¶
func NewDeviceStore(configDir string) *DeviceStore
func (*DeviceStore) FindByKey ¶
func (s *DeviceStore) FindByKey(publicKey []byte) (Device, bool, error)
func (*DeviceStore) List ¶
func (s *DeviceStore) List() ([]Device, error)
func (*DeviceStore) UpdateLastSeen ¶
UpdateLastSeen stamps the device's LastSeen to now, reporting whether the device exists. Missing devices are not an error: a connection may race its own revocation, and the registry is the truth either way — a device that was unpaired a moment ago is not brought back by having connected.
The whole file is rewritten, like every other mutation here, because that is what makes a concurrent revoke and a concurrent stamp serialise on the same lock rather than on two partial views of the same JSON.