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

e2e

package
v0.56.0 Latest Latest
Warning

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

Go to latest
Published: Oct 11, 2026 License: MIT Imports: 23 Imported by: 0

Documentation

Overview

Package e2e carries the server-side AWARENESS of client-side (E2E) encrypted folders — nothing more. The server never sees a password or a key and cannot decrypt anything; this package only lets the pipelines recognise the two artifacts the client leaves behind so they stop doing pointless (and potentially leaky) work:

  • the folder marker `.filex-e2e.json` at an encrypted folder's root (public salt + verify blob — hidden from listings, but readable via the preview endpoint so the client can unlock);
  • the `filexe2e` magic prefix every encrypted file starts with.

Design + threat model: docs/E2E-ENCRYPTION.md.

Index

Constants

View Source
const (
	LongNameSuffix = ".fxl"
	SidecarSuffix  = ".fxl.name"
)

LongNameSuffix and SidecarSuffix are the two spellings a shortened encrypted name takes (docs/E2E-ENCRYPTION.md → "Encrypted names"): `<43 base64url>.fxl` for the item, `<43 base64url>.fxl.name` for the sidecar that holds its full encrypted name.

View Source
const (

	// FileHeaderFixedLen is magic (8) + version (1) + header length (4).
	FileHeaderFixedLen = 13
	// FileHeaderMaxLen is the largest header a writer produces or a reader
	// accepts — so FileHeaderFixedLen+FileHeaderMaxLen bytes always hold it.
	FileHeaderMaxLen = 64 * 1024
)
View Source
const (
	VaultFeature         = "vault" // the req entry
	VaultFormat          = 1       // vault.v, header byte 8, body version
	VaultMinPackLog2     = 16      // readers
	VaultMaxPackLog2     = 24      // readers
	VaultDefaultPackLog2 = 22      // writers: 4 MiB
	VaultLargePackLog2   = 24      // writers: 16 MiB
	VaultPackHeaderLen   = 32
	VaultIndexHeaderLen  = 40
	VaultIndexMinSize    = 65536
	VaultIndexReadMax    = 64 << 20
	VaultIndexWriteMax   = 32 << 20
	VaultKindPack        = 0x50
	VaultKindIndex       = 0x49
	VaultKeepGenerations = 3
	VaultEntriesWriteMax = 250000
	VaultEntriesWarn     = 200000
	VaultEntriesReadMax  = 1000000
	VaultMaxDepth        = 256
)
View Source
const AdoptedByEnv = "env:" + EnvEscrowAdopt

AdoptedByEnv is what the record says when consent came from the env var. It names the mechanism, so a future second mechanism is legible in the data instead of being flattened into a bare "adopted".

View Source
const EnvEscrowAdopt = "FILEX_INSTALLATION_E2E_ESCROW_ADOPT"

EnvEscrowAdopt is the operator's separate, explicit consent to turn escrow on for an installation that already exists.

Why a second variable and not just "the key changed from empty, so they must have meant it": an escrow key arrives by being pasted into a compose file, a Helm values file or a .env, often copied from another deployment or from the quickstart. That is exactly the shape of an accident, and the accident is silent — the installation gains a second key holder and only new folders get it, so nothing looks wrong until somebody needs the key on an old folder and it does not work.

Why an env var and not a CLI subcommand or an admin button: the operator has to set EnvEscrowKey anyway, and that is an env var. A CLI step would mean shell access to the container plus database credentials — routine on a VPS, awkward on Kubernetes and impossible on several managed platforms filex is deployed to — and it would still leave two places that must agree. An admin button would put "give the operator a key to every folder from now on" behind an HTTP session; the person entitled to that decision is the person who can edit the environment, which is where the decision already lives. One extra line, in the file they are already editing, read once and then dead, is the smallest thing that is still a deliberate act.

View Source
const EnvEscrowKey = "FILEX_INSTALLATION_E2E_ESCROW_KEY"

EnvEscrowKey is the install-time escrow public key. Unset or empty means escrow is disabled for this installation.

View Source
const EscrowAlg = "RSA-OAEP-256"

