pbs

package
v0.4.0 Latest Latest
Warning

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

Go to latest
Published: Oct 16, 2026 License: AGPL-3.0 Imports: 39 Imported by: 0

Documentation

Overview

Package pbs is a Proxmox Backup Server client for creating and reading backups.

It supports API-token and username/password (ticket) authentication, SHA-256 certificate fingerprint pinning, and the HTTP/2 backup protocol (proxmox-backup-protocol-v1): dynamic indexes, content-defined chunk upload with zstd compression and deduplication against the previous snapshot, blobs, manifest and finish. Chunk uploads run on a parallel pipeline while index order is preserved by sequence numbers.

Client-side encryption (Config.Crypt) is compatible with proxmox-backup-client: AES-256-GCM chunks and blobs, keyed chunk digests so deduplication works per key, signed manifests, proxmox key.json files (LoadKeyFile/CreateKeyFile) and RSA master-key wrapping.

ListSnapshots and StartReader (proxmox-backup-reader-protocol-v1) read snapshots back, verified and decrypted.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrAuth reports HTTP 401 or 403.
	ErrAuth = errors.New("pbs: authentication failed")

	// ErrNotFound reports an unknown datastore, snapshot or file.
	ErrNotFound = errors.New("pbs: not found")

	// ErrFingerprint reports a certificate that does not match
	// Config.Fingerprint.
	ErrFingerprint = errors.New("pbs: certificate fingerprint mismatch")
)
View Source
var ErrNoPrevious = errors.New("pbs: no previous index")

ErrNoPrevious reports that the server has no previous snapshot index for the requested archive.

Functions

func CreateKeyFile added in v0.2.0

func CreateKeyFile(key [32]byte, passphrase []byte, kdf KDF, hint string) ([]byte, error)

CreateKeyFile serializes key as a proxmox-compatible key file. With KDFScrypt or KDFPBKDF2 the key is sealed under the passphrase (at least 5 bytes, matching proxmox-backup); with KDFNone the passphrase must be nil and the key is stored in plain — write the file with mode 0600.

func DecodeBlob added in v0.4.0

func DecodeBlob(framed []byte, c *CryptConfig) ([]byte, error)

DecodeBlob decodes a framed blob or chunk. c may be nil for unencrypted frames.

func GenerateEncryptionKey added in v0.2.0

func GenerateEncryptionKey() ([32]byte, error)

GenerateEncryptionKey returns a fresh random 32-byte encryption key.

func LoadMasterKey added in v0.4.0

func LoadMasterKey(pemData, passphrase []byte) (*rsa.PrivateKey, error)

LoadMasterKey parses an RSA master private key in PEM form: the passphrase-protected PKCS#8 file "proxmox-backup-client key create-master-key" writes (PBES2 with PBKDF2 and AES-CBC), or an unencrypted "PRIVATE KEY" / "RSA PRIVATE KEY" block, for which passphrase must be nil.

func SplitIndexNames

func SplitIndexNames(name string) (meta, payload string)

SplitIndexNames derives the dynamic index names of a v2 split archive from an archive name in any customary spelling ("root", "root.pxar", "root.pxar.didx", or one of the split names): "<base>.mpxar.didx" for the metadata stream and "<base>.ppxar.didx" for the payload stream. An empty name maps to base "backup".

Types

type Auth

type Auth interface {
	// contains filtered or unexported methods
}

Auth selects an authentication method. Implementations are sealed: TokenAuth, PasswordAuth and TicketAuth.

type BackupSession

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

BackupSession is one open backup-protocol connection: one session writes exactly one snapshot. It is bound to a single HTTP/2 connection — a connection loss fails the session rather than silently opening a second one (a defect in the reference client; ARCHITECTURE.md §12).

Index and blob methods are safe for concurrent use; Finish and Abort are not, and must be called once, after all uploads completed.

func (*BackupSession) Abort

func (s *BackupSession) Abort() error

Abort closes the connection without committing; the server discards the unfinished snapshot.

func (*BackupSession) AppendDynamicIndex

func (s *BackupSession) AppendDynamicIndex(ctx context.Context, wid uint64, digests []string, offsets []uint64) error

