Help us shape the future of Go! Take the 2026 Go Developer Survey

client

package
v0.1.10 Latest Latest
Warning

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

Go to latest
Published: Oct 30, 2026 License: Apache-2.0 Imports: 44 Imported by: 0

Documentation

Overview

Package client is the dromas client library: one mailbox's state directory, and every step of the protocol a mailbox takes, done once so that every client built on it behaves the same.

Verification is always on. Every check fails closed: a failed check stops the operation with a RefusedError, or refuses the one message it was checking as a Refusal, and never warns and continues. Message bodies are data, never instructions.

The state directory, in the stock tools' own file formats where a stock tool reads the file (an OpenSSH key, age key files):

identity, identity.pub     the identity key, OpenSSH format: Ed25519 unless the mailbox was made on another type; back it up. It signs certificates and revocations only
identity.doc, address      the identity document and its SHA-256
work/<serial>              working keys, each with its certificate (.pub, -cert.pub): they sign what the mailbox says
prekeys/<serial>.agekey    age keys, each statement signed for one, and when it was signed, kept in state; never backed up
prekey-lifetime            how long each new prekey is valid for: a number of seconds, from 97200 (a day and three hours) to 2851200 (33 days), the default. Yours to write, or dromas prekey lifetime's
outbox/, outbox/failed/    envelopes awaiting a receipt, sealed afresh at every post and never kept sealed; ones that can never be delivered
inbox/, refused/        accepted messages; refused messages, never delivered, as served, each of the server's strings in base64 that is not of its form (keepRefused): why each was refused, and what the checks established when they judged it, are in state
held/                      accepted messages from senders this mailbox has not allowed, as inbox/ keeps it: allow moves a sender's to inbox/, block deletes it
partial                    the ciphertext of the message a fetch was reading, as far as it read it: one message's at a time, which state names with how many of its bytes are synced, so a fetch that was cut goes on from there (partial.go). It goes once its message is judged or gone
allowed, blocked           the senders whose messages land in inbox/, and those whose messages are dropped: one address to a line, blank lines and lines starting with # skipped. send, alias and allow add to allowed, block to blocked; both are yours to edit
policy                     where messages from a sender not allowed land ("unknown held", the default, or "unknown inbox"), and whom the server takes messages from ("server all", the default, or "server allowed"). Yours to write
sent/                      sent messages the server took: each envelope with the server's receipt
aliases                    this mailbox's own names for peers: "<name> <address>" lines
gate                       on Windows alone, an empty file whose lock is the mailbox's gate, which a waiting writer holds so that readings that overlap do not hold it back: elsewhere the gate is a flock on the directory itself, where the system has flock (gate_unix.go)
state                      a bbolt database of what the client writes about the mailbox itself, each change one transaction (client/store.go): the prekey serial it published last, each prekey statement it signed and when, the renewal under way and one that failed, a restore's adoption of its server's ACL until it is done, a statement its server served in its name that it did not make, the pass it last signed, the ETag of the last empty poll, the ACL its server last took, and that a sync replaced one holding what no file of the mailbox says until recv reports it, its own revocations once one verifies, what its server's answers last said of its version (a deprecation and a sunset, each with its date) and when it last read its server's document, with the latest version that named, what it pinned of each peer, the replay set and its floor, and why each message in refused/ was refused. It is the mailbox's lock too: each command that writes the mailbox holds it open from its start to its end, a second process waits for it, and one killed leaves nothing. A mailbox directory on NFS is not supported
.gitignore                 "*": the mailbox ignores itself in any repository it lands in

Index

Constants

View Source
const (
	RefusedDecrypt    = "undecryptable"           // not encrypted to a prekey this mailbox holds, or not to exactly one recipient of a prekey's type
	RefusedReplay     = "replay"                  // this ciphertext was already received
	RefusedID         = "bad_id"                  // the server's id for it is not the SHA-256 of its ciphertext
	RefusedPrekeyType = "unsupported_prekey_type" // the recipient's prekey is an age recipient of a type this client cannot encrypt to
)

Why a message was refused, as codes: with protocol's (bad_message, bad_envelope, bad_identity, bad_signature, reattributed, stale), a closed set; and why a send refused its recipient's prekey statement when nothing is wrong with it (RefusedPrekeyType). A refusal's words are this client's own and never quote the message, its claimed sender's text or the server's: whoever reads a refusal may be a model.

View Source
const (
	RefusedRevoked     = "revoked"
	RefusedCertificate = "certificate_revoked"
)

RefusedRevoked is why a message from a revoked address is refused: this mailbox holds a revocation of the sender that verifies. RefusedCertificate is why a message under a revoked certificate is: its sender's address goes on, and the identity has revoked the certificate the message was signed under.

View Source
const (
	// LandHeld and LandInbox are where a message from a sender the mailbox has not
	// allowed lands: held/ (the default), or inbox/ as any other.
	LandHeld  = "held"
	LandInbox = "inbox"
	// AdmitAll and AdmitAllowed are whom the mailbox's server takes messages from:
	// every sender the mailbox has not blocked (the default), or only those it
	// has allowed.
	AdmitAll     = "all"
	AdmitAllowed = "allowed"
)

The values of a mailbox's policy.

View Source
const DefaultBase = "https://dromas.dev"

DefaultBase is the server every mailbox talks to unless told otherwise.

View Source
const DefaultDrainTime = 15 * time.Minute

DefaultDrainTime is how long one Receive drains while bytes move, unless Options.DrainTime (recv --drain-time) says otherwise: the drain's bound in time, beside its others. At it a call under way is cut, and a fetch keeps what it read for the next Receive to go on from (partial.go), so a drain of large messages on a slow link completes over several (#2, #381).

View Source
const DefaultHold = 4*time.Minute + 45*time.Second

DefaultHold is how long a mailbox asks the server to hold its list at first: under the 5 minutes at which common networks drop a silent connection.

View Source
const DevelVersion = "0.0.0-devel"

DevelVersion is the version a build that records none names: a build of this module's own checkout, Go's "(devel)", or one with no build information. A pre-release of 0.0.0, it is below every release.

View Source
const EchoAddress = "82be51e181471140db80904d4992a99383028c1fbc92e1f53614341def8c2225"

EchoAddress is the echo mailbox dromas.dev runs (cmd/dromas-echo): send it anything, and it answers with a signed reply saying what it checked and carrying the body back. Its prekey is post-quantum. A message to it is readable by dromas.dev's operator, who runs it.

View Source
const EchoAddressNoPQ = "518a0a89c533354f0d5a890599722a86d01b9b2d8c87549bb24c3276e819048c"

EchoAddressNoPQ is dromas.dev's second echo mailbox, whose prekey is X25519 only: the one a sender on age 1.2 can reach (sh/dromas.sh; this client reaches both). It answers as EchoAddress does, and a message to it is as readable by dromas.dev's operator.

View Source
const MinHold = time.Minute

MinHold is the shortest wait a mailbox asks for, however its connections drop: the poll budget covers a list a minute.

