security

package
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Mar 12, 2026 License: MIT Imports: 16 Imported by: 0

Documentation

Index

Constants

View Source
const (
	// MaxMessageSize is the hard limit for message payload size (1 MB).
	MaxMessageSize = 1 << 20

	// NonceWindowDuration is how long nonces are remembered for replay protection.
	NonceWindowDuration = 5 * time.Minute

	// TimestampSkew is the maximum allowed clock difference.
	TimestampSkew = 2 * time.Minute
)
View Source
const DefaultSecondHandWeight = 0.3

DefaultSecondHandWeight is the default weight applied to reputation claims from other peers.

View Source
const DefaultTOFUExpiry = 30 * 24 * time.Hour // 30 days

DefaultTOFUExpiry is the default duration after which a TOFU trust entry expires.

View Source
const HKDFSaltSize = 32

HKDFSaltSize is the size of the random salt used for HKDF key derivation.

View Source
const MinTrustForGossip = TrustVerified

MinTrustForGossip is the minimum trust level required to accept gossip from a peer.

View Source
const NostrReputationKind = 30078

NostrReputationKind is the Nostr event kind for reputation claims (NIP-78 application-specific data).

Variables

View Source
var ErrInvalidTrustTransition = fmt.Errorf("invalid trust level transition")

ErrInvalidTrustTransition is returned when a trust level transition is not allowed.

Functions

func DeriveSessionSalt added in v0.2.0

func DeriveSessionSalt(pubA, pubB []byte) []byte

DeriveSessionSalt produces a deterministic 32-byte salt from two public keys. Keys are sorted so both sides compute the same salt regardless of call order.

func MarshalClaim

func MarshalClaim(claim *ReputationClaim) ([]byte, error)

MarshalClaim serializes a claim to JSON for Nostr event content.

func TrustLevelString

func TrustLevelString(level TrustLevel) string

TrustLevelString returns a human-readable name for a TrustLevel.

func ValidTrustTransition added in v0.2.0

func ValidTrustTransition(from, to TrustLevel) bool

ValidTrustTransition checks whether transitioning from one trust level to another is allowed by the trust state machine. Allowed transitions:

  • Unknown -> TOFU, Verified, Pinned, Blocked
  • TOFU -> Verified, Blocked
  • Verified -> Pinned, Blocked
  • Pinned -> Blocked
  • Blocked -> Unknown (explicit unblock only)

All other transitions are rejected (e.g., Blocked->Verified, Blocked->Pinned, Pinned->TOFU, Verified->TOFU, etc.).

Types

type BehaviorType

type BehaviorType string

BehaviorType represents the type of observed behavior from a peer.

const (
	BehaviorSuccess           BehaviorType = "success"
	BehaviorTimeout           BehaviorType = "timeout"
	BehaviorError             BehaviorType = "error"
	BehaviorInvalidSignature  BehaviorType = "invalid_signature"
	BehaviorSpam              BehaviorType = "spam"
	BehaviorProtocolViolation BehaviorType = "protocol_violation"
)

type MessageValidator

type MessageValidator struct {
	// contains filtered or unexported fields
}

MessageValidator provides message-level security: signature verification, replay protection via nonces, and size limits.

func NewMessageValidator

func NewMessageValidator() *MessageValidator

NewMessageValidator creates a new message validator.

func (*MessageValidator) CleanExpiredNonces

func (v *MessageValidator) CleanExpiredNonces()

CleanExpiredNonces removes nonces older than the window duration.

func (*MessageValidator) ValidateMessage

func (v *MessageValidator) ValidateMessage(env *envelope.Envelope, pubKeyStr string) error

ValidateMessage validates the integrity and freshness of an envelope.

type ReputationClaim

type ReputationClaim struct {
	ClaimID   string    `json:"claim_id"` // unique claim identifier for replay protection
	Issuer    string    `json:"issuer"`   // pubkey of the issuer
	Subject   string    `json:"subject"`  // pubkey of the rated peer
	Score     float64   `json:"score"`    // 0.0 - 1.0
	Reason    string    `json:"reason"`   // brief description
	Timestamp time.Time `json:"timestamp"`
}

ReputationClaim represents a reputation assertion published via Nostr.

func UnmarshalClaim

func UnmarshalClaim(data []byte) (*ReputationClaim, error)

UnmarshalClaim deserializes a claim from JSON.

type ReputationEntry

type ReputationEntry struct {
	PubKey      string    `json:"pub_key"`
	Score       float64   `json:"score"`
	EventCount  int64     `json:"event_count"`
	LastUpdated time.Time `json:"last_updated"`
}

ReputationEntry tracks the reputation of a single peer.

type ReputationGossip

type ReputationGossip struct {
	SecondHandWeight float64 // Configurable weight for second-hand reputation claims
	// contains filtered or unexported fields
}

ReputationGossip manages publishing and consuming reputation claims via Nostr.

func NewReputationGossip