AppendDynamicIndex registers uploaded chunks with an index: digests are lowercase hex, offsets the chunk START positions within the archive stream. At most 128 chunks per call (the server rejects oversized requests); the Upload* helpers batch accordingly.

func (*BackupSession) ChunkDigest added in v0.2.0

func (s *BackupSession) ChunkDigest(plain []byte) [32]byte

ChunkDigest returns the chunk digest for plain under this session's crypt mode: SHA-256 of the plaintext normally and in sign-only mode, the keyed digest SHA256(plain ‖ id_key) in encrypt mode. Digests — never ciphertext — drive deduplication, so identical plaintext under the same key deduplicates across backups.

func (*BackupSession) CloseDynamicIndex

func (s *BackupSession) CloseDynamicIndex(ctx context.Context, wid uint64, csum [32]byte, size, chunkCount uint64) error

CloseDynamicIndex finishes an index: csum is the index checksum (sha256 over per-chunk LE end-offset ‖ digest), size the total byte count, chunkCount the number of index entries.

func (*BackupSession) CreateDynamicIndex

func (s *BackupSession) CreateDynamicIndex(ctx context.Context, name string) (uint64, error)

CreateDynamicIndex opens a dynamic-index writer for the named archive (e.g. "root.pxar.didx") and returns its writer id. Parameters are sent both as a query string and as a JSON body: the real server requires the body, pmoxs3backuproxy reads only the query, and each ignores the other's encoding.

func (*BackupSession) DownloadPrevious

func (s *BackupSession) DownloadPrevious(ctx context.Context, archiveName string) ([]byte, error)

DownloadPrevious fetches the previous snapshot's raw index for the named archive, for chunk deduplication. Returns ErrNoPrevious when this is the first backup. Digests of a well-formed index are registered with the session's dedup set as a side effect (the server registers them as known to the session at the same time).

func (*BackupSession) Finish

func (s *BackupSession) Finish(ctx context.Context) error

Finish uploads the manifest, commits the snapshot and closes the connection. With a key configured the manifest is signed (and carries the key fingerprint); with a master key, the wrapped encryption key is uploaded alongside so its holder can recover the data. The session is unusable afterwards.

func (*BackupSession) PreviousIndex added in v0.3.0

func (s *BackupSession) PreviousIndex(ctx context.Context, archiveName string) ([]IndexEntry, error)

PreviousIndex downloads and parses the previous snapshot's index for the named archive (registering its chunks as known, like DownloadPrevious). Metadata change detection needs the payload index's chunk layout before generation starts, and the metadata index to validate a local copy of the previous metadata stream.

func (*BackupSession) Ref

func (s *BackupSession) Ref() SnapshotRef

Ref returns the snapshot identity this session writes, with all defaults resolved (the exact values a restore later addresses).

func (*BackupSession) UploadBlob

func (s *BackupSession) UploadBlob(ctx context.Context, enc *BlobEncoder, filename string, data []byte, compress bool) error

UploadBlob frames data as a blob (optionally zstd-compressed, encrypted when the session has a key in encrypt mode), uploads it under filename (e.g. "pct.conf.blob"), and records it in the manifest with the size and sha256 of the encoded blob as stored by the server (matching the reference client — the restore path verifies both against the stored file).

func (*BackupSession) UploadCatalog

func (s *BackupSession) UploadCatalog(ctx context.Context, r io.Reader) (UploadStats, error)

UploadCatalog streams a .pcat1 catalog into the snapshot's "catalog.pcat1.didx" index, making it browsable in the PBS UI.

func (*BackupSession) UploadDynamicChunk

func (s *BackupSession) UploadDynamicChunk(ctx context.Context, enc *BlobEncoder, wid uint64, digest [32]byte, plain []byte) error

UploadDynamicChunk uploads one content chunk (plaintext; framing, compression and encryption are handled here) for the given index writer. digest must be ChunkDigest(plain).

func (*BackupSession) UploadPXARv1

func (s *BackupSession) UploadPXARv1(ctx context.Context, name string, r io.Reader) (UploadStats, error)

