store

package
v0.1.1 Latest Latest
Warning

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

Go to latest
Published: Jul 3, 2026 License: MIT Imports: 21 Imported by: 0

Documentation

Overview

Package store is AgentTransfer's persistence layer: one SQLite database plus a sha256-addressed, refcounted blob directory. It also owns the instance ed25519 identity and writes the signed receipt chain.

Index

Constants

This section is empty.

Variables

View Source
var ErrCircleFull = errors.New("recipient circle full")

ErrCircleFull is returned when a send would add more unique remote recipients than the agent's circle allows.

View Source
var ErrNameTaken = errors.New("name taken")

ErrNameTaken is returned when an agent name is already registered.

View Source
var ErrNotFound = errors.New("not found")

ErrNotFound is returned when a row does not exist.

View Source
var ErrQueueFull = errors.New("mail queue full")

ErrQueueFull is returned when an instance's mail queue is at capacity, so the SMTP path can answer a retryable 452 rather than a permanent reject.

View Source
var ErrQuota = errors.New("storage quota exceeded")

ErrQuota is returned when an upload would exceed the agent's storage quota or the max file size.

Functions

func NewID

func NewID(prefix string) string

NewID returns a prefixed, unguessable identifier like "msg_ab3k...".

func NewLinkToken

func NewLinkToken() string

NewLinkToken returns a 128-bit share-link token.

func VolumeStats

func VolumeStats(path string) (free, total int64, err error)

VolumeStats returns the free (available to unprivileged users) and total bytes of the filesystem holding path.

Types

type Agent

type Agent struct {
	ID            string `json:"agent_id"`
	Name          string `json:"name"`
	Email         string `json:"email"`
	OwnerEmail    string `json:"owner_email,omitempty"`
	OwnerVerified bool   `json:"owner_verified"`
	AlwaysCCOwner bool   `json:"always_cc_owner"`
	// HumanRecipientsMax overrides the instance-wide cap on unique remote
	// recipients for this agent: 0 = instance default, <0 = unlimited.
	HumanRecipientsMax int64 `json:"-"`
	CreatedAt          int64 `json:"created_at"`
}

Agent is one identity: an email address plus an API key.

type Attachment

type Attachment struct {
	SHA256 string `json:"sha256"`
	Name   string `json:"name"`
	MIME   string `json:"mime"`
	Size   int64  `json:"size"`
}

Attachment describes an inbound email attachment ingested into the folder.

type ConnectInstance

type ConnectInstance struct {
	Name      string
	Verified  bool
	Suspended bool
}

ConnectInstance is one tunneled instance in the host registry. Only the fields the server actually reads are surfaced; created_at / last_seen / owner_email live in the table and are used by reaping and verification via SQL, not through this struct.

type ConnectMail

type ConnectMail struct {
	ID    string
	Name  string
	Rcpts []string
	Raw   []byte
}

ConnectMail is one queued inbound email for a tunneled instance.

type File

type File struct {
	ID        string `json:"id"`
	AgentID   string `json:"-"`
	SHA256    string `json:"sha256"`
	Name      string `json:"name"`
	MIME      string `json:"mime"`
	Size      int64  `json:"size"`
	Source    string `json:"source"` // upload | inbound | request
	Claimed   bool   `json:"claimed"`
	ExpiresAt int64  `json:"expires_at,omitempty"` // unix; 0 = never
	CreatedAt int64  `json:"created_at"`
}

File is one entry in an agent's folder. Claimed means the agent owns it (its own upload, or an arrival it kept); unclaimed files (inbound attachments, upload-request drops) await a keep. ExpiresAt > 0 makes a file mortal regardless of claiming — the unverified-owner tier uploads with an expiry that verification later lifts.

type Link struct {
	Token     string `json:"token"`
	AgentID   string `json:"-"`
	SHA256    string `json:"sha256"`
	Name      string `json:"name"`
	MIME      string `json:"mime"`
	Size      int64  `json:"size"`
	Once      bool   `json:"once"`
	Downloads int64  `json:"downloads"`
	Status    string `json:"status"` // active | revoked | burned | expired
	ExpiresAt int64  `json:"expires_at"`
	CreatedAt int64  `json:"created_at"`
}

Link is an ephemeral, unguessable share link over a blob.

type Message