View Source
const MinPrekeyLifetime = renewAfter + time.Hour + renewTime + protocol.MaxSkew

MinPrekeyLifetime is the shortest a mailbox's prekeys may be valid for: the day Receive waits to renew one (renewAfter), an hour of slip for when recv runs, renewTime, and protocol.MaxSkew for clocks, the hour a sender's may read ahead of the mailbox's (PROTOCOL.md §3.4, §12.4). At it, an hourly recv renews in time.

View Source
const Module = "github.com/dromas-dev/dromas-client"

Module is this client's module path: the version of it a binary was built with is the version every request names (Version).

View Source
const ReceiveEvery = time.Hour

ReceiveEvery is the longest Await holds before it returns for a Receive, which renews the prekey when it is due.

Variables

This section is empty.

Functions

func DeprecationWords added in v0.1.9

func DeprecationWords(own string, at time.Time) string

DeprecationWords say, in this client's own words, that the server deems this client's version, own, deprecated from a date (RFC 9745 §2.1).

func Dir

func Dir() (string, error)

Dir returns the state directory of the mailbox to use, as the stock recipe finds it: $DROMAS_HOME if set, otherwise ${XDG_CONFIG_HOME:-$HOME/.config}/dromas/${DROMAS_MAILBOX:-default}, the XDG Base Directory Specification's home for configuration. It is never the working directory, which for a coding agent is a git repository.

func IsID

func IsID(s string) bool

IsID reports whether s is a message's id as this mailbox names it: the SHA-256 of its ciphertext, as 64 lowercase hex. Each file inbox/, held/ and refused/ keep is named by one.

func MinVersion added in v0.1.9

func MinVersion(p *protocol.Problem) (string, bool)

MinVersion is the min_version a version_retired carries, only where it is a policy's version (protocol.ParsePolicyVersion): a value of any other form is none, and a client shows none of it.

func Publish

func Publish(ctx context.Context, opt Options, rec *protocol.Revocations) (protocol.Address, error)

Publish publishes a record to the server opt names: a revocation of an address, a revocation of its certificates, or both. It needs no mailbox and no key, only the record, so a mailbox that is lost can still be revoked with a record made in advance (Mailbox.Revocation). Each part is checked here first, and a record with a part that does not verify goes nowhere.

func RecvWithin

func RecvWithin(lifetime time.Duration) time.Duration

RecvWithin is how often a mailbox must run Receive for a prekey of the given lifetime to be renewed while every sender whose clock a server takes still takes it: Receive renews one once it is a day old, and the prekey then has renewTime and protocol.MaxSkew left, the room whoever makes a time-limited thing leaves (PROTOCOL.md §3.4).

func Revoke

func Revoke(ctx context.Context, opt Options, rec *protocol.Revocations) (protocol.Address, error)

Revoke publishes a revocation to the server opt names: the address the record is for is revoked there, for good. It needs no mailbox and no key, only the record, so a mailbox that is lost can still be revoked with a record made in advance. The record is checked here first. It is Publish, of a record that must carry a revocation of the address.

func SunsetWords added in v0.1.9

func SunsetWords(own string, at time.Time) string

SunsetWords say, in this client's own words, that the mailbox's server stops taking this client's version, own, at a date (PROTOCOL.md §11.17).

func Transient added in v0.1.8

func Transient(err error) bool

Transient reports whether err is a call that failed and that making it again may get past: no answer, a server error, a rate limit or a request timeout. A refusal no wait mends, a revocation or an answer out of its form, is not.

func UpgradeWords added in v0.1.9

func UpgradeWords(own, latest string) string

UpgradeWords say, in this client's own words, that the mailbox's server names a later version of this client than own.

func ValidAlias

func ValidAlias(name string) error

ValidAlias returns nil if name can be an alias, and otherwise why not.

func Version added in v0.1.9

func Version() string

Version is the version this binary names in every request's Dromas-Version (PROTOCOL.md §11.17): the version of Module in its build information (runtime/debug), the binary's own module's where Module is the one built (the dromas command), or the one it depends on otherwise (a program that imports this library), without its "v" and without build metadata (Go's "+dirty", "+incompatible"). A Go pseudo-version is then a SemVer pre-release of the patch after the release it follows. A build that records none of these is DevelVersion.

Types

type APIError

type APIError struct {
	Status  int
	Problem protocol.Problem
	// RetryAfter is the server's Retry-After, or zero.
	RetryAfter time.Duration
	// Dated is the time in the answer's Date header, and Read this mailbox's
	// clock when the answer came: both zero unless the call carried a pass
	// and the answer a Date. They are set side by side in the error for a
	// pass or a statement refused for its time, and never adopted: a mailbox
	// checks everything against its own clock, and a server may lie about
	// the time as about anything else.
	Dated, Read time.Time
	// Version is the version the request named (Dromas-Version), for
	// version_retired's words.
	Version string
}

APIError is a non-2xx answer from the server. Problem is the RFC 9457 body when the server sent one with a code this client knows, for the status the code has, beside the type that is the code's own (PROTOCOL.md §11.3); otherwise its code is empty.

func (*APIError) Error

func (e *APIError) Error() string

Error is the status and the code, then what the code means, in this client's own words, with the values the error carries once each is checked to its type. Nothing the server wrote is in it: its detail, hint and title are for a person reading the body, and whoever reads this may be a model (PROTOCOL.md §11.3). A code this client does not know is not printed at all, since any text can be made to fit a code's grammar.

type Alias

type Alias struct {
	Name    string
	Address protocol.Address
}

Alias is this mailbox's own name for a peer's address: a word to send to in place of 64 hex characters. Aliases live in the mailbox's aliases file, one "<name> <address>" line each, and never leave the mailbox: neither the server nor the peer sees them. An alias is only as good as where its address came from.

type Delivery

type Delivery struct {
	ID       string // the SHA-256 of its ciphertext, as computed here
	Envelope *protocol.Envelope
	// Line is the envelope as ONE line of JSON, built by this client from the
	// checked fields (the identity document dropped), as kept in inbox/.
	// Print or pass on this, never Plaintext, whose bytes the sender chose.
	Line []byte
	// Plaintext is the envelope's line exactly as the sender signed it, and
	// Signature the signature block that verified over it: together they
	// show anyone that this sender wrote this to this mailbox. The client keeps
	// neither on disk.
	Plaintext []byte
	Signature []byte
	// contains filtered or unexported fields
}

Delivery is a message that passed every check.

type Fields

type Fields struct {
	Subject string
	// InReplyTo is the msg_id of the message this one answers, as its
	// envelope carried it: never the id the server lists a message by.
	InReplyTo string
	// Supersedes is the msg_id of an earlier message of this mailbox's that this
	// one replaces. The earlier one is not altered: the recipient decides.
	Supersedes string
}

Fields are an envelope's optional fields: the sender's own words about a message, encrypted with it, so the server sees none of them.

type Held

type Held struct {
	// Revoked is true when the mailbox holds a revocation of the address: it is
	// ended, for good.
	Revoked bool
	// Certificates is the highest revocation of the address's certificates
	// the mailbox holds, or nil. The address goes on.
	Certificates *protocol.RevokedCertificates
}