UploadPXARv1 streams a pxar v1 archive into a dynamic index: the stream is content-defined-chunked, chunks are hashed, deduplicated, compressed and uploaded by Config.Workers concurrent workers, and the index is appended strictly in stream order and closed with its checksum. Deduplication is seeded from the previous snapshot's index automatically and shared across all uploads of the session. name may be "root.pxar" or "root.pxar.didx".

func (*BackupSession) UploadPXARv2

func (s *BackupSession) UploadPXARv2(ctx context.Context, name string, meta, payload io.Reader) (metaStats, payloadStats UploadStats, err error)

UploadPXARv2 streams a split v2 archive — metadata stream and payload stream — into its two dynamic indexes ("<base>.mpxar.didx" and "<base>.ppxar.didx"; see SplitIndexNames). The two streams are uploaded concurrently: generators couple the streams (metadata emission can await payload dispatch), so consuming them sequentially could deadlock. Deduplication is shared with all other uploads of the session.

A payload stream produced with metadata change detection is framed (see package reuse): its injected chunks — previous-snapshot chunks the generator did not re-read — are appended to the index without upload. They must be known to the session, which DownloadPrevious of the payload index guarantees when the previous snapshot is the one the generator compared against.

func (*BackupSession) UploadStream added in v0.4.0

func (s *BackupSession) UploadStream(ctx context.Context, name string, r io.Reader) (UploadStats, error)

UploadStream is UploadPXARv1 for any byte stream. The official client restores such an index only to stdout: "proxmox-backup-client restore <snapshot> NAME.didx -".

type BlobEncoder

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

BlobEncoder frames chunk and blob payloads. It owns a reusable zstd encoder (allocating one per chunk is a reference-client mistake worth not repeating); use one BlobEncoder per goroutine.

func NewBlobEncoder

func NewBlobEncoder() *BlobEncoder

NewBlobEncoder returns an encoder with zstd at the default level (what PBS clients use).

func (*BlobEncoder) Encode

func (e *BlobEncoder) Encode(plain []byte, compress bool) []byte

Encode frames plain as a blob. With compress set it compresses first and keeps the smaller representation — the decision is made before framing, so nothing is framed twice. The returned slice is reused by the next Encode call on this encoder.

type Client

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

Client holds connection settings and (for password auth) the cached ticket. Safe for concurrent use.

func NewClient

func NewClient(cfg Config) (*Client, error)

NewClient validates the configuration. No connection is made until the first request. Auth and Datastore are checked by the calls that need them, so a client without them can still log in (Login, OpenIDLogin), list realms, or list datastores (with Auth).

func (*Client) ListDatastores added in v0.4.0

func (c *Client) ListDatastores(ctx context.Context) ([]Datastore, error)

ListDatastores returns the datastores the credentials can access, sorted by name. Config.Datastore is not used.

func (*Client) ListGroups added in v0.4.0

func (c *Client) ListGroups(ctx context.Context) ([]Group, error)

ListGroups returns the backup groups in Config.Namespace of Config.Datastore, sorted by type and id.

func (*Client) ListNamespaces added in v0.4.0

func (c *Client) ListNamespaces(ctx context.Context) ([]Namespace, error)

ListNamespaces returns the direct child namespaces of Config.Namespace in Config.Datastore, sorted by path.

func (*Client) ListSnapshots added in v0.4.0

func (c *Client) ListSnapshots(ctx context.Context, backupType, backupID string) ([]SnapshotInfo, error)

ListSnapshots returns one backup group's snapshots, newest first. backupType "" means "host". The token needs Datastore.Audit or Datastore.Backup.

func (*Client) Login added in v0.4.0

func (c *Client) Login(ctx context.Context, userID, password string) (*LoginResult, error)

Login logs in with a user id ("user@realm") and password. Users with a second factor get a TFAChallenge to answer with Respond.

func (*Client) OpenIDAuthURL added in v0.4.0

func (c *Client) OpenIDAuthURL(ctx context.Context, realm, redirectURL string) (string, error)