type Message struct {
	ID          string       `json:"id"`
	AgentID     string       `json:"-"`
	From        string       `json:"from"`
	To          []string     `json:"to"`
	Subject     string       `json:"subject"`
	Text        string       `json:"text"`
	MessageID   string       `json:"message_id"`
	InReplyTo   string       `json:"in_reply_to,omitempty"`
	References  string       `json:"references,omitempty"`
	Manifest    string       `json:"-"` // raw manifest JSON, if any
	Attachments []Attachment `json:"attachments"`
	DKIM        string       `json:"dkim"`
	SPF         string       `json:"spf"`
	Read        bool         `json:"read"`
	ReceivedAt  int64        `json:"received_at"`
}

Message is one inbox entry.

type StorageConsumer

type StorageConsumer struct {
	AgentID       string `json:"agent_id"`
	Name          string `json:"name"`
	Email         string `json:"email"`
	OwnerEmail    string `json:"owner_email"`
	OwnerVerified bool   `json:"owner_verified"`
	Files         int64  `json:"files"`
	Bytes         int64  `json:"bytes"`
}

StorageConsumer is one row of the admin "top storage consumers" view.

type Store

type Store struct {
	DB *sql.DB
	// contains filtered or unexported fields
}

Store wraps the database, blob directory, and instance identity.

func Open

func Open(dataDir, adminToken string) (s *Store, firstBootAdminToken string, err error)

Open opens (creating if needed) the store at dataDir. adminToken, if non-empty, becomes the admin token; otherwise one is generated on first boot and returned in firstBootAdminToken exactly once.

func (*Store) AddFile

func (s *Store) AddFile(agentID, sha, name, mime string, size int64, source string, claimed bool, expiresAt int64) (File, error)

AddFile records a folder entry over an existing blob and takes a blob reference. Re-adding the same (name, sha) refreshes the row instead.

func (*Store) AddMessage

func (s *Store) AddMessage(m Message) (Message, error)

AddMessage inserts an inbox row for an agent.

func (*Store) AgentByID

func (s *Store) AgentByID(id string) (Agent, error)

AgentByID resolves an agent by id.

func (*Store) AgentByKey

func (s *Store) AgentByKey(key string) (Agent, error)

AgentByKey resolves an API key to its agent.

func (*Store) AgentByName

func (s *Store) AgentByName(name string) (Agent, error)

AgentByName resolves an agent by name (the address localpart).

func (*Store) AgentHasFile

func (s *Store) AgentHasFile(agentID, sha, name string) bool

AgentHasFile reports whether the agent's folder already holds this exact (name, sha) entry — used to waive quota on idempotent re-uploads.

func (*Store) AppendReceipt

func (s *Store) AppendReceipt(actor, action, sha string, size int64, target, messageID string) (receipt.Receipt, error)

AppendReceipt signs and appends one receipt to the instance chain.

func (s *Store) BurnLink(token string) (Link, error)

BurnLink marks a burn-after-read link consumed.

func (*Store) CheckUnsubscribeToken

func (s *Store) CheckUnsubscribeToken(addr, tok string) bool

CheckUnsubscribeToken verifies an unsubscribe token for addr.

func (*Store) ClaimHumanRecipients

func (s *Store) ClaimHumanRecipients(agentID string, addrs []string, max int64) (newly []string, err error)

ClaimHumanRecipients records addrs in the agent's recipient circle, enforcing max (<0 = unlimited) atomically. It returns the addresses this call newly claimed, so a failed send can release exactly those.

func (*Store) Close

func (s *Store) Close() error

Close closes the database.

func (*Store) ConnectInstanceByName

func (s *Store) ConnectInstanceByName(name string) (ConnectInstance, error)

ConnectInstanceByName fetches a registered instance.

func (*Store) ConnectInstanceByToken

func (s *Store) ConnectInstanceByToken(token string) (ConnectInstance, error)

ConnectInstanceByToken resolves an instance token.

func (*Store) ConsumeVerifyToken

func (s *Store) ConsumeVerifyToken(tok string) (string, error)

ConsumeVerifyToken redeems a verification token for its agent id.

func (*Store) CountAgentsByOwner

func (s *Store) CountAgentsByOwner(owner string) (int64, error)

CountAgentsByOwner counts agents registered to an owner address (case-insensitive) — open signup caps this so identities aren't free in bulk.

func (*Store) CountDownload