EscrowAlg is the only escrow algorithm this version understands. It is written into every escrow slot so a future format change is legible rather than silent.

View Source
const EscrowKeyBits = 3072

EscrowKeyBits is the modulus size `filex e2e-escrow keygen` mints. 3072 buys a comfortable margin over 2048 while still generating in about a second, which matters because an operator runs it interactively.

View Source
const EscrowMinKeyBits = 2048

EscrowMinKeyBits rejects a public key too small to take seriously.

View Source
const FileExtension = ".fxe"

FileExtension is the stored-name suffix of a single encrypted file.

View Source
const InstallationFile = "installation.json"

InstallationFile is the operator-readable mirror inside the data dir.

View Source
const MarkerName = syspath.E2EKeyFile

MarkerName is the folder marker filename dropped by the client at the root of every encrypted folder. Spelled once, in syspath (E2EKeyFile), whose listing and keyless-write rules judge it by this very name.

View Source
const PinnedByFirstBoot = "first-boot"

PinnedByFirstBoot is what the record says when escrow was there from the installation's first boot. Adoption never overwrites it — see Installation.

View Source
const SettingInstallation = "installation.pinned"

SettingInstallation is the settings-table key holding the pinned record.

View Source
const VaultTempPrefix = ".tmp-"

VaultTempPrefix starts the name of the server's temporary index file in v/idx/ while it commits one.

Variables

View Source
var (
	ErrPlaintextIntoEncrypted = errors.New("cannot move or copy a file into an encrypted folder: the server has no key, so the file would be stored unencrypted inside it. Upload it through the web UI with the folder unlocked instead")
	ErrEncryptedOutOfFolder   = errors.New("cannot move or copy an encrypted file out of its folder: it stays encrypted, and outside the folder nothing knows which password opens it")
	ErrAcrossEncrypted        = errors.New("cannot move or copy between two different encrypted folders: each folder has its own key, and the destination's key cannot open the source's files")
	ErrNestedEncrypted        = errors.New("cannot move an encrypted folder into another encrypted folder: encrypted folders cannot be nested")
)

ErrPlaintextIntoEncrypted / ErrEncryptedOutOfFolder / ErrAcrossEncrypted are the three ways to cross the boundary. They are separate errors because the operator-facing advice differs for each.

View Source
var ErrNoEscrowKey = errors.New("e2e: no escrow key configured")

ErrNoEscrowKey is returned when no escrow key is configured at all.

View Source
var ErrVaultHeader = errors.New("bad vault header")

ErrVaultHeader is what the header checks wrap.

View Source
var ErrVaultMalformed = errors.New("malformed vault key file")

ErrVaultMalformed is what ParseVaultKeyFile wraps for a key file that names the vault feature and breaks a rule of docs/E2E-VAULT-FORMAT.md → "The key file" (or for bytes that are not a JSON object at all).

View Source
var ErrVaultNewer = errors.New("the vault was written by a newer filex")

ErrVaultNewer is what ParseVaultKeyFile wraps for a vault whose format (vault.v) is newer than this filex: the reader refuses it and says a newer filex is needed.

View Source
var FileMagicPrefix = []byte("filexfxe")

FileMagicPrefix is the 8-byte prefix of a single encrypted file (`.fxe`, docs/E2E-ENCRYPTION.md → "Single encrypted files"): a file encrypted on its own, outside any encrypted folder, carrying its own key slots.

View Source
var MagicPrefix = []byte("filexe2e")

MagicPrefix is the 8-byte prefix of every client-encrypted file.

View Source
var VaultMagicPrefix = []byte("filexvlt")

VaultMagicPrefix is the 8-byte magic of packs and index files.

Functions

func CheckVaultIndexHeader added in v0.54.0

func CheckVaultIndexHeader(b []byte, gen uint64) error

func CheckVaultPackHeader added in v0.54.0

func CheckVaultPackHeader(b []byte, id [16]byte, packLog2 int) error

CheckVaultPackHeader / CheckVaultIndexHeader check the plaintext headers (magic, version, kind, zeros, log2/generation, id) - all the server can.

func ConversionPending added in v0.48.0

func ConversionPending(markerBytes []byte) bool