OpenIDAuthURL starts an OpenID Connect login on realm: the user opens the returned URL, and the identity provider redirects to redirectURL with "state" and "code" query parameters for OpenIDLogin. redirectURL must be allowed by the provider.

func (*Client) OpenIDLogin added in v0.4.0

func (c *Client) OpenIDLogin(ctx context.Context, state, code, redirectURL string) (TicketAuth, error)

OpenIDLogin completes an OpenID Connect login with the redirect's state and code; redirectURL is the one given to OpenIDAuthURL.

func (*Client) Realms added in v0.4.0

func (c *Client) Realms(ctx context.Context) ([]Realm, error)

Realms lists the server's authentication realms. No credentials needed.

func (*Client) StartBackup

func (c *Client) StartBackup(ctx context.Context, ref SnapshotRef) (*BackupSession, error)

StartBackup opens a backup session: it dials the server, upgrades the connection to the backup protocol, and speaks HTTP/2 over it from then on.

func (*Client) StartReader added in v0.4.0

func (c *Client) StartReader(ctx context.Context, ref SnapshotRef) (*ReaderSession, error)

StartReader opens a reader session on one snapshot. ref.ID and ref.Time are required. Config.DialSession is not used: that dialer cannot tell which protocol to upgrade to.

type Config

type Config struct {
	// BaseURL is the server address, e.g. "https://pbs.example.com:8007".
	// The scheme must be https; the port defaults to 8007.
	BaseURL string

	// Auth selects the authentication method: TokenAuth, PasswordAuth or
	// TicketAuth.
	Auth Auth

	// Fingerprint pins the server certificate: the SHA-256 of its DER
	// encoding as colon-separated hex (case-insensitive). When set, it is
	// always enforced and replaces chain verification. When empty, standard
	// chain verification applies.
	Fingerprint string

	// InsecureSkipAll disables certificate verification entirely. For lab
	// use only; Fingerprint is the supported way to trust a self-signed
	// server.
	InsecureSkipAll bool

	// Datastore is the target datastore's name on the server.
	Datastore string

	// Namespace within the datastore; empty for the root namespace.
	Namespace string

	// Workers is the number of concurrent chunk uploads, and of chunk
	// downloads per OpenDynamicIndex stream; 0 = 4.
	Workers int

	// ChunkSizeAvg is the content-defined chunking target; 0 = 4 MiB.
	// Must be a power of two.
	ChunkSizeAvg uint64

	// Crypt enables client-side encryption (or manifest signing) with the
	// given key; nil uploads plaintext with crypt-mode "none". Treated as
	// read-only after NewClient.
	Crypt *CryptConfig

	// DialSession, when set, replaces the built-in TLS dial and HTTP/1.1
	// protocol upgrade: StartBackup calls it once per session and expects a
	// connection on which the backup protocol has already been negotiated —
	// the peer answered 101 Switching Protocols and now speaks HTTP/2. Use it
	// to run the session through a proxy or tunnel that performs the upgrade
	// (and holds the PBS credentials) on the client's behalf. With
	// DialSession set, BaseURL, Auth and Datastore are optional and the TLS
	// settings (Fingerprint, InsecureSkipAll) do not apply to the session.
	// StartReader does not use it: the dialer cannot tell which protocol to
	// upgrade to.
	DialSession func(ctx context.Context, ref SnapshotRef) (net.Conn, error)

	// OnUploadProgress, when set, is called by the upload pipeline as chunks
	// are committed to an index, in stream order (Stats.Size grows
	// monotonically per index), and once more with done=true after the index
	// closed. Called from the uploading goroutine; keep it fast. A v2 split
	// upload runs two indexes concurrently, so calls (for different archive
	// names) can arrive from two goroutines at once — synchronize any shared
	// state.
	OnUploadProgress func(archiveName string, stats UploadStats, done bool)
}

Config configures a Client.

type CryptConfig added in v0.2.0