func (s *Store) CountDownload(token string) error

CountDownload bumps a link's download counter.

func (*Store) CountHumanRecipients

func (s *Store) CountHumanRecipients(agentID string) (int64, error)

CountHumanRecipients returns the number of unique remote recipients the agent has claimed.

func (*Store) CreateAgent

func (s *Store) CreateAgent(name, ownerEmail string, verified bool) (Agent, string, error)

CreateAgent mints an agent and returns it with the plaintext API key (stored only as a hash).

func (*Store) CreateConnectInstance

func (s *Store) CreateConnectInstance(name string) (string, error)

CreateConnectInstance registers a tunneled instance and returns its plaintext token (stored hashed).

func (s *Store) CreateLink(agentID, sha, name, mime string, size int64, once bool, ttl time.Duration) (Link, error)

CreateLink mints an ephemeral share link over a blob and takes a blob ref.

func (*Store) CreateUploadRequest

func (s *Store) CreateUploadRequest(agentID, note string, ttl time.Duration) (UploadRequest, error)

CreateUploadRequest mints a one-time human upload page token.

func (*Store) CreateVerifyToken

func (s *Store) CreateVerifyToken(agentID string) (string, error)

CreateVerifyToken mints an owner-verification token.

func (*Store) DeleteAgent

func (s *Store) DeleteAgent(agentID string) (Agent, []string, error)

DeleteAgent removes an agent and everything it owns — files, links, inbox, recipient circle, upload requests, counters, idempotency + verify tokens — EXCEPT its receipts: the signed chain is append-only and must outlive the account, or it stops being deletion-evident. Blob refs held by the agent's files and active links are released (only this agent's contribution, so content deduped with another agent survives), and the active link tokens are returned so the caller can sever any in-flight downloads. All in one transaction: a partial cascade would leave dangling refs or FK orphans.

func (*Store) DeleteConnectMail

func (s *Store) DeleteConnectMail(name, id string) error

DeleteConnectMail acknowledges (removes) one queued message.

func (*Store) DeleteFile

func (s *Store) DeleteFile(agentID, sha string) ([]File, error)

DeleteFile removes folder entries for a hash and drops their blob refs. It returns the removed entries.

func (*Store) DeleteOrphanBlobs

func (s *Store) DeleteOrphanBlobs() (int, error)

DeleteOrphanBlobs removes blobs with zero references from db and disk.

Safety has three layers. The grace period skips young rows entirely — PutBlob creates (or refreshes) the row at refs=0 and the first reference lands moments later. The row DELETE re-checks refs AND age, so a blob re-referenced or re-put since the scan is left alone. And each delete + unlink pair runs under blobMu so it can't interleave with PutBlob's row-write + byte-write pair — without the lock, a dedup upload could see the bytes on disk, skip writing them, and then lose them to the unlink.

func (*Store) DiskFull

func (s *Store) DiskFull() bool

DiskFull reports whether the volume holding the data dir is below the configured free-space reserve — the global backstop that keeps the disk from ever reaching 100% (where SQLite writes start failing and the whole instance falls over). Callers refuse new uploads while it holds.

func (*Store) DiskStats

func (s *Store) DiskStats() (free, total, reserve int64)

DiskStats returns the data-dir volume's free and total bytes plus the configured reserve (0 = guard disabled). free/total are 0 when the platform can't report them.

func (*Store) EnqueueConnectMail

func (s *Store) EnqueueConnectMail(name string, rcpts []string, raw []byte, maxMsgs, maxBytes int64) error

EnqueueConnectMail stores one inbound email for an instance, enforcing per-instance count and byte caps.

func (*Store) ExpireFiles

func (s *Store) ExpireFiles(cutoff int64) ([]File, error)

ExpireFiles removes folder entries past their expiry — unclaimed arrivals and unverified-tier uploads alike (expires_at=0 means immortal). It returns the expired entries (for receipts).

func (s *Store) ExpireLinks(cutoff int64) ([]Link, error)

ExpireLinks closes active links past expiry and returns them.

func (*Store) FileByName

func (s *Store) FileByName(agentID, name string) (File, error)

FileByName fetches an agent's folder entry by filename.

func (*Store) FileBySHA

func (s *Store) FileBySHA(agentID, sha string) (File, error)

FileBySHA fetches an agent's folder entry by content hash.