Held is what a mailbox holds about an address: what that address's identity signed about it, verified here, and kept. It is what a send to the address and a read of its messages are checked against, with no call to anyone.

type HoldResult added in v0.1.3

type HoldResult struct {
	// Changed reports that the mailbox's list changed, or that the mailbox must
	// receive to find out (its pass refused): a Receive follows.
	Changed bool
	// Dropped reports that a connection of the hold dropped: before the
	// hold's answer, seen as it dropped or only at the hold's deadline, or
	// on a reused connection that net/http sent the request again past,
	// which the hold's answer then follows. Wait and KeepAlive are then what
	// the mailbox asks for from now on.
	Dropped bool
	// After is how long the request was held on the connection it got
	// last.
	After           time.Duration
	Wait, KeepAlive time.Duration
}

HoldResult is what one held list came to.

type Mailbox added in v0.1.8

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

Mailbox is one mailbox: its state directory and the server it talks to. It is safe for concurrent use: a command or reading of one goroutine waits for another's, as one of another process does.

func Init

func Init(ctx context.Context, dir string, opt Options, kt protocol.KeyType) (*Mailbox, error)

Init creates a mailbox in dir, or finishes an init that stopped half way: it makes the identity, the first working key with its certificate, and the first prekey (of type kt) if they are missing, and registers the mailbox. The registration carries a pass the working key signs, so the mailbox is in use at once. Run again on a finished mailbox, it changes nothing.

func Open

func Open(dir string, opt Options) (*Mailbox, error)

Open opens an existing mailbox's state directory, its owner's alone as Init leaves it (makeDirs). A directory holding only the identity, a mailbox restored from its backup, gets the mailbox's other directories; Mailbox.Rekey then gives it a working key and a prekey, and the lists its server's ACL holds when it has none of its own.

func (*Mailbox) ACLPending added in v0.1.8

func (b *Mailbox) ACLPending(ctx context.Context) (bool, error)

ACLPending reports whether the mailbox's files say an ACL other than the one its server last took: the next send, recv, allow or block sends it.

func (*Mailbox) Address added in v0.1.8

func (b *Mailbox) Address() protocol.Address

Address returns the mailbox's address.

func (*Mailbox) Adopt added in v0.1.8

func (b *Mailbox) Adopt(ctx context.Context, key string) (string, error)

Adopt puts the mailbox in the account an adopt key names, and returns the account's id as the server gives it. An account can lift the mailbox's limits; the server can tell who pays for the mailbox, and nothing else about its messages changes. Keep the key secret: anyone holding it can adopt a mailbox into the account until it is spent or expires.

func (*Mailbox) Aliases added in v0.1.8

func (b *Mailbox) Aliases() ([]Alias, error)

Aliases returns the mailbox's aliases, sorted by name. A line of the aliases file that is not "<name> <address>" names nothing and is skipped.

func (*Mailbox) Allow added in v0.1.8

func (b *Mailbox) Allow(ctx context.Context, a protocol.Address) ([]Delivery, error)

Allow allows a sender: its messages land in inbox/ from now on, whatever the policy says, and what held/ keeps from it moves there. A sender the mailbox blocks is refused, with nothing done: blocking wins. The moved messages are returned as Receive delivers them, oldest first, but for Plaintext and Signature, which the mailbox never kept. Then the server is sent the mailbox's ACL, if the change is one it holds (Mailbox.SyncACL): an error from that leaves the sender allowed here.

func (*Mailbox) Allowed added in v0.1.8

func (b *Mailbox) Allowed() ([]protocol.Address, error)

Allowed returns the senders whose messages land in inbox/ whatever the policy says: those the allowed file lists and those an alias names.

func (*Mailbox) Ask added in v0.1.8

func (b *Mailbox) Ask(ctx context.Context, a protocol.Address) (*Held, error)

Ask asks this mailbox's server what it holds about a, keeps what verifies, and returns what the mailbox then holds: a mailbox may ask at any time, and whatever it has verified about an address it keeps. A send asks by itself (Mailbox.SendWith), and so does a drain, of each sender (Mailbox.Receive).

A server that answers that it holds nothing has answered, and that is its word: it can keep a record back, and nothing here tells. What the mailbox holds already stands whatever a server answers. No answer is an error.

func (*Mailbox) Await added in v0.1.8

func (b *Mailbox) Await(ctx context.Context, until time.Time, say func(*HoldResult, error)) error

Await holds the mailbox's list, one held request after another (Hold), until it changes, until passes or ReceiveEvery has, and returns for a Receive; a zero until is no deadline, as for a mailbox that waits for messages for as long as it runs. A call that holding again may get past (no answer, a server error, a rate limit) is held again, after its Retry-After where it gives one; a refusal no wait mends ends it, as its error. say, when not nil, is told of each: a held request that failed, with its error, and a connection that dropped, with its HoldResult. Await returns by until, its waits for a turn to hold included (Hold).

With under a second left Await waits it out, so the Receive after is the caller's last, never one of a burst of polls until the deadline passes.

func (*Mailbox) Block added in v0.1.8

func (b *Mailbox) Block(ctx context.Context, a protocol.Address) (int, error)

Block blocks a sender: its messages are dropped from now on, what its server holds from it at the next drain among it, and its server refuses its later sends; what held/ keeps from it is deleted. It returns how many held messages it deleted. Blocking wins over allowing. An error sending the server the mailbox's ACL leaves the sender blocked here, and the next send, recv, allow or block sends it.

func (*Mailbox) Blocked added in v0.1.8

func (b *Mailbox) Blocked() ([]protocol.Address, error)

Blocked returns the senders whose messages this mailbox drops, and its server refuses.

func (*Mailbox) CertificatesRecord added in v0.1.8

func (b *Mailbox) CertificatesRecord(ctx context.Context) (*protocol.Revocations, error)

CertificatesRecord is the record of this mailbox's own revocation of its certificates that it keeps, the one it published or was shown, or nil: what dromas cert publish-revoked sends again.

func (*Mailbox) Destination added in v0.1.8

func (b *Mailbox) Destination(s string) (protocol.Address, error)

Destination parses where to send: an address, a link to one on this mailbox's server, or one of this mailbox's aliases (see Mailbox.SetAlias). A link to another server is refused, since a mailbox sends only through its own.

func (*Mailbox) Dir added in v0.1.8

func (b *Mailbox) Dir() string

Dir returns the mailbox's state directory.

func (*Mailbox) Flush added in v0.1.8

func (b *Mailbox) Flush(ctx context.Context) ([]*Sent, error)

Flush posts again every message still in the outbox, each sealed afresh to what the mailbox holds now, as a send seals it: a seal is made for one post and never kept. A message the server took whose answer was lost is posted again as a new ciphertext, which the server stores and counts again and its reader drops by its msg_id (PROTOCOL.md §12.2). It tries every entry; one that fails never stops the others, and the error names each that failed. The server is asked about each recipient once, as a send asks (Mailbox.SendWith).