type CryptConfig struct {
	// Mode is CryptModeEncrypt or CryptModeSignOnly. Empty defaults to
	// CryptModeEncrypt, matching proxmox-backup-client's default when a key
	// is present.
	Mode CryptMode

	// Key is the raw 32-byte encryption key, e.g. from LoadKeyFile or
	// GenerateEncryptionKey. An all-zero key is rejected by NewClient.
	Key [32]byte

	// KeyCreated is the key's creation time, preserved in the master-key
	// wrapped copy uploaded with each backup. LoadKeyFile fills it from the
	// key file; zero means the wrap time is used.
	KeyCreated time.Time

	// MasterPublicKey, when set, is an RSA public key in PEM form ("PUBLIC
	// KEY" or "RSA PUBLIC KEY" block). Each backup then includes the
	// encryption key wrapped with it ("rsa-encrypted.key.blob"), so the
	// master key holder can recover the data if the encryption key is lost.
	// Requires Mode == CryptModeEncrypt.
	MasterPublicKey []byte
}

CryptConfig configures client-side encryption, compatible with proxmox-backup-client: the same key file yields the same chunk digests, so deduplication works across clients. Set it on Config.Crypt; a nil Config.Crypt uploads plaintext with crypt-mode "none". The struct is treated as read-only after NewClient.

type CryptMode added in v0.2.0

type CryptMode string

CryptMode selects how uploaded data relates to the encryption key.

const (
	// CryptModeEncrypt encrypts every chunk and blob with AES-256-GCM and
	// signs the manifest.
	CryptModeEncrypt CryptMode = "encrypt"
	// CryptModeSignOnly uploads plaintext but signs the manifest, proving it
	// was written by a holder of the key.
	CryptModeSignOnly CryptMode = "sign-only"
)

type Datastore added in v0.4.0

type Datastore struct {
	Name    string
	Comment string
}

Datastore is one entry of ListDatastores.

type Group added in v0.4.0

type Group struct {
	Type       string
	ID         string
	LastBackup time.Time
	Count      int
	Owner      string
	Comment    string
	Files      []string // of the newest snapshot
}

Group is one entry of ListGroups: a backup type and id.

type IndexEntry

type IndexEntry struct {
	EndOffset uint64
	Digest    [32]byte
}

IndexEntry is one dynamic-index record.

func ParseDynamicIndex

func ParseDynamicIndex(data []byte) ([]IndexEntry, error)

ParseDynamicIndex decodes a raw .didx file (as returned by DownloadPrevious) with full length validation — the reference client panics on short bodies and mis-slices trailing bytes.

type IndexFile added in v0.4.0

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

IndexFile is random access to the content of a dynamic index: an io.ReaderAt over the plain, verified byte stream. Chunks are fetched when a read first touches them and kept in a small LRU cache; concurrent reads of the same chunk share one download. Sequential reads are detected and read ahead, like the kernel's page cache does: each consecutive step to the next chunk widens the window by one, up to Config.Workers chunks fetched in the background, and any jump resets it. A long sequential read (a v2 payload during a full restore) keeps Workers downloads in flight, while lookups and small files fetch little beyond what they read. It is safe for concurrent use.

Each chunk is checked like OpenDynamicIndex checks it (size and digest); a failure is returned from ReadAt, never io.EOF.

func (*IndexFile) ReadAt added in v0.4.0

func (f *IndexFile) ReadAt(p []byte, off int64) (int, error)

ReadAt implements io.ReaderAt.

func (*IndexFile) Size added in v0.4.0

func (f *IndexFile) Size() int64

Size returns the content size in bytes.

type KDF added in v0.2.0

type KDF string

KDF selects how a key file's passphrase protects the key.

const (
	// KDFScrypt protects the key with scrypt (n=65536, r=8, p=1), the
	// proxmox-backup-client default.
	KDFScrypt KDF = "scrypt"
	// KDFPBKDF2 protects the key with PBKDF2-HMAC-SHA256 (65535 iterations).
	KDFPBKDF2 KDF = "pbkdf2"
	// KDFNone stores the key in plain; the file itself is the secret.
	KDFNone KDF = "none"
)

type KeyInfo added in v0.2.0

type KeyInfo struct {
	Key         [32]byte
	Created     time.Time
	Modified    time.Time
	Hint        string // passphrase hint, if the file has one
	Fingerprint string // colon-separated hex, recomputed from Key
}