func NewReputationGossip(store *ReputationStore, trustStore *TrustStore, selfPubKey string) *ReputationGossip

NewReputationGossip creates a new gossip manager with the default second-hand weight.

func (*ReputationGossip) CleanSeenClaims added in v0.2.0

func (rg *ReputationGossip) CleanSeenClaims()

CleanSeenClaims removes stale entries from seenClaims to prevent unbounded growth. Should be called periodically.

func (*ReputationGossip) CreateClaim

func (rg *ReputationGossip) CreateClaim(subjectPubKey string) *ReputationClaim

CreateClaim creates a reputation claim for publishing.

func (*ReputationGossip) ProcessClaim

func (rg *ReputationGossip) ProcessClaim(claim *ReputationClaim) bool

ProcessClaim processes an incoming reputation claim from another peer. It only accepts claims from peers with TrustVerified or higher, and applies the configurable SecondHandWeight to the score. Returns false if the claim is rejected (untrusted issuer, self-issued, duplicate, stale, or rate-limited).

type ReputationStore

type ReputationStore struct {
	// contains filtered or unexported fields
}

ReputationStore tracks per-peer reputation scores using EWMA.

func NewReputationStore

func NewReputationStore() *ReputationStore

NewReputationStore creates a new reputation store with default settings.

func (*ReputationStore) ApplyGossipScore added in v0.2.0

func (rs *ReputationStore) ApplyGossipScore(peerID string, gossipScore float64, weight float64)

ApplyGossipScore blends a gossip-reported score with the existing score using a weighted EWMA formula. This is the safe way to incorporate external reputation data without allowing direct score overrides.

func (*ReputationStore) GetEntry

func (rs *ReputationStore) GetEntry(pubKey string) *ReputationEntry

GetEntry returns the full reputation entry for a peer, or nil if not found.

func (*ReputationStore) GetScore

func (rs *ReputationStore) GetScore(pubKey string) float64

GetScore returns the reputation score for a peer. Returns 0.5 (neutral) if unknown.

func (*ReputationStore) IsMalicious

func (rs *ReputationStore) IsMalicious(pubKey string) bool

IsMalicious returns true if the peer's reputation is below the malicious threshold.

func (*ReputationStore) ListEntries

func (rs *ReputationStore) ListEntries() []ReputationEntry

ListEntries returns all reputation entries.

func (*ReputationStore) LoadFromFile

func (rs *ReputationStore) LoadFromFile(path string) error

LoadFromFile loads the reputation store from a JSON file.

func (*ReputationStore) RecordEvent

func (rs *ReputationStore) RecordEvent(pubKey string, behavior BehaviorType)

RecordEvent records a behavior event for a peer and updates the EWMA score.

func (*ReputationStore) SaveToFile

func (rs *ReputationStore) SaveToFile(path string) error

SaveToFile persists the reputation store to a JSON file.

type SessionKey

type SessionKey struct {
	// contains filtered or unexported fields
}

SessionKey holds the derived symmetric key for encrypting messages between two peers.

func DeriveSessionKey

func DeriveSessionKey(privateKey *ecdh.PrivateKey, peerPublicKey *ecdh.PublicKey, peerID string, salt ...[]byte) (*SessionKey, []byte, error)

DeriveSessionKey computes a shared secret via X25519 ECDH and derives a 32-byte symmetric key using HKDF-SHA256. An optional salt can be provided; if nil, a random 32-byte salt is generated. The salt is returned alongside the session key so it can be exchanged with the peer.

func NewSessionKeyFromBytes

func NewSessionKeyFromBytes(key []byte, peerID string) (*SessionKey, error)

NewSessionKeyFromBytes creates a SessionKey from raw key bytes. Used primarily for testing.

func (*SessionKey) Decrypt

func (sk *SessionKey) Decrypt(data []byte) ([]byte, error)

Decrypt decrypts data produced by Encrypt. Expects input format: nonce (24 bytes) || ciphertext || tag (16 bytes).

func (*SessionKey) DecryptWithAAD added in v0.2.0

func (sk *SessionKey) DecryptWithAAD(data, aad []byte) ([]byte, error)

DecryptWithAAD decrypts data with additional associated data verification. The AAD must match what was provided during encryption.

func (*SessionKey) Encrypt

func (sk *SessionKey) Encrypt(plaintext []byte) ([]byte, error)

Encrypt encrypts plaintext using XChaCha20-Poly1305 with a random nonce. The nonce is prepended to the ciphertext. Returns: nonce (24 bytes) || ciphertext || tag (16 bytes).

func (*SessionKey) EncryptWithAAD added in v0.2.0

func (sk *SessionKey) EncryptWithAAD(plaintext, aad []byte) ([]byte, error)

EncryptWithAAD encrypts plaintext with additional associated data (AAD). AAD is authenticated but not encrypted — it binds the ciphertext to context (e.g., envelope Source + Destination + Nonce) preventing ciphertext swapping.