func (*Mailbox) HeldMessages added in v0.1.8

func (b *Mailbox) HeldMessages() ([]UnknownSender, error)

HeldMessages returns the messages held/ keeps, by sender, the sender with the oldest first. It reads only held/, and calls no server.

func (*Mailbox) Hold added in v0.1.8

func (b *Mailbox) Hold(ctx context.Context, wait time.Duration) (*HoldResult, error)

Hold holds the mailbox's list for up to wait, or the mailbox's own wait if that is shorter (DefaultHold, or what its drops taught it): the server answers once the mailbox's first page changes, or at the wait with nothing new. It first waits its turn (one a minute on average), and where the turn comes past the wait, it waits the wait out and holds nothing. It then holds the mailbox's lock only to read its tag and its pass, never through the hold, so the mailbox's other commands go on meanwhile. The held request reads nothing of the mailbox's state: an answer about a revocation is proved under the lock once it comes (provedLocked).

A mailbox with no tag kept, one whose last list found messages, or whose pass the server refused, is Changed at once, for a Receive to settle. An error is a call that failed and that holding again may get past (Transient): a refusal no wait mends (a revocation, an answer out of its form) is one too, which a caller tells by its kind (APIError, RevokedError).

func (*Mailbox) Identity added in v0.1.8

func (b *Mailbox) Identity() *protocol.Identity

Identity returns the mailbox's identity.

func (*Mailbox) Inbox added in v0.1.8

func (b *Mailbox) Inbox() ([]Delivery, error)

Inbox returns the messages inbox/ keeps, oldest first by sent_at (within a second as [Mailbox.keptMessages] orders it), each as Mailbox.InboxMessage returns it: what recv delivered and nobody has pruned since. A file that is not the line recv keeps is left out, as Mailbox.InboxMessage refuses it. It reads only inbox/, and calls no server.

func (*Mailbox) InboxMessage added in v0.1.8

func (b *Mailbox) InboxMessage(id string) (Delivery, error)

InboxMessage returns the message inbox/<id>.json keeps, as Receive delivered it but for Plaintext and Signature, which the mailbox never kept: its checked fields, as recv printed them ([Mailbox.keptLine]). An id that is not one is refused before any file is read.

func (*Mailbox) KeepRevocation added in v0.1.8

func (b *Mailbox) KeepRevocation(ctx context.Context, rec *protocol.Revocations) (a protocol.Address, h *Held, err error)

KeepRevocation takes a record someone handed over, of this mailbox's own address or of anyone's: a revocation of the address, a revocation of its certificates, or both. Each part is checked, and what verifies is kept. It is the answer to a server that hides one: the record proves itself wherever it came from. A record with a part that does not verify is refused whole, and nothing of it is kept: whoever handed it over is told, where a server's answer that does not verify counts as nothing shown.

It returns the address and what this mailbox then holds about it. A revocation of certificates through no higher a serial than the one held changes nothing.

func (*Mailbox) Leave added in v0.1.8

func (b *Mailbox) Leave(ctx context.Context) error

Leave takes the mailbox out of its account: it has the server's own limits again.

func (b *Mailbox) Link() string

Link returns the mailbox's link, <server>/to/<address>: what to give whoever should write to it.

func (*Mailbox) NotMade added in v0.1.8

func (b *Mailbox) NotMade(ctx context.Context) (*NotMade, error)

NotMade is the statement the mailbox's server served in its name, at the mailbox's last read of itself, that the mailbox did not make, or nil.

func (*Mailbox) Policy added in v0.1.8

func (b *Mailbox) Policy() (Policy, error)

Policy reads the mailbox's policy file: "<setting> <value>" lines, "unknown held" or "unknown inbox", and "server all" or "server allowed", each at most once, with blank lines and lines starting with "#" skipped. A file with any other line is an error, never a default: a policy that cannot be read stops what depends on it until it is put right.

func (*Mailbox) PrekeyLifetime added in v0.1.8

func (b *Mailbox) PrekeyLifetime() (time.Duration, error)

PrekeyLifetime is how long each new prekey of this mailbox is valid for: the seconds its prekey-lifetime file names, or protocol.PrekeyLifetime when it has none. A file that names anything but a lifetime from MinPrekeyLifetime to protocol.PrekeyLifetime is an error, never read as the default: the mailbox renews no prekey until it is put right.

func (*Mailbox) Publish added in v0.1.8

func (b *Mailbox) Publish(ctx context.Context, rec *protocol.Revocations) (protocol.Address, error)

Publish is Publish as this mailbox: to its own server, under its lock. It keeps nothing of the record (see Mailbox.KeepRevocation), but what the server shows when it answers that it holds as much already, once that verifies, as of every answer (proved).

func (*Mailbox) RebuildAllowed added in v0.1.8

func (b *Mailbox) RebuildAllowed(ctx context.Context) (int, error)

RebuildAllowed adds back to the allowed file every address the mailbox has an alias for or has sent messages to, as sent/ names them, and returns how many it added. What the file lists stays. It is for a mailbox whose allowed file was lost: send, alias and allow keep it otherwise.

func (*Mailbox) Receive added in v0.1.8

func (b *Mailbox) Receive(ctx context.Context) (*Result, error)

Receive drains the mailbox: every page, every message, up to the drain's limits, its time among them (Options.DrainTime). Each message is judged by one gate (see [Mailbox.judge]); only one that passes every check lands, where the mailbox's say over its sender puts it: inbox/ for a sender it allowed, held/ for one it has not (unless its policy lands such a message in inbox/ too), and nowhere for one it blocked. Refused messages go to refused/. All of them are acked. A transient error stops the drain and leaves the rest for the next one. It holds the mailbox's lock throughout ([Mailbox.hold]): a second Receive, or any other command that writes the mailbox, waits for it.

First it renews the prekey if the current one is more than a day old, so a mailbox received at least monthly never lapses. Once that renewal is taken, a read of the ACL its server holds is owed, and the first Receive that can make it makes it, renewing or not, and replaces one the mailbox did not send (aclAt, checkACL). A drain that empties the mailbox then deletes the retired prekeys no message can still need (see [Mailbox.dropRetired]): all but the newest. And once the server has answered the drain's list, so has taken a pass dated by this machine's clock, the prekeys whose deletion time has come by that pass's date go too.

A mailbox that holds its own revocation receives nothing.

func (*Mailbox) RefusedMessages added in v0.1.8

func (b *Mailbox) RefusedMessages(ctx context.Context) ([]RefusedMessage, error)

RefusedMessages lists refused/, by id: each message it keeps, with what the mailbox's state keeps of why it was refused. A message with no record there, or one this client did not write, has the code "unknown" and nothing from it. Each value is held to its form again as it is read.

func (*Mailbox) Rekey added in v0.1.8

func (b *Mailbox) Rekey(ctx context.Context, kt protocol.KeyType) (*protocol.Prekey, error)