KeyInfo is an encryption key loaded from a key file, with its metadata.

func LoadKeyFile added in v0.2.0

func LoadKeyFile(data []byte, passphrase []byte) (KeyInfo, error)

LoadKeyFile parses a proxmox-backup key file ("key.json") and returns the key. passphrase unlocks scrypt/PBKDF2-protected files and must be nil for unprotected ones. The stored fingerprint, when present, is verified against the key.

func RecoverKey added in v0.4.0

func RecoverKey(wrapped []byte, master *rsa.PrivateKey) (KeyInfo, error)

RecoverKey decrypts a master-key-wrapped encryption key: the content of a snapshot's "rsa-encrypted.key.blob", as DownloadBlob returns it.

func (KeyInfo) CryptConfig added in v0.2.0

func (k KeyInfo) CryptConfig(mode CryptMode) *CryptConfig

CryptConfig returns a config using this key in the given mode, preserving the key file's creation time for master-key wrapping.

type LoginResult added in v0.4.0

type LoginResult struct {
	Auth TicketAuth
	TFA  *TFAChallenge
}

LoginResult is the outcome of Login: either Auth is set, or TFA asks for a second factor.

type ManifestFile added in v0.4.0

type ManifestFile struct {
	CryptMode string `json:"crypt-mode"` // "none", "encrypt" or "sign-only"
	Csum      string `json:"csum"`       // stored blob's SHA-256, or the index checksum
	Filename  string `json:"filename"`
	Size      uint64 `json:"size"` // stored blob size, or the plain archive size
}

ManifestFile is one file entry of a snapshot manifest.

type Namespace added in v0.4.0

type Namespace struct {
	Path    string // full path, "a/b"
	Comment string
}

Namespace is one entry of ListNamespaces.

type PasswordAuth

type PasswordAuth struct {
	Username string // without realm
	Realm    string // e.g. "pam" or "pbs"
	Password string
}

PasswordAuth authenticates with username and password via /api2/json/access/ticket. Tickets are cached and renewed automatically.

type ReaderSession added in v0.4.0

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

ReaderSession reads one committed snapshot. Its methods are safe for concurrent use; Close must come last.

func (*ReaderSession) Close added in v0.4.0

func (r *ReaderSession) Close() error

Close closes the connection; open index readers fail afterwards.

func (*ReaderSession) DownloadBlob added in v0.4.0

func (r *ReaderSession) DownloadBlob(ctx context.Context, name string) ([]byte, error)

DownloadBlob returns the decoded content of a .blob file, verified against the manifest. ".blob" is appended to name when missing.

func (*ReaderSession) Manifest added in v0.4.0

func (r *ReaderSession) Manifest(ctx context.Context) (SnapshotManifest, error)

Manifest returns the snapshot manifest. With Config.Crypt set, a manifest written with another key or with a bad signature is refused.

func (*ReaderSession) OpenDynamicIndex added in v0.4.0

func (r *ReaderSession) OpenDynamicIndex(ctx context.Context, name string) (io.ReadCloser, error)

OpenDynamicIndex streams the content of a .didx file, verified against the manifest. ".didx" is appended to name when missing. A verification failure is returned from Read, never io.EOF. ctx bounds the whole stream; Close releases its goroutines.

func (*ReaderSession) OpenDynamicIndexAt added in v0.4.0

func (r *ReaderSession) OpenDynamicIndexAt(ctx context.Context, name string) (*IndexFile, error)

OpenDynamicIndexAt opens a .didx file for random access, verified against the manifest. ".didx" is appended to name when missing. ctx bounds every later read.

func (*ReaderSession) RecoverKey added in v0.4.0

func (r *ReaderSession) RecoverKey(ctx context.Context, master *rsa.PrivateKey) (KeyInfo, error)

RecoverKey recovers the snapshot's encryption key with the master private key, from the wrapped copy a backup with Crypt.MasterPublicKey stores. The session's client needs no key, so nothing read is verified yet: open a new client with the recovered key (info.CryptConfig) to read the snapshot. Its manifest signature, which covers the wrapped key, then proves the recovered key belongs to the snapshot.