func (*SessionKey) PeerID

func (sk *SessionKey) PeerID() string

PeerID returns the remote peer identifier associated with this session key.

type TrustChangeCallback

type TrustChangeCallback func(pubKey string, oldLevel, newLevel TrustLevel)

TrustChangeCallback is called when a trust entry changes.

type TrustEntry

type TrustEntry struct {
	PublicKey  string     `json:"public_key"`
	Level      TrustLevel `json:"level"`
	FirstSeen  string     `json:"first_seen"`
	LastSeen   string     `json:"last_seen,omitempty"`
	Alias      string     `json:"alias,omitempty"`
	ExpiresAt  time.Time  `json:"expires_at,omitempty"`
	WasBlocked bool       `json:"was_blocked,omitempty"` // L-05: tracks if peer was previously blocked
}

TrustEntry records trust information about a peer.

type TrustLevel

type TrustLevel int

TrustLevel represents how much an agent is trusted.

const (
	TrustUnknown  TrustLevel = 0
	TrustTOFU     TrustLevel = 1 // Trust On First Use
	TrustVerified TrustLevel = 2 // Explicitly verified
	TrustBlocked  TrustLevel = 3 // Explicitly blocked
	TrustPinned   TrustLevel = 4 // Permanently pinned (highest trust)
)

type TrustStore

type TrustStore struct {
	// contains filtered or unexported fields
}

TrustStore manages TOFU trust relationships with peers.

func NewTrustStore

func NewTrustStore() *TrustStore

NewTrustStore creates a new empty trust store.

func (*TrustStore) Check

func (ts *TrustStore) Check(pubKey string) TrustLevel

Check returns the trust level for a public key. If the entry is a TOFU entry that has expired, TrustUnknown is returned.

func (*TrustStore) CleanExpired

func (ts *TrustStore) CleanExpired()

CleanExpired removes expired TOFU entries from the store. Only TOFU entries are subject to expiration; entries at TrustVerified or higher (including TrustBlocked and TrustPinned) are never removed.

func (*TrustStore) Export

func (ts *TrustStore) Export() ([]byte, error)

Export serializes all entries to JSON bytes.

func (*TrustStore) Import

func (ts *TrustStore) Import(data []byte) error

Import merges entries from JSON bytes into the store. Existing entries are NOT overwritten — only new keys are imported. Trust levels are validated; invalid values are rejected.

func (*TrustStore) IsAllowed

func (ts *TrustStore) IsAllowed(pubKey string) bool

IsAllowed returns true if the peer is trusted (TOFU, Verified, or Pinned).

func (*TrustStore) IsAllowedWithReputation

func (ts *TrustStore) IsAllowedWithReputation(pubKey string) bool

IsAllowedWithReputation returns true if the peer passes both trust and reputation checks. If no ReputationStore is set, it falls back to IsAllowed.

func (*TrustStore) ListEntries

func (ts *TrustStore) ListEntries() []TrustEntry

ListEntries returns all trust entries sorted by public key.

func (*TrustStore) LoadFromFile

func (ts *TrustStore) LoadFromFile(path string) error

LoadFromFile loads the trust store from a JSON file.

func (*TrustStore) OnTrustChange

func (ts *TrustStore) OnTrustChange(cb TrustChangeCallback)

OnTrustChange registers a callback invoked when trust levels change.

func (*TrustStore) RemoveEntry

func (ts *TrustStore) RemoveEntry(pubKey string) bool

RemoveEntry removes a trust entry entirely.

func (*TrustStore) SaveToFile

func (ts *TrustStore) SaveToFile(path string) error

SaveToFile persists the trust store to a JSON file using atomic write (write to temp file, then rename) to prevent corruption on crash.

func (*TrustStore) SetAlias

func (ts *TrustStore) SetAlias(pubKey, alias string)

SetAlias sets a human-readable alias for a peer.

func (*TrustStore) SetReputationStore

func (ts *TrustStore) SetReputationStore(rs *ReputationStore)

SetReputationStore associates a ReputationStore with this TrustStore.

func (*TrustStore) SetTrust

func (ts *TrustStore) SetTrust(pubKey string, level TrustLevel) error

SetTrust explicitly sets the trust level for a public key. Returns an error if the transition is not allowed by the trust state machine.

func (*TrustStore) TouchLastSeen

func (ts *TrustStore) TouchLastSeen(pubKey string)

TouchLastSeen updates the LastSeen timestamp for a peer.

func (*TrustStore) TrustOnFirstUse

func (ts *TrustStore) TrustOnFirstUse(pubKey, firstSeen string) TrustLevel

TrustOnFirstUse records a new peer with TOFU trust if not already known. The TOFU entry expires after DefaultTOFUExpiry (30 days). L-05: If the peer was previously blocked (WasBlocked is true), auto-TOFU is denied — the caller must use explicit verification (SetTrust) instead. Returns the trust level (existing or newly created).

Jump to

Keyboard shortcuts

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