Rekey publishes a NEW prekey, of type kt, or of the current prekey's type if kt is empty (post-quantum, init's default, when there is none to read), signed by a NEW working key under a new certificate. The three share one number, which this machine's clock gives (protocol.SerialAt). If an earlier Rekey signed one and the server did not take it, that one is sent again, unchanged, until it can no longer be sent (PROTOCOL.md §12.4): it has expired or does not verify by this clock, its certificate began less than an hour before the clock or is at or below a serial the identity revoked, it was made for longer than the mailbox's lifetime now allows or has no record of when it was made, this mailbox no longer holds its key or its working key, or another type is asked for. A key is signed once, so no key is encrypted to for longer than its lifetime, at most 33 days or the mailbox's shorter one, whatever the server does with what it was sent. It needs only the identity, so it also recovers a mailbox that lost its prekeys or its working key, and such a mailbox needs no record of the numbers the lost machine used; one that lost its allowed, blocked and policy files too takes them from the ACL its server holds (adoptPending). The upload carries a pass under the new certificate, and the server then takes no pass under an older one. Mailbox.Receive renews the prekey once it is more than a day old, so a mailbox received at least monthly never lapses; Rekey is for a new key type, for recovery, and for mailboxes that are only ever sent from.

It holds the mailbox's lock, so two runs never make the same serial's key at once, and it refuses a served serial below the highest this mailbox has published (a rollback), whose next serial's key was already published. A prekey with an error is one the server took, and a fault of this mailbox after that.

func (*Mailbox) RemoveAlias added in v0.1.8

func (b *Mailbox) RemoveAlias(ctx context.Context, name string) error

RemoveAlias removes a name. The peer's pinned identity and messages stay, and it stays allowed: un-naming a peer is not blocking it.

func (*Mailbox) RemoveRefused added in v0.1.8

func (b *Mailbox) RemoveRefused(ctx context.Context, ids []string) ([]string, error)

RemoveRefused deletes refused messages from refused/, each with what the mailbox's state keeps of it, and returns the ids it deleted; with no ids it deletes them all. An id that is not one, or that refused/ does not hold, is refused before anything is deleted.

It holds the mailbox's lock from start to end ([Mailbox.hold]), as every command that writes the mailbox does.

func (*Mailbox) RenewAndRevoke added in v0.1.8

func (b *Mailbox) RenewAndRevoke(ctx context.Context, kt protocol.KeyType) (*Remedy, error)

RenewAndRevoke is the remedy for a mailbox whose working key may have been taken, with the address kept: a revocation, signed by the identity, of every certificate before a new one, then a new prekey under a new working key and that new certificate.

It reads the mailbox once at its server, for what is held of the mailbox's own revocation of its certificates. An answer it cannot use stops nothing: the revocation still goes to the server (PROTOCOL.md §12.6). It sends nothing an earlier renewal left: whoever copied the mailbox while one waited holds its working key too.

The revocation is published first, once, through the serial below the number this machine's clock gives, or through the highest one held if that is higher. A server that holds a higher one it did not show answers conflict: the mailbox reads itself once more, keeps that one once it verifies, and goes on above it, or stops there with nothing renewed when it shows none that covers what this one would have. Only then is the new certificate numbered, one above the revocation, so it is never revoked as it is made, and the renewal is sent, once. Once a server has taken the revocation it takes nothing under the certificates it revokes, the one the mailbox was using among them: whoever holds that working key can no longer spend the mailbox's calls, and the renewal that follows spends none of the mailbox's counts, the calls a taker spent before the revocation among them (PROTOCOL.md §10.2, §11.9; dromas-dev/dromas-server#84). While the mailbox's server holds the revocation and not the renewal, the mailbox takes no messages there and signs none, and Mailbox.Receive and Mailbox.Rekey send the renewal again.

It returns no Remedy where it stopped before it published anything, a mailbox shown its own revocation on the way among them, which is its RevokedError alone; otherwise the Remedy says what each publish met, and an error beside it is a fault of this mailbox after a server took the revocation or the renewal, or the mailbox's own revocation, shown at the renewal.

func (*Mailbox) Resolve added in v0.1.8

func (b *Mailbox) Resolve(ctx context.Context, peer protocol.Address) (*protocol.Prekey, error)

Resolve fetches a peer's identity and current prekey and verifies them. It returns the prekey only when every check passes; until then there is nothing to encrypt to.

  • The identity is the pinned one, or at first contact the served one, which must hash to the address. A pin always wins over what the server sends later.
  • The prekey statement must be signed by a working key that identity certified, under a certificate valid now, in the peer's prekey namespace, and name the peer. One whose key is an age recipient of a type this client cannot encrypt to is refused with its own code, RefusedPrekeyType.
  • It may not be ordered before one already seen (rollback): under an earlier certificate, or under the same one with a lower serial. A later certificate outranks any serial under an earlier one, so a mailbox that moved to a new certificate is followed whatever serial it publishes.
  • Its certificate may not be one the peer's identity has revoked, by the revocation this mailbox holds, and it may not have expired.
  • A peer this mailbox holds a revocation of is refused before anything is asked: a RevokedError, whatever the server now serves for it.

The identity is pinned, and the serials recorded, only after every check passed: nothing is kept of a peer whose statement did not verify. It holds the mailbox's lock ([Mailbox.hold]).

func (*Mailbox) Revocation added in v0.1.8

func (b *Mailbox) Revocation(ctx context.Context) (*protocol.Revocations, error)

Revocation returns this mailbox's revocation: its identity document and the identity's signature over the fixed statement. It publishes nothing. The record is what Revoke sends, and it can be made long before it is needed and kept somewhere other than the mailbox. A mailbox that holds its own revocation returns the one it holds, and signs nothing (sign).

func (*Mailbox) Revoke added in v0.1.8

func (b *Mailbox) Revoke(ctx context.Context, rec *protocol.Revocations) (protocol.Address, error)

Revoke is Revoke as this mailbox: to its own server.

func (*Mailbox) RevokeEarlier added in v0.1.8

func (b *Mailbox) RevokeEarlier(ctx context.Context) (*protocol.RevokedCertificates, error)

RevokeEarlier revokes every certificate this mailbox's identity made before the one in use: it signs a revocation of them, publishes it, and keeps it. Mailbox.RenewAndRevoke is the whole remedy for a mailbox whose working key may have been taken, and is what "dromas cert revoke-earlier" runs; this is its second half alone, for a mailbox that has renewed already.

It revokes through the serial below the one in use, as the mailbox holds it once it has read itself at its server (known), which records a renewal the server took whose answer the mailbox never had. A mailbox numbers a certificate by its clock (protocol.SerialAt), so that covers every certificate made before this one on any machine, whether this mailbox knows of it or not: one a lost machine made and never published is among them, unless that machine's clock read ahead of this one's (PROTOCOL.md §5); a later run covers that one.