ConversionPending reports whether a key file says an in-place conversion is under way: v3, `req` naming "conv", and a conv slot with `pending: true` (docs/E2E-ENCRYPTION.md → "Encrypting a folder you already have"). While it is, and only then, the server lets a write replace a plaintext file in the folder with its ciphertext without keeping the plaintext as a version - and only a write by somebody who may delete the folder's versions anyway: the flag is the client's word, never the right (api/handlers/e2e_convert.go).

func EscrowKeyID

func EscrowKeyID(spkiDER []byte) string

EscrowKeyID is the stable short name of an escrow key: the first 8 bytes of SHA-256 over the SPKI DER, hex-encoded. The browser computes the same value from the same bytes (escrowKeyId in e2ecrypto.ts).

func FileAt added in v0.48.0

func FileAt(ctx context.Context, lk NodeByPathLookup, storageID int64, rel string) bool

FileAt reports whether rel names a live, catalogued single encrypted file (`.fxe`): a FILE row whose name carries the extension. It is what the escrow and password endpoints act on when their subject is one file rather than a folder — the file holds its own key slots, so it is its own "root".

A directory named `something.fxe` is not one, and neither is a name the catalogue does not know: the endpoints answer 400 for both, as they do for a folder without a key file.

func FindRoot

func FindRoot(ctx context.Context, lk NodeByPathLookup, storageID int64, dir string) (string, bool)

FindRoot walks dir and its ancestors (deepest first, storage root last) and returns the relative path of the nearest directory carrying an encrypted-folder marker. ok=false when no ancestor is marked. The returned root is trimmed of slashes ("" = the storage root itself).

func GenerateEscrowKeyPair

func GenerateEscrowKeyPair(bits int) (spkiB64, pkcs8B64 string, err error)

GenerateEscrowKeyPair mints a fresh escrow keypair and returns both halves base64-encoded: SPKI for the server's config, PKCS#8 for the admin's safe.

⚠ The private half is returned to the caller and never written anywhere by filex. `filex e2e-escrow keygen` prints it once; that is the only copy that will ever exist.

func GuardTransfer

func GuardTransfer(ctx context.Context, lk NodeByPathLookup, srcStorageID int64, srcRels []string, dstStorageID int64, dstRel string) error

GuardTransfer reports whether a copy/move of srcRels (relative paths on srcStorageID) into dstRel (a directory on dstStorageID) crosses an encryption boundary.

A nil lookup, or a deployment with no encrypted folders at all, costs one cheap ancestor walk per item and always returns nil.

func HasEncryptedPrefix added in v0.48.0

func HasEncryptedPrefix(b []byte) bool

HasEncryptedPrefix reports whether b starts with any of the three magics — a file in an encrypted folder (`filexe2e`), a single encrypted file (`filexfxe`), or a vault's pack or index file (`filexvlt`, vault.go). Every pipeline that would read content (thumbnails, content indexing, document editing) treats them the same: ciphertext it cannot, and must not try to, render.

func HasMagicPrefix

func HasMagicPrefix(b []byte) bool

HasMagicPrefix reports whether b starts with the encrypted-FOLDER-file magic. HasEncryptedPrefix recognises every kind of encrypted file.

func HasVaultMagic added in v0.54.0

func HasVaultMagic(b []byte) bool

HasVaultMagic reports whether b starts with the vault magic (a pack or an index file). HasEncryptedPrefix recognises it too.

func IsRoot added in v0.50.0

func IsRoot(ctx context.Context, lk NodeByPathLookup, storageID int64, dir string) bool

IsRoot reports whether dir is itself an encrypted folder: it holds a live marker. The one test behind the listing badge (`e2e: true` on a folder row), the AI surface's `encrypted` folder and the transfer guard's "an encrypted folder may move, its marker travels with it".

func KeepsVaultBlock added in v0.54.0

func KeepsVaultBlock(before, after []byte) bool

