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
- Variables
- func CheckVaultIndexHeader(b []byte, gen uint64) error
- func CheckVaultPackHeader(b []byte, id [16]byte, packLog2 int) error
- func ConversionPending(markerBytes []byte) bool
- func EscrowKeyID(spkiDER []byte) string
- func FileAt(ctx context.Context, lk NodeByPathLookup, storageID int64, rel string) bool
- func FindRoot(ctx context.Context, lk NodeByPathLookup, storageID int64, dir string) (string, bool)
- func GenerateEscrowKeyPair(bits int) (spkiB64, pkcs8B64 string, err error)
- func GuardTransfer(ctx context.Context, lk NodeByPathLookup, srcStorageID int64, srcRels []string, ...) error
- func HasEncryptedPrefix(b []byte) bool
- func HasMagicPrefix(b []byte) bool
- func HasVaultMagic(b []byte) bool
- func IsRoot(ctx context.Context, lk NodeByPathLookup, storageID int64, dir string) bool
- func KeepsVaultBlock(before, after []byte) bool
- func LooksEncryptedFile(name string) bool
- func LooksEncryptedName(name string) bool
- func NamesEncrypted(markerBytes []byte) bool
- func ParseVaultGeneration(s string) (uint64, bool)
- func ParseVaultID(s string) ([16]byte, bool)
- func ReadFileHeader(b []byte) (map[string]json.RawMessage, bool)
- func RetiredSecret(old, now []byte) bool
- func SameFileKey(x, y []byte) bool
- func SameVaultBlock(before, after []byte) bool
- func UnderEncrypted(ctx context.Context, lk NodeByPathLookup, storageID int64, nodePath string) bool
- func ValidVaultIndexSize(n int64) bool
- func VaultIndexFileSize(bodyLen int64) int64
- func VaultIndexPath(gen uint64) string
- func VaultPackPath(id [16]byte) string
- func VaultPadme(n int64) int64
- type Adoption
- type EscrowKey
- type FileHeaderDiff
- type Installation
- type InstallationMismatchError
- type KeyFileDiff
- type NodeByPathLookup
- type SettingsStore
- type TransferGuardError
- type VaultInfo
- type VaultPathKind
Constants ¶
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.
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 )
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 )
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".
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.
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.
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.
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.
const EscrowMinKeyBits = 2048
EscrowMinKeyBits rejects a public key too small to take seriously.
const FileExtension = ".fxe"
FileExtension is the stored-name suffix of a single encrypted file.
const InstallationFile = "installation.json"
InstallationFile is the operator-readable mirror inside the data dir.
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.
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.
const SettingInstallation = "installation.pinned"
SettingInstallation is the settings-table key holding the pinned record.
const VaultTempPrefix = ".tmp-"
VaultTempPrefix starts the name of the server's temporary index file in v/idx/ while it commits one.
Variables ¶
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.
var ErrNoEscrowKey = errors.New("e2e: no escrow key configured")
ErrNoEscrowKey is returned when no escrow key is configured at all.
var ErrVaultHeader = errors.New("bad vault header")
ErrVaultHeader is what the header checks wrap.
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).
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.
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.
var MagicPrefix = []byte("filexe2e")
MagicPrefix is the 8-byte prefix of every client-encrypted file.
var VaultMagicPrefix = []byte("filexvlt")
VaultMagicPrefix is the 8-byte magic of packs and index files.
Functions ¶
func CheckVaultIndexHeader ¶ added in v0.54.0
func CheckVaultPackHeader ¶ added in v0.54.0
CheckVaultPackHeader / CheckVaultIndexHeader check the plaintext headers (magic, version, kind, zeros, log2/generation, id) - all the server can.
func ConversionPending ¶ added in v0.48.0
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 ¶
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
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 ¶
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 ¶
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
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 ¶
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
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
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
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
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
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
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
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
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
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
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
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
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
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
VaultIndexPath is "v/idx/0000000000000003.fxi".
func VaultPackPath ¶ added in v0.54.0
VaultPackPath is "v/p/b0/b067….fxp".
func VaultPadme ¶ added in v0.54.0
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 ¶
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 ¶
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 ¶
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 ¶
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
VaultInfo is the key file's `vault` block.
func ParseVaultKeyFile ¶ added in v0.54.0
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.
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.
Source Files
¶
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. |