func (*ReaderSession) Ref added in v0.4.0

func (r *ReaderSession) Ref() SnapshotRef

Ref returns the snapshot this session reads.

type Realm added in v0.4.0

type Realm struct {
	Realm   string // e.g. "pam", "pbs", or an OpenID/LDAP realm's name
	Type    string // "pam", "pbs", "openid", "ldap", "ad"
	Comment string
}

Realm is one authentication realm of the server.

type SnapshotInfo added in v0.4.0

type SnapshotInfo struct {
	Ref       SnapshotRef
	Size      uint64 // as the server reports it
	Files     []string
	Protected bool
	// Encrypted reports that at least one file has crypt-mode "encrypt":
	// reading it needs Config.Crypt (or a master key).
	Encrypted bool
	Comment   string // the first line of the snapshot notes
}

SnapshotInfo is one entry of ListSnapshots.

type SnapshotManifest added in v0.4.0

type SnapshotManifest struct {
	Ref   SnapshotRef
	Files []ManifestFile
}

SnapshotManifest is a snapshot's decoded index.json.blob.

type SnapshotRef

type SnapshotRef struct {
	Type string    // "host", "vm" or "ct"; default "host"
	ID   string    // default: os.Hostname()
	Time time.Time // default: now; fixed for the whole session
	// Notes is the snapshot comment PBS shows in its UI and API (the
	// manifest's unprotected "notes" field, same place the server's notes
	// endpoint writes). Optional; outside the manifest signature.
	Notes string
}

SnapshotRef identifies the snapshot a backup session writes.

type TFAChallenge added in v0.4.0

type TFAChallenge struct {

	// Types lists the second factors the user has configured and the server
	// offers, sorted: "totp", "recovery", "webauthn", "yubico", ….
	Types []string
	// contains filtered or unexported fields
}

TFAChallenge is a pending second-factor login.

func (*TFAChallenge) Respond added in v0.4.0

func (ch *TFAChallenge) Respond(ctx context.Context, kind, code string) (TicketAuth, error)

Respond answers the challenge with a second factor: kind is one of Types ("totp", "recovery", …) and code the user's answer.

type TicketAuth added in v0.4.0

type TicketAuth struct {
	Username string
	Ticket   string
	CSRF     string
}

TicketAuth authenticates with a ticket obtained earlier, from Login (with a second factor), OpenIDLogin, or any other PBS login. Username is the full user id ("user@realm"), needed to renew the ticket, which happens automatically before it expires.

type TokenAuth

type TokenAuth struct {
	AuthID string
	Secret string
}

TokenAuth authenticates with an API token: AuthID is "user@realm!tokenname", Secret the token secret. Sent as "Authorization: PBSAPIToken=<authid>:<secret>" on every request.

type UploadStats

type UploadStats struct {
	Size         uint64 // total bytes indexed
	ChunkCount   uint64
	NewChunks    uint64 // uploaded to the server
	NewBytes     uint64 // plain size of the chunks uploaded to the server
	ReusedChunks uint64 // deduplicated (previous snapshot or repeats in this stream)
	// Entries is the index as closed on the server (end offset + digest per
	// chunk); callers keeping a local copy of a v2 metadata stream for change
	// detection store it to validate the copy against the next snapshot's
	// previous index.
	Entries []IndexEntry
}

UploadStats summarizes one index upload.

Directories

Path Synopsis
Package pbstest provides an in-process mock PBS server for testing code built on package pbs: a TLS listener that answers the regular API's ticket login and snapshot listing, performs the backup- and reader-protocol 101 upgrades, then serves the session endpoints over HTTP/2 — verifying chunk framing (magic, CRC, compression, digest) as the real server would, and recording everything for assertions.
Package pbstest provides an in-process mock PBS server for testing code built on package pbs: a TLS listener that answers the regular API's ticket login and snapshot listing, performs the backup- and reader-protocol 101 upgrades, then serves the session endpoints over HTTP/2 — verifying chunk framing (magic, CRC, compression, digest) as the real server would, and recording everything for assertions.

Jump to

Keyboard shortcuts

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