KeepsVaultBlock is the vault's rule for a key file written through an ordinary door (docs/E2E-VAULT-FORMAT.md → The key file): before is the key file there now (nil when there is none, or it could not be read), after the bytes about to replace it.

  • a vault's key file keeps its `v`, `req` and `vault` (SameVaultBlock): a password change, a recovery reset, an escrow slot - nothing else;
  • no write makes a folder a vault: a key file that names the vault feature is created only by the vault API, in a new or empty folder, never over a level-1 or level-2 key file;
  • a key file that is no vault's, before and after, is not this rule's business (DiffKeyFiles and the encryption rule are).

func LooksEncryptedFile added in v0.48.0

func LooksEncryptedFile(name string) bool

LooksEncryptedFile reports whether a stored NAME is a single encrypted file's — the check that needs no read, for skipping work before anything is opened. The content sniff (HasEncryptedPrefix) is the authority.

func LooksEncryptedName added in v0.48.0

func LooksEncryptedName(name string) bool

LooksEncryptedName reports whether a stored name has the SHAPE of a name the browser encrypted: base64url with no dot and at least 23 characters, a shortened `<43>.fxl` item, its `.fxl.name` sidecar — or either of the first two followed by `.` and a folder's 22-character id (a folder's name, docs/E2E-ENCRYPTION.md → "Folder ids").

The server holds no key and cannot tell an encrypted name from a plaintext one that happens to look like it, so this is used for exactly one thing: REFUSING to invent a name next to one (the `-copy` suffix of a colliding copy or move). A name the server makes up inside a folder whose names are encrypted is a name nobody can decrypt, so the right answer there is a conflict the person resolves, not a silent new name.

func NamesEncrypted added in v0.56.0

func NamesEncrypted(markerBytes []byte) bool

NamesEncrypted reports whether a key file says the folder's NAMES are encrypted (level 2, docs/E2E-ENCRYPTION.md → "Encrypted names"): v3 with `names` among its required features and a names slot - the browser's markerHasNames. A level-1 key file, a vault's (`req` exactly ["vault"]), bytes that are not a key file: false.

⚠ The key file is the client's word, like every field of it: what this answers is only what the server cannot read - the kind of a file whose stored name is ciphertext (handlers app_ui_e2e.go: an app door leaves that kind to the browser) - never a right.

func ParseVaultGeneration added in v0.54.0

func ParseVaultGeneration(s string) (uint64, bool)