func (*Store) GetIdempotent

func (s *Store) GetIdempotent(agentID, key string) (string, error)

GetIdempotent returns a stored response for (agent, key), or "".

func (s *Store) GetLink(token string) (Link, error)

GetLink fetches a link by token.

func (*Store) GetMessage

func (s *Store) GetMessage(agentID, id string) (Message, error)

GetMessage fetches one inbox message owned by the agent.

func (*Store) GetSetting

func (s *Store) GetSetting(k string) (string, error)

GetSetting returns a persisted setting ("" if unset).

func (*Store) GetUploadRequest

func (s *Store) GetUploadRequest(token string) (UploadRequest, error)

GetUploadRequest fetches a live (unused, unexpired) upload request.

func (*Store) HasMessageID

func (s *Store) HasMessageID(agentID, messageID string) bool

HasMessageID reports whether the agent already has a message with this RFC Message-ID — used to make at-least-once inbound delivery (connect store-and-forward, retried drains) idempotent instead of duplicating.

func (*Store) IncrCounter

func (s *Store) IncrCounter(agentID, kind string) (int64, error)

IncrCounter bumps and returns today's counter of a kind for an agent.

func (*Store) IncrCounterN

func (s *Store) IncrCounterN(agentID, kind string, n int64) (int64, error)

IncrCounterN bumps today's counter by n and returns the new total. n=0 reads the current value; a negative n refunds a charge.

func (*Store) Instance

func (s *Store) Instance() string

Instance returns the instance domain ("local" when unconfigured).

func (*Store) IsAdmin

func (s *Store) IsAdmin(tok string) bool

IsAdmin reports whether tok is the admin token.

func (*Store) IsSuppressed

func (s *Store) IsSuppressed(addr string) bool

IsSuppressed reports whether addr has unsubscribed from this instance.

func (*Store) KeepFile

func (s *Store) KeepFile(agentID, sha string, expiresAt int64) (File, error)

KeepFile claims a file. expiresAt caps its remaining lifetime: 0 makes it persistent (verified owners); unverified agents pass their tier's ceiling — keeping must not grant an immortality their own uploads don't get.

func (*Store) ListConnectMail

func (s *Store) ListConnectMail(name string, limit int) ([]ConnectMail, error)

ListConnectMail returns queued mail for an instance, oldest first.

func (*Store) ListFiles

func (s *Store) ListFiles(agentID string) ([]File, error)

ListFiles returns the agent's folder, newest first.

func (*Store) ListInbox

func (s *Store) ListInbox(agentID string, unreadOnly bool, thread string, limit int) ([]Message, error)

ListInbox returns inbox messages, oldest first. thread filters by an AgentTransfer message id (matches the message or replies to it).

func (s *Store) ListLinks(agentID string) ([]Link, error)

ListLinks returns the agent's links, newest first.

func (*Store) ListReceipts

func (s *Store) ListReceipts(actor string, limit int) ([]receipt.Receipt, error)

ListReceipts returns receipts, oldest first. actor "" means all (admin).

func (*Store) MarkOwnerVerified

func (s *Store) MarkOwnerVerified(agentID string) error

MarkOwnerVerified flips owner verification on and lifts the unverified storage tier: the agent's claimed files stop expiring. (Unclaimed arrivals stay mortal until kept — that guard is about strangers, not the owner.)

func (*Store) MarkRead

func (s *Store) MarkRead(agentID, id string) error

MarkRead flags a message read.

func (*Store) OpenBlob

func (s *Store) OpenBlob(sha string) (*os.File, error)

OpenBlob opens a blob for reading.

func (*Store) PeekVerifyToken

func (s *Store) PeekVerifyToken(tok string) (string, error)

PeekVerifyToken resolves a verification token WITHOUT consuming it — the GET landing page must be side-effect-free so link prefetchers and mail scanners can't verify on the owner's behalf; only the explicit confirm POST consumes.

func (*Store) Prune

func (s *Store) Prune() error

Prune clears expired idempotency keys, verify tokens, upload requests and stale counters.

func (*Store) PublicKey

func (s *Store) PublicKey() ed25519.PublicKey

PublicKey returns the instance receipt-signing public key.

func (*Store) PutBlob

func (s *Store) PutBlob(r io.Reader, limit int64) (sha string, size int64, err error)