It returns the revocation, or nil when the certificate in use has serial 1, which nothing is below. A revocation with an error is one the server took, and a fault of this mailbox after that: the mailbox keeps it at its next read of itself (#383). A message this mailbox sent under those certificates, and that its reader has not read yet, is refused too: nobody can tell it from a thief's.

func (*Mailbox) Send added in v0.1.8

func (b *Mailbox) Send(ctx context.Context, to protocol.Address, body string) (*Sent, error)

Send sends one logical message with none of the optional fields: see Mailbox.SendWith.

func (*Mailbox) SendJSON added in v0.1.8

func (b *Mailbox) SendJSON(ctx context.Context, to protocol.Address, body []byte, f Fields) (*Sent, error)

SendJSON is Mailbox.SendWith with a body that is a JSON value, given as one JSON text, where SendWith's is text: an object, say, arrives as that object and not as a string holding it. It is refused whole, with nothing written, when its reader would refuse it (protocol.NewJSONEnvelope has the rules), and sent compact, as written.

func (*Mailbox) SendWith added in v0.1.8

func (b *Mailbox) SendWith(ctx context.Context, to protocol.Address, body string, f Fields) (*Sent, error)

SendWith sends one logical message: its envelope is built once and kept in the outbox, then sealed for the post: dated at the post, signed for that peer only by this mailbox's working key, and encrypted with that signature to the peer's verified prekey. On 409 stale_prekey it seals the SAME envelope to the newer prekey, once. If the post fails, the envelope stays in the outbox: retry with Mailbox.Flush, never by sending again, or the peer gets it twice. Once the server has it, the envelope and the server's receipt are kept in sent/.

Writing to a peer allows it: its replies land in inbox/, and the mailbox's server is sent the mailbox's ACL, when it changed, before anything is posted (Mailbox.SyncACL). One the server does not take holds the message in the outbox only when the ACL it last took does not admit the peer's reply, which it would refuse for good; otherwise the message is posted, and Sent.ACLErr says why the ACL was not taken (#180).

Before anything is posted the server is asked what it holds about the peer: a revocation of its address, or of its certificates. What verifies is kept, and the send is checked against what the mailbox then holds. With no answer nothing is posted, and the message stays in the outbox.

The signature is inside the encryption, so the server is handed none: it knows the sender from the pass the post carries. Every message is padded, after the signature, so that the server sees its size only to within a block (protocol.PaddedSize).

Nothing is written or sent when its reader would refuse the envelope for its form (PROTOCOL.md §3.3, §12.3 check 3): a noncharacter in the body or the subject is refused here, before the outbox.

It holds the mailbox's lock from start to end ([Mailbox.hold]), as every command that writes the mailbox does.

func (*Mailbox) SetAlias added in v0.1.8

func (b *Mailbox) SetAlias(ctx context.Context, name string, a protocol.Address) error

SetAlias names a peer's address, and allows it: its messages land in inbox/ (Mailbox.Allow). A name that already names another address is refused, never moved: remove it first, so no send goes to a peer other than the one the name meant when it was learned.

func (*Mailbox) SetPolicy added in v0.1.8

func (b *Mailbox) SetPolicy(ctx context.Context, p Policy) error

SetPolicy writes the mailbox's policy file. The server learns what it changes at the mailbox's next send, recv, allow or block (Mailbox.SyncACL).

func (*Mailbox) SetPrekeyLifetime added in v0.1.8

func (b *Mailbox) SetPrekeyLifetime(ctx context.Context, d time.Duration) error

SetPrekeyLifetime writes the mailbox's prekey-lifetime file: each prekey made from now on is valid for d, a whole number of seconds from MinPrekeyLifetime to protocol.PrekeyLifetime. The prekey in use keeps its own; Receive renews it at once if it was made for longer.

func (*Mailbox) Status added in v0.1.8

func (b *Mailbox) Status(ctx context.Context) (*Status, error)

Status reads the mailbox's own files and its state, read-only: it waits while a command writes the mailbox, and changes nothing.

func (*Mailbox) SyncACL added in v0.1.8

func (b *Mailbox) SyncACL(ctx context.Context) error

SyncACL sends the mailbox's server the ACL the mailbox's files say, unless that is the one it took last, which is the case for a mailbox that has blocked nobody and lets every sender reach the server: such a mailbox sends none, and its server holds none. Each one sent replaces whatever the server holds, whoever wrote it, and carries no If-Match (PROTOCOL.md §11.14): the mailbox's files are what its ACL is, so what another machine of the mailbox sent is replaced, not merged, and a precondition would only add a read and a 412 to end the same way. One the server answers mailbox_changed (the mailbox changed while it handled the request) is sent again as it is, once. The server's answer must be the ACL sent, and is kept in the mailbox's state. It reads nothing of the server first, but for a restore's adoption of its server's ACL (adoptPending), so it does not see an ACL another writer put there since: Mailbox.Receive reads that at each renewal (checkACL).

func (*Mailbox) Versions added in v0.1.9

func (b *Mailbox) Versions() *Versions

Versions is what this mailbox's commands met of its version: Options.Versions, where it was given one.

type NotMade

type NotMade struct {
	Serial            uint64 `json:"serial"`
	CertificateSerial uint64 `json:"certificate_serial"`
	// OwnCertificate is set when the statement is under a certificate this
	// mailbox made: one that certifies a working key it holds.
	OwnCertificate bool `json:"own_certificate"`
	// At is this machine's clock at that read.
	At string `json:"at"`
}

NotMade is a prekey statement the mailbox's server served in its name at the mailbox's last read of itself, verified under its identity, that the mailbox did not make: none it keeps. Under a certificate this mailbox made, whoever made it holds that certificate's working key, from a copy of the mailbox's directory, which holds the identity too; under one it did not, the identity certified someone else's working key, as on the lost machine a mailbox restored from its identity alone meets. Either way the mailbox recommends revoking the address (PROTOCOL.md §12.4), and recv renews nothing above it: Rekey, which its owner runs, does (#74).

func (*NotMade) Words

func (nm *NotMade) Words() string

Words says what nm is, to the mailbox's owner, and recommends what to do: in either case, revoking the address (PROTOCOL.md §12.4).

type Options

type Options struct {
	// Base is the server's base URL; DefaultBase if empty. It is https, or
	// http only to a server on this machine ([checkServerURL]).
	Base string
	// HTTPClient makes the requests; if nil, a client that cuts a request
	// after a minute, so a server that stops answering cannot hold the mailbox's
	// lock for ever: a send or a fetch of a ciphertext once a minute passes
	// with no byte of it moving, the wait for its answer's head among them,
	// with no bound on the whole, so a message of any size moves on a slow
	// link (#381); the rest of such a request, a send's answer once its
	// ciphertext is sent and a fetch's answer that is not its ciphertext, and
	// any other request, after a minute in all. A client
	// given here is used as it is, its own timeouts its choice, and none of
	// those bounds is added. The mailbox uses a copy of it that follows no
	// redirect ([followNone]).
	HTTPClient *http.Client
	// Now is the clock; time.Now if nil.
	Now func() time.Time
	// IdentityType is the type of identity key Init makes for a new mailbox:
	// protocol.IdentityEd25519 if empty, and that is the one to use. Every
	// client verifies an Ed25519 identity; a mailbox of any other type can
	// neither send to nor receive from a mailbox whose client does not verify
	// that type. An existing identity key is used as it is, whatever this
	// says.
	IdentityType string
	// SenderKeyTypes is what the mailbox declares with each prekey it
	// publishes: the identity key types of the senders it takes messages from
	// (protocol.AcceptsSender). Nil: every type this client verifies, which
	// is the one to use. The one entry protocol.AnySender is for a mailbox that
	// would not show which types it verifies: the server then takes messages
	// for it from a sender of any type, and this client refuses what it
	// cannot verify.
	SenderKeyTypes []string
	// Waiting, if not nil, is told when a command finds the mailbox's lock held
	// by another command of the mailbox, once, before it waits for it: a mailbox's
	// commands write its files one at a time.
	Waiting func()
	// DrainTime is how long one Receive drains while bytes move, holding the
	// mailbox's lock: past it the drain stops, as at its other limits
	// (Result.More), and a fetch under way keeps what it read for the next
	// Receive to go on from. Zero is DefaultDrainTime.
	DrainTime time.Duration
	// Version is the version every request names in Dromas-Version
	// (PROTOCOL.md §11.17): the function [Version] if empty, and that is the one to
	// use. Another is for a test, and must be of a request's form
	// (protocol.ParseVersion).
	Version string
	// Versions, if not nil, keeps what every mailbox made with these options
	// meets of its version, for the caller to say once its command is done
	// ([Versions]). Otherwise each Mailbox keeps its own.
	Versions *Versions
}

Options configures a Mailbox. The zero value is ready to use.

type Policy

type Policy struct {
	// Unknown is where a message from a sender the mailbox has not allowed lands:
	// LandHeld or LandInbox.
	Unknown string `json:"unknown"`
	// Server is whom the mailbox's server takes messages from: AdmitAll or
	// AdmitAllowed.
	Server string `json:"server"`
}

Policy is what a mailbox's policy file says. A mailbox with none, or a line left out, has the default.

func DefaultPolicy

func DefaultPolicy() Policy

DefaultPolicy is the policy of a mailbox whose policy file says nothing: a message from a sender the mailbox has not allowed is held, and the server refuses only senders the mailbox has blocked.

type Refusal

type Refusal struct {
	ID string
	// Code says which check failed: one of this package's Refused codes or
	// protocol's. Reason says it in this client's own words, which never
	// quote the message.
	Code   string
	Reason string
	// Findings is what the checks established about it before it was
	// refused (protocol.Findings): kept with it in refused/. Where the mailbox
	// holds a revocation of the address that signed it, or of its
	// certificate, it is the clock and the identity alone, with Signed false,
	// as for a signature that does not verify (#265).
	Findings *protocol.Findings
}

Refusal is a message that failed a check. It was kept in refused/, never delivered, and acked so that it leaves the server. It never blocks its claimed sender: a forgery may be the operator framing them.

type RefusedError

type RefusedError struct {
	// Code is the refusal's code, for a check that has one of its own:
	// RefusedPrekeyType. Otherwise it is empty.
	Code   string
	Reason string
}

RefusedError is a check that failed. The operation stopped there: nothing was encrypted, sent, delivered or recorded past the failed check.

func (*RefusedError) Error

func (e *RefusedError) Error() string

type RefusedMessage added in v0.1.8

type RefusedMessage struct {
	ID                string `json:"id"`
	Code              string `json:"code"`
	Reason            string `json:"detail,omitempty"`
	ReceivedAt        string `json:"received_at,omitempty"`
	JudgedAt          string `json:"judged_at,omitempty"`
	SignedBy          string `json:"signed_by,omitempty"`
	ClaimsIdentity    string `json:"claims_identity,omitempty"`
	CertificateSerial uint64 `json:"certificate_serial,omitempty"`
	CertificateBegan  string `json:"certificate_began,omitempty"`
	CertificateEnds   string `json:"certificate_ends,omitempty"`
	SentAt            string `json:"sent_at,omitempty"`
	MsgID             string `json:"msg_id,omitempty"`
}

RefusedMessage is a refused message in refused/, in this client's words: its id, the code it was refused for and why, the time the server gave, and what this client's checks established about it when it judged it (keptFindings), each only when it has its form. Nothing else of what the server or the sender wrote is in it.

type Remedy

type Remedy struct {
	// Below is the serial of the certificate this call made, numbered once
	// the revocation was final. Every certificate below it is revoked where
	// the revocation was taken.
	Below uint64
	// Prekey is the new prekey, if the server took it.
	Prekey *protocol.Prekey
	// NotRenewed is why the server did not take it, or nil.
	NotRenewed error
	// Revoked is the revocation of those certificates, if a server took it,
	// whether or not this mailbox kept it: one it did not keep is the call's
	// error, a fault of this mailbox after the server took it (#383).
	Revoked *protocol.RevokedCertificates
	// NotRevoked is why the mailbox's server did not take the revocation, or
	// nil. One it holds higher, shown and verified, is taken: Revoked is that
	// one.
	NotRevoked error
	// Unread is why the mailbox's own server's read of it could not be used (no
	// answer, a statement that does not verify, or one ordered before what
	// the mailbox published), or nil. The remedy went on: the certificate was
	// numbered from what the mailbox knows.
	Unread error
}

A Remedy is what Mailbox.RenewAndRevoke did.

type Result

type Result struct {
	// Delivered lists the messages that landed in inbox/: from a sender the mailbox
	// allowed, or from any sender under "unknown inbox".
	Delivered []Delivery
	// Held lists the messages that passed every check from a sender the mailbox has not
	// allowed, kept in held/ under "unknown held" ([Mailbox.Allow] moves them to
	// inbox/). Blocked names the messages from a sender the mailbox blocked, dropped.
	// Both were acked.
	Held    []Delivery
	Blocked []string
	// Duplicates are re-encrypted retries of messages already delivered:
	// acked, not delivered again.
	Duplicates []string
	Refused    []Refusal
	// More reports that the drain stopped at one of its limits (see
	// maxDrainMessages), its time among them (Options.DrainTime), or because
	// the server paced it: the rest is still on the server for the next
	// Receive, which goes on from what a fetch the time cut kept.
	More bool
	// Paced is how long the server asked the mailbox to wait before taking out
	// more, when it paced the drain (a 429 fetch_paced or refetch_spent with
	// Retry-After, on a fetch); zero otherwise.
	Paced time.Duration
	// PollAfter is the server's poll interval, in seconds: the list's
	// Retry-After.
	PollAfter int64
	// Renewed is the prekey this Receive published, the current one being
	// more than a day old; nil if none was due.
	Renewed *protocol.Prekey
	// RenewErr is why a due renewal failed. The drain went ahead, and a
	// later Receive tries again, at most hourly.
	RenewErr error
	// ACLErr is why the mailbox's ACL was not sent where it differs from the one
	// its server last took ([Mailbox.SyncACL]), or from one another writer put
	// there, which the renewal's read then kept as taken (checkACL). The drain
	// went ahead, and the next send or Receive sends it.
	ACLErr error
	// ACLReplaced reports that the read of the ACL the mailbox's server holds,
	// owed since a renewal recv began was taken and made by this Receive
	// (aclAt), found an ACL other than the one this mailbox last sent it, which
	// another machine of the mailbox, whoever holds its pass or the server itself
	// wrote, and that the mailbox sent its own in its place (checkACL); or that a
	// sync since the last Receive replaced an ACL a restore adopted that held
	// what no file of the mailbox says, or one another writer put that an owed
	// read kept and could not replace then (syncACL; #366, #377).
	ACLReplaced bool
	// NotMade is a statement the mailbox's server served in its name, at the
	// mailbox's last read of itself, that the mailbox did not make, or nil
	// ([NotMade]).
	NotMade *NotMade
	// contains filtered or unexported fields
}

Result is what one Receive did.

func (*Result) Again

func (r *Result) Again() time.Duration

Again is how long the mailbox waits before its next Receive: the server's poll interval, or a paced drain's wait when that is the later, since the next Receive begins with a list, which is a poll (PROTOCOL.md §11.11, §11.5). Sooner would spend the mailbox's polls, and be refused once they are spent, where the poll interval lets the server's pace of new messages refill meanwhile (#117).

type RevokedError

type RevokedError struct {
	Address protocol.Address
	// Own is true when the address is this mailbox's.
	Own bool
}

RevokedError is an address this mailbox holds a revocation of. The revocation verified here, so it is not the server's word: nothing is sent to that address or taken from it again, and nothing a server says later undoes it.

func (*RevokedError) Error

func (e *RevokedError) Error() string

type Sent

type Sent struct {
	To    protocol.Address
	MsgID string
	protocol.Receipt
	// ACLErr is why the mailbox's ACL, changed since its server last took one,
	// was not sent ([Mailbox.SyncACL]): the post went ahead, since the ACL the
	// server last took admits the recipient's reply. The next send or recv
	// sends it.
	ACLErr error
}

Sent is a message the server took: the mailbox it went to, the msg_id its envelope carries, and the server's receipt for it, checked against the ciphertext posted. Its ID is the server's id for the message, the SHA-256 of the ciphertext; MsgID names the message itself, on every re-encryption.

type Status

type Status struct {
	Address protocol.Address `json:"address"`
	// PrekeySerial and PrekeyNotAfter are the prekey this mailbox published
	// last: zero and empty if it holds none.
	PrekeySerial   uint64 `json:"prekey_serial"`
	PrekeyNotAfter string `json:"prekey_not_after"`
	// PrekeyMade is when that prekey was signed, by the record its client
	// kept: empty if there is none, and the next recv renews it.
	PrekeyMade string `json:"prekey_made,omitempty"`
	// PrekeyLifetime is how long each new prekey is valid for, in seconds:
	// the mailbox's prekey-lifetime file, or 33 days. Zero if the file names no
	// lifetime, and the mailbox then renews no prekey until it is put right.
	PrekeyLifetime int64 `json:"prekey_lifetime"`
	// CertificateSerial and CertificateNotAfter are the certificate of the
	// working key in use, the one made with that prekey: zero and empty if
	// the mailbox holds none it can sign with.
	CertificateSerial   uint64 `json:"certificate_serial"`
	CertificateNotAfter string `json:"certificate_not_after"`
	// RenewalPendingSince is when this mailbox signed the oldest new prekey it
	// still holds and has not seen published: empty if every renewal went
	// through.
	RenewalPendingSince string `json:"renewal_pending_since,omitempty"`
	Inbox               int    `json:"inbox"`
	Sent                int    `json:"sent"`
	Outbox              int    `json:"outbox"`
	OutboxFailed        int    `json:"outbox_failed"`
	Refused             int    `json:"refused"`
	// Held counts the messages held/ keeps from senders this mailbox has not allowed.
	Held int `json:"held"`
	// Policy is what the mailbox's policy file says, or the default.
	Policy Policy `json:"policy"`
	// Revoked is true when the mailbox holds a revocation of its own address
	// that verifies: the address is finished.
	Revoked bool `json:"revoked,omitempty"`
	// PrekeyNotMade is a statement the mailbox's server served in its name, at
	// its last read of itself, that it did not make, or nil ([NotMade]).
	PrekeyNotMade *NotMade `json:"prekey_not_made,omitempty"`
	// Attention says, in words, each thing that needs a look. It is empty
	// when nothing does.
	Attention []string `json:"attention"`
}

Status is what a mailbox can say of itself from its own files, with no call to the server: what a wrapper reads to learn that the mailbox needs a look.

type UnknownSender added in v0.1.5

type UnknownSender struct {
	From protocol.Address `json:"from"`
	// IDs name its messages in held/, oldest first by sent_at: held/<id>.json
	// is the line recv would have printed.
	IDs         []string `json:"ids"`
	FirstSentAt string   `json:"first_sent_at"`
	LastSentAt  string   `json:"last_sent_at"`
}

UnknownSender describes the messages held/ keeps from one sender.

type Versions added in v0.1.9

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

Versions is what the answers a command met said of this client's version (PROTOCOL.md §11.17): a deprecation of it, from the Deprecation an answer carried, a sunset of it, from the Sunset one carried, and an upgrade, from the latest version the server's document names, read at most once a day. Every Mailbox made with the same Options.Versions keeps what it met there, so whoever runs the command says it once at its end. A Mailbox made with none keeps its own (Mailbox.Versions). It is safe for concurrent use.

func (*Versions) Deprecation added in v0.1.9

func (v *Versions) Deprecation() (at time.Time, passed, ok bool)

Deprecation is the date of the earliest Deprecation an answer the command met carried, from which its server deems this client's version deprecated, and whether that date has passed at this client's clock; ok is false where none carried one of its form. A date to come says the version will be deprecated then (RFC 9745 §2.1).

func (*Versions) Own added in v0.1.9

func (v *Versions) Own() string

Own is the version this client names in every request.

func (*Versions) Sunset added in v0.1.9

func (v *Versions) Sunset() (time.Time, bool)

Sunset is the date of the earliest Sunset an answer the command met carried, the date its server stops taking this client's version, and false where none carried one of its form.

func (*Versions) Upgrade added in v0.1.9

func (v *Versions) Upgrade() (string, bool)

Upgrade is the latest version the server's document names, where the command read it and it is an upgrade for this client (protocol.PolicyVersion.Upgrade), and false otherwise: the document is read at most once a day, so this is said at most once a day.

Directories

Path Synopsis
internal
sign
Package sign holds a mailbox's keys: its identity, which signs certificates and revocations and nothing else, and its working keys, which sign what the mailbox says (PROTOCOL.md §5).
Package sign holds a mailbox's keys: its identity, which signs certificates and revocations and nothing else, and its working keys, which sign what the mailbox says (PROTOCOL.md §5).
taken
Package taken is a reading of a mailbox's clock that a server took: the date of a pass it checked, on a call it answered, the pass's not_after less protocol.PassLifetime.
Package taken is a reading of a mailbox's clock that a server took: the date of a pass it checked, on a call it answered, the pass's not_after less protocol.PassLifetime.

Jump to

Keyboard shortcuts

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