ParseVaultGeneration reads a generation written as 16 lower-case hex digits (an index file's name without `.fxi`). Generation 0 is no generation.

func ParseVaultID added in v0.54.0

func ParseVaultID(s string) ([16]byte, bool)

ParseVaultID reads a pack id or a vault id written as 32 lower-case hex digits (the spelling of a pack's name and of the `id` query parameter).

func ReadFileHeader added in v0.48.0

func ReadFileHeader(b []byte) (map[string]json.RawMessage, bool)

ReadFileHeader returns the JSON fields of the `.fxe` header b starts with, or ok=false when b is not one (wrong magic or version, a length out of range, a header cut short, or not a JSON object).

func RetiredSecret added in v0.48.0

func RetiredSecret(old, now []byte) bool

RetiredSecret reports whether old holds the file key now holds under a password or recovery slot now no longer uses: a copy that opens the file's CURRENT contents with a secret that was changed. That, and only that, is what a password change leaves behind as a liability.

func SameFileKey added in v0.48.0

func SameFileKey(x, y []byte) bool

SameFileKey reports whether two `.fxe` headers wrap the same file key: the same wrapped `dek` bytes, which a writer never reproduces by chance (every wrap takes a fresh IV). Such a pair holds the same content under the same folder-master key — so the older one's password opens the newer one's body.

func SameVaultBlock added in v0.54.0

func SameVaultBlock(before, after []byte) bool

SameVaultBlock reports whether two key files agree on v, req and vault (compact JSON) - the rule a key-file rewrite must keep.

The comparison is of the canonical form (keys sorted, no white space): a client that re-serialises the key file with its keys in another order has not changed the block. A field present in one and missing in the other is a change; bytes that are not a JSON object never agree.

func UnderEncrypted

func UnderEncrypted(ctx context.Context, lk NodeByPathLookup, storageID int64, nodePath string) bool

UnderEncrypted reports whether nodePath (a FILE or dir path, relative) sits inside an encrypted folder subtree — i.e. any of its ancestor directories carries the marker. Used by the thumb pipeline and the content extractor to skip work on ciphertext.

func ValidVaultIndexSize added in v0.54.0

func ValidVaultIndexSize(n int64) bool

ValidVaultIndexSize reports whether n can be an index file's size: 65536 ≤ n ≤ 64 MiB and Padmé(n) == n.

func VaultIndexFileSize added in v0.54.0

func VaultIndexFileSize(bodyLen int64) int64

VaultIndexFileSize is an index file's size for a body of bodyLen bytes: max(65536, Padmé(40+bodyLen+16)).

func VaultIndexPath added in v0.54.0

func VaultIndexPath(gen uint64) string

VaultIndexPath is "v/idx/0000000000000003.fxi".

func VaultPackPath added in v0.54.0

func VaultPackPath(id [16]byte) string

VaultPackPath is "v/p/b0/b067….fxp".

func VaultPadme added in v0.54.0

func VaultPadme(n int64) int64

VaultPadme is Padmé(n) (Nikitin et al., PETS 2019): E = ⌊log2 n⌋, S = ⌊log2 E⌋ + 1, step = 2^(E-S), the result n rounded up to a multiple of step. 0 for n ≤ 0.

Types

type Adoption

type Adoption struct {
	// Allowed is the consent itself. False means empty -> set is refused
	// exactly as it was before adoption existed.
	Allowed bool
	// By is written verbatim into the record as e2e_escrow_adopted_by.
	By string
}

Adoption is the operator's explicit consent to adopt escrow, and the record of how it was given.

func ResolveAdoption

func ResolveAdoption() Adoption

ResolveAdoption reads the operator's consent from the environment. Booleans follow the same rule as the rest of filex: "1" or "true".

type EscrowKey

type EscrowKey struct {
	// KID is the first 8 bytes of SHA-256(SPKI) in hex — the short name
	// that appears in every escrow slot and in the boot banner.
	KID string
	// SPKI is the DER public key, base64, exactly as the browser imports it.
	SPKI string
	Bits int
	// contains filtered or unexported fields
}

EscrowKey is a parsed, validated installation escrow public key.

func ParseEscrowPublicKey

func ParseEscrowPublicKey(s string) (*EscrowKey, error)

ParseEscrowPublicKey validates an operator-supplied escrow public key.

Accepts base64 SPKI DER with or without PEM armour and with any whitespace, because it arrives through an env var that has been through a shell, a .env file and probably a copy-paste.

func ResolveEscrow

func ResolveEscrow() (*EscrowKey, error)

ResolveEscrow reads and validates the install-time escrow key from the environment. A missing or empty value means escrow is off. A present but unparseable value is an error — silently running without escrow when the operator believes they configured it is the one outcome to avoid.

func (*EscrowKey) SealNonce

func (k *EscrowKey) SealNonce(nonce []byte) ([]byte, error)

SealNonce encrypts a challenge nonce to the escrow public key, so that only a caller actually holding the private half can echo it back.

This is what turns "someone claims they used the escrow key" into "someone demonstrably had the escrow key in their browser". It does NOT stop an operator from decrypting files offline with the same key and never telling anyone — see docs/E2E-ENCRYPTION.md.

type FileHeaderDiff added in v0.48.0

type FileHeaderDiff struct {
	// Valid: the new bytes carry a readable `.fxe` header.
	Valid bool
	// Compared: there was a readable previous header to compare with.
	Compared bool
	// Changes, sorted: "password" (salt, iter, verify, fmk_pw), "recovery_key"
	// (rk), "escrow" (esc), "content" (dek, nonce, size, chunk), "name" (the
	// sealed original name), "other" (anything else).
	Changes []string
	// SecretChanged: the password or the recovery slot changed — the event
	// after which a copy under the old secret is a liability.
	SecretChanged bool
}

FileHeaderDiff says what changed between two headers of the same `.fxe`.

func DiffFileHeaders added in v0.48.0

func DiffFileHeaders(before, after []byte) FileHeaderDiff

DiffFileHeaders compares the header before (the version an overwrite kept, or nil) with the header after (the file as it is now).

type Installation

type Installation struct {
	// E2EEscrowKID is the escrow key id, or "" when escrow is disabled.
	E2EEscrowKID string `json:"e2e_escrow_kid"`
	// E2EEscrowSPKI is the escrow public key, kept so the mirror file is
	// self-contained. It is public material; nothing here is a secret.
	E2EEscrowSPKI string `json:"e2e_escrow_spki,omitempty"`
	E2EEscrowAlg  string `json:"e2e_escrow_alg,omitempty"`
	// PinnedAt / PinnedBy describe the FIRST BOOT and are never rewritten,
	// not even by an adoption. "When was this installation created?" and
	// "when did it gain a second key?" are two questions, and answering the
	// second by overwriting the first would destroy the only record of the
	// installation's own age.
	PinnedAt string `json:"pinned_at,omitempty"`
	PinnedBy string `json:"pinned_by,omitempty"`
	// E2EEscrowAdoptedAt is set only when escrow was turned on AFTER the
	// first boot. Its presence is the whole answer to "was this first-boot
	// or adoption?", and its value is the boundary: folders created before
	// this instant carry no escrow slot and never will.
	E2EEscrowAdoptedAt string `json:"e2e_escrow_adopted_at,omitempty"`
	// E2EEscrowAdoptedBy records HOW consent was given (AdoptedByEnv today).
	E2EEscrowAdoptedBy string `json:"e2e_escrow_adopted_by,omitempty"`
	// E2EEscrowAdoptionNote is written alongside them so the mirror file
	// explains itself to a reader who has never seen this documentation.
	E2EEscrowAdoptionNote string `json:"e2e_escrow_adoption_note,omitempty"`
	// JustAdopted is true only on the boot that PERFORMED the adoption, so
	// that boot can say so once and loudly. It describes this process, not
	// the installation, so it is never written to the record — comparing
	// E2EEscrowAdoptedAt against the boot clock would have been close
	// enough almost always and wrong for a restart inside the same second.
	JustAdopted bool `json:"-"`
}

Installation is the pinned record. Fields are add-only: a newer filex reading an older record must see zero values, never a parse error.

func PinInstallation

func PinInstallation(ctx context.Context, store SettingsStore, dataDir string, escrow *EscrowKey, now string, adopt Adoption) (Installation, error)

PinInstallation records the install-time settings on first boot, verifies them on every boot after that, and performs the one change that is allowed: adopting escrow on an installation that already exists.

adopt carries the operator's explicit consent (see Adoption). It is consulted for exactly one transition, escrow off -> escrow on, and is ignored everywhere else — a first boot does not need consent, and no consent makes a key SWAP or a key REMOVAL safe.

Returns the effective record. An *InstallationMismatchError means the caller must abort — see server.New.

func (Installation) EscrowAdopted

func (i Installation) EscrowAdopted() bool

EscrowAdopted reports whether escrow was adopted rather than present from the first boot.

type InstallationMismatchError

type InstallationMismatchError struct {
	Setting  string
	Pinned   string
	Supplied string
	DataDir  string
	// Adoptable is true for the one transition that CAN be performed —
	// escrow off -> escrow on — when the operator has not yet said they
	// mean it. The message then explains adoption and its permanent limit
	// instead of only listing the two ways to back out.
	Adoptable bool
}

InstallationMismatchError is returned when the environment disagrees with what this installation was initialised with. Its message is the whole point: it must tell an operator what changed, why filex will not simply do as it is told, and what their actual options are.

func (*InstallationMismatchError) Error

func (e *InstallationMismatchError) Error() string

type KeyFileDiff added in v0.48.0

type KeyFileDiff struct {
	// Valid: the new bytes are a JSON object with a version and a salt — a
	// key file, not a stray upload under its name. Nothing is deleted
	// otherwise.
	Valid bool
	// Changes, sorted: "password", "recovery_key", "escrow", "level",
	// "rekey", "conversion", "created" and "other".
	Changes []string
	// KeySlotChanged: the password or the recovery slot changed, so every
	// earlier version wraps the folder key under a secret that should no
	// longer open it.
	KeySlotChanged bool
}

KeyFileDiff says what a rewrite changed.

func DiffKeyFiles added in v0.48.0

func DiffKeyFiles(before, after []byte) KeyFileDiff

DiffKeyFiles compares the key file before a rewrite with the one after it. before may be nil (not known — no version was kept).

type NodeByPathLookup

type NodeByPathLookup interface {
	GetNodeByPath(ctx context.Context, storageID int64, pathHash string) (*model.Node, error)
}

NodeByPathLookup is the narrow store surface the ancestor walk needs. db.Store satisfies it.

type SettingsStore

type SettingsStore interface {
	GetSetting(ctx context.Context, key string) (string, error)
	UpsertSetting(ctx context.Context, key, value string) error
}

SettingsStore is the narrow store surface the pin needs. db.Store satisfies it.

type TransferGuardError

type TransferGuardError struct {
	Source string
	Dest   string
	Reason error
}

TransferGuardError names the item that was refused alongside the reason, so the message a user sees says which file, not just "no".

func (*TransferGuardError) Error

func (e *TransferGuardError) Error() string

func (*TransferGuardError) Unwrap

func (e *TransferGuardError) Unwrap() error

type VaultInfo added in v0.54.0

type VaultInfo struct {
	V        int
	ID       [16]byte
	PackLog2 int
}

VaultInfo is the key file's `vault` block.

func ParseVaultKeyFile added in v0.54.0

func ParseVaultKeyFile(b []byte) (info VaultInfo, isVault bool, err error)

ParseVaultKeyFile reads a key file. isVault is false for a level-1/2 key file (no "vault" in req); err is non-nil for a key file that names "vault" and breaks a rule of docs/E2E-VAULT-FORMAT.md → "The key file" (req not exactly ["vault"], fmk not "wrapped", vault.v != 1, a bad id or pack), and for bytes that are not a JSON object (isVault false then).

errors.Is(err, ErrVaultNewer) for a vault.v above 1 - asked first, so a later format that changes anything else is still told apart from damage; errors.Is(err, ErrVaultMalformed) for everything else.

func (VaultInfo) IDHex added in v0.54.0

func (v VaultInfo) IDHex() string

IDHex is the vault id as 32 lower-case hex digits - the spelling the server keys its write lock by and names in its answers.

type VaultPathKind added in v0.54.0

type VaultPathKind int
const (
	VaultPathOther VaultPathKind = iota
	VaultPathKeyFile
	VaultPathPack
	VaultPathIndex
	VaultPathTemp // v/idx/.tmp-*
)

func ParseVaultPath added in v0.54.0

func ParseVaultPath(rel string) (kind VaultPathKind, id [16]byte, gen uint64)

ParseVaultPath classifies rel, a path RELATIVE TO THE VAULT ROOT.

The names are exact: lower-case hex only, a pack's folder the first two digits of its id, generation 0 no index. Anything else is VaultPathOther - a reader ignores it and a writer never makes it.

Directories

Path Synopsis
Package fxewatch is the server's own record of a rewritten single encrypted file (`.fxe`): an audit row for every rewrite of one, and — when the rewrite changed its password or recovery slot — the deletion of the older versions that still open the file with the old secret.
Package fxewatch is the server's own record of a rewritten single encrypted file (`.fxe`): an audit row for every rewrite of one, and — when the rewrite changed its password or recovery slot — the deletion of the older versions that still open the file with the old secret.
Package slotchange is what the server does when a write changed a KEY SLOT of something end-to-end encrypted - the password or the recovery slot of an encrypted folder's key file (`.filex-e2e.json`, e2e/keyfilewatch) or of a single encrypted file's header (`.fxe`, e2e/fxewatch): who may retire the old copies that still open it with the old secret, and who is told.
Package slotchange is what the server does when a write changed a KEY SLOT of something end-to-end encrypted - the password or the recovery slot of an encrypted folder's key file (`.filex-e2e.json`, e2e/keyfilewatch) or of a single encrypted file's header (`.fxe`, e2e/fxewatch): who may retire the old copies that still open it with the old secret, and who is told.

Jump to

Keyboard shortcuts

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