PutBlob streams r to disk while hashing, capped at limit bytes. Identical content is stored once (content addressing); re-putting an existing blob just refreshes its row.

func (*Store) PutIdempotent

func (s *Store) PutIdempotent(agentID, key, response string) error

PutIdempotent stores a response for (agent, key).

func (*Store) ReapConnectInstances

func (s *Store) ReapConnectInstances(graceNew, graceIdle time.Duration) ([]string, error)

ReapConnectInstances removes registrations that never connected within graceNew, or have been idle longer than graceIdle, along with their queued mail. Returns the reaped names.

func (*Store) ReleaseHumanRecipients

func (s *Store) ReleaseHumanRecipients(agentID string, addrs []string) error

ReleaseHumanRecipients removes addresses from the agent's circle — used to refund slots claimed for a send that then failed at the relay.

func (*Store) RenameInstance

func (s *Store) RenameInstance(domain string) error

RenameInstance changes the instance domain and rewrites agent addresses to the new domain (agent emails are stored denormalized at creation time). Historical receipts keep the addresses that were true when they were signed — rewriting them would break the chain.

func (s *Store) RevokeLink(token string) (Link, error)

RevokeLink kills a link now.

func (*Store) RevokeLinksForSHA

func (s *Store) RevokeLinksForSHA(agentID, sha string) ([]Link, error)

RevokeLinksForSHA revokes all of an agent's active links over a hash.

func (*Store) RotateKey

func (s *Store) RotateKey(agentID string) (string, error)

RotateKey issues a new API key for the agent; the old one dies now.

func (*Store) SetAlwaysCC

func (s *Store) SetAlwaysCC(agentID string, v bool) error

SetAlwaysCC sets the per-agent "always CC my owner" flag.

func (*Store) SetConnectSuspended

func (s *Store) SetConnectSuspended(name string, v bool) error

SetConnectSuspended flips the kill switch for an instance.

func (*Store) SetConnectVerified

func (s *Store) SetConnectVerified(name, ownerEmail string) error

SetConnectVerified marks an instance's owner verified (unlocks outbound email through the host).

func (*Store) SetDiskReserve

func (s *Store) SetDiskReserve(bytes int64)

SetDiskReserve sets the free-space floor (bytes) below which DiskFull reports true. 0 disables the guard.

func (*Store) SetHumanRecipientsMax

func (s *Store) SetHumanRecipientsMax(agentID string, n int64) error

SetHumanRecipientsMax sets the per-agent recipient-circle override (0 = instance default, <0 = unlimited).

func (*Store) SetInstance

func (s *Store) SetInstance(domain string)

SetInstance sets the domain recorded on receipts and used in addresses.

func (*Store) SetSetting

func (s *Store) SetSetting(k, v string) error

SetSetting persists a setting.

func (*Store) StorageUsed

func (s *Store) StorageUsed(agentID string) (int64, error)

StorageUsed sums the agent's folder bytes (each entry counted once).

func (*Store) StoredBytes

func (s *Store) StoredBytes() (int64, error)

StoredBytes is the physical footprint: the sum of all blob sizes (dedup means this is ≤ the sum of folder entries).

func (*Store) Suppress

func (s *Store) Suppress(addr string) error

Suppress records that addr never wants agent mail from this instance again.

func (*Store) TopStorageConsumers

func (s *Store) TopStorageConsumers(limit int) ([]StorageConsumer, error)

TopStorageConsumers returns agents ordered by folder bytes, biggest first — abuse cleanup starts with being able to SEE who holds the disk.

func (*Store) TouchConnectInstance

func (s *Store) TouchConnectInstance(name string) error

TouchConnectInstance records tunnel activity.

func (*Store) UnsubscribeToken

func (s *Store) UnsubscribeToken(addr string) string

UnsubscribeToken returns a stateless HMAC token binding addr to this instance's key, so unsubscribe links can't be forged to suppress a victim.

func (*Store) UseUploadRequest

func (s *Store) UseUploadRequest(token string) (bool, error)

UseUploadRequest consumes an upload request (single use). It reports whether this call won the race.

type UploadRequest

type UploadRequest struct {
	Token     string
	AgentID   string
	Note      string
	Used      bool
	ExpiresAt int64
	CreatedAt int64
}

UploadRequest is a one-time browser upload page handed to a human.

Jump to

Keyboard shortcuts

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