Documentation
¶
Overview ¶
Package takeout defines the Take-Out of restore Path A: its directory layout, its manifest, and the key-free integrity check both halves of the path run on it (decisions.md, "Restore paths (contract)").
The split of powers is the whole point and is enforced by the package layout:
- The admin half, takeout/remote, runs with S3 access only. Extract has no key parameter of any kind and therefore *cannot* decrypt: the admin moves ciphertext, nothing else (decisions.md #2, #15).
- The user-side half lives in the subpackage takeout/decrypt, which runs on the user's own machine with the Recovery Key, touches no network and needs no OpenCloud (decisions.md, Path A). Keeping it out of the admin's packages is what lets the admin's binary be built without any code that unwraps a Data Key or restores a repository, rather than merely not calling it.
- This package sits under both and links neither an S3 client nor an unwrap path, so each side can read the format without the other's capabilities (phase 10.6).
A Take-Out is a plain directory so it stays readable by hand and by future tooling:
<out>/manifest.json provenance + integrity records (no key material) <out>/recovery.ocbke the RK-wrapped Data Key envelope (ciphertext) <out>/repo/... the Space's kopia repository, copied verbatim
This layout is a long-term promise in the same sense as the key envelope: the decrypt tool is the family's last resort and must keep reading old Take-Outs.
Index ¶
Constants ¶
const ( // ManifestFormat identifies a Take-Out directory. ManifestFormat = "opencloud-backup-takeout" // ManifestVersion is the current Take-Out manifest version. Bump additively; // the decrypt tool must keep reading every version. ManifestVersion = 1 // ManifestFile is the manifest's name inside a Take-Out directory. ManifestFile = "manifest.json" // EnvelopeFile is the RK-wrapped Data Key envelope's name inside a // Take-Out directory. EnvelopeFile = "recovery.ocbke" // RepoDir is the kopia repository's directory inside a Take-Out. RepoDir = "repo" )
Variables ¶
var ( // ErrNoTakeOut means the directory is not (or is no longer) a Take-Out. ErrNoTakeOut = errors.New("takeout: not a take-out directory (manifest.json missing)") // ErrNoEnvelope means the target holds no key envelope for the Space, so a // Take-Out from it could never be decrypted. ErrNoEnvelope = errors.New("takeout: no recovery key envelope found for this space") // ErrCorrupt means the Take-Out failed its integrity check. ErrCorrupt = errors.New("takeout: take-out is damaged") // ErrNewerTakeOut means the manifest declares a format version this build // does not know. The Take-Out is not damaged; a newer decrypt reads it. ErrNewerTakeOut = errors.New("takeout: take-out format is newer than this tool") )
Errors surfaced to operators and users. They stay coarse on purpose: an unwrap failure must not hint at which part of the input was wrong, and no error ever carries key material.
Functions ¶
func Verify ¶
Verify re-reads a Take-Out and checks it against its own manifest. It needs no key: the integrity of the ciphertext is verifiable by whoever holds the copy.
func WriteManifest ¶
WriteManifest serializes the manifest into a Take-Out directory.
Types ¶
type BlobRef ¶
type BlobRef struct {
ID string `json:"id"`
Size int64 `json:"size"`
SHA256 string `json:"sha256"`
}
BlobRef records one copied repository blob. The digest is over ciphertext and reveals nothing about the backed-up data; it exists so a Take-Out can be verified offline before anyone depends on it. It is part of the manifest format, so it is defined here and not by the code that copies the blobs.
type EnvelopeRef ¶
type EnvelopeRef struct {
Version int `json:"version"`
Kind string `json:"kind"`
KDF string `json:"kdf"`
ArgonTime uint32 `json:"argon_time,omitempty"`
ArgonMemoryKiB uint32 `json:"argon_memory_kib,omitempty"`
ArgonLanes uint8 `json:"argon_lanes,omitempty"`
}
EnvelopeRef describes the copied key envelope without revealing anything secret: format version, wrap kind and the (public) KDF parameters.
type Manifest ¶
type Manifest struct {
Format string `json:"format"`
Version int `json:"version"`
SpaceID string `json:"space_id"`
CreatedAt time.Time `json:"created_at"`
Source SourceRef `json:"source"`
RepoDir string `json:"repo_dir"`
EnvelopeRef string `json:"envelope_file,omitempty"`
// Envelope is absent when the Take-Out was forced without one.
Envelope *EnvelopeRef `json:"envelope,omitempty"`
BlobCount int `json:"blob_count"`
TotalBytes int64 `json:"total_bytes"`
// Blobs records every copied repository blob (id, size, ciphertext digest)
// so the copy can be verified offline.
Blobs []BlobRef `json:"blobs"`
}
Manifest is the Take-Out's self-description. It contains no key material.
func ReadManifest ¶
ReadManifest loads the manifest of a Take-Out directory.
func (Manifest) EnvelopePath ¶
EnvelopePath returns the file holding the RK-wrapped Data Key envelope.
type SourceRef ¶
type SourceRef struct {
Endpoint string `json:"endpoint,omitempty"`
Bucket string `json:"bucket,omitempty"`
Prefix string `json:"prefix,omitempty"`
// RepoPrefix and EnvelopeKey are the exact object keys that were copied.
RepoPrefix string `json:"repo_prefix"`
EnvelopeKey string `json:"envelope_key"`
}
SourceRef records where a Take-Out came from. It is provenance only and holds no credentials — a Take-Out is handed to an end user.
Directories
¶
| Path | Synopsis |
|---|---|
|
Package decrypt is the user-side half of Path A: unwrap the Data Key with the Recovery Key and restore a snapshot out of a Take-Out directory.
|
Package decrypt is the user-side half of Path A: unwrap the Data Key with the Recovery Key and restore a snapshot out of a Take-Out directory. |