Documentation
¶
Overview ¶
Package encreplica is a replicate.ReplicaClient that PQ-encrypts every LTX segment with a per-base age key BEFORE it touches durable storage, and decrypts on read — the SOLE at-rest boundary for the replica stream, using the SAME key as the whole-file path (store.OrgKey). This is what makes hanzoai/replicate safe for per-org data: without it the replica stream is plaintext and every base's SQLite pages hit the backend unencrypted.
Why a client and not replicate's built-in age ¶
replicate v0.8.0's Replica.AgeRecipients encrypts the LTX BEFORE the file/s3 client calls ltx.PeekHeader for a timestamp, so those clients reject the ciphertext. Encrypting INSIDE the client — after the plaintext header is read — is both the working path and the correct single-boundary design.
On-storage framing (self-describing, backend-agnostic) ¶
[8 bytes BE plaintext length][8 bytes BE unix-milli timestamp][age ciphertext]
The plaintext length and timestamp are read from the plaintext LTX header at write time and stored in the clear PREFIX so LTXFiles can report an accurate FileInfo (size + CreatedAt) — which replicate's restore requires (it checks Size >= ltx.HeaderSize and drives a resumable reader off Size) — WITHOUT leaking any base data (the LTX body is entirely inside the age ciphertext).
The backend is any path-addressed Blobs store: local-fs for dev/test, S3 or hanzoai/vfs in production (durability/scale, Pillar 3). Encryption is in this client, identical for every backend.
Index ¶
- type Blobs
- type Client
- func (c *Client) DeleteAll(ctx context.Context) error
- func (c *Client) DeleteLTXFiles(ctx context.Context, a []*ltx.FileInfo) error
- func (c *Client) Init(ctx context.Context) error
- func (c *Client) LTXFiles(ctx context.Context, level int, seek ltx.TXID, useMetadata bool) (ltx.FileIterator, error)
- func (c *Client) OpenLTXFile(ctx context.Context, level int, minTXID, maxTXID ltx.TXID, offset, size int64) (io.ReadCloser, error)
- func (c *Client) SetLogger(l *slog.Logger)
- func (c *Client) Type() string
- func (c *Client) WriteLTXFile(ctx context.Context, level int, minTXID, maxTXID ltx.TXID, rd io.Reader) (*ltx.FileInfo, error)
- type LocalBlobs
- func (b *LocalBlobs) Delete(_ context.Context, key string) error
- func (b *LocalBlobs) DeleteAll(_ context.Context) error
- func (b *LocalBlobs) Get(_ context.Context, key string) ([]byte, error)
- func (b *LocalBlobs) List(_ context.Context, prefix string) ([]string, error)
- func (b *LocalBlobs) Put(_ context.Context, key string, data []byte) error
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Blobs ¶
type Blobs interface {
Put(ctx context.Context, key string, data []byte) error
Get(ctx context.Context, key string) ([]byte, error)
List(ctx context.Context, prefix string) ([]string, error)
Delete(ctx context.Context, key string) error
DeleteAll(ctx context.Context) error
}
Blobs is the minimal path-addressed byte store the client persists to. Keys use "/" separators. Get returns an error satisfying errors.Is(err, os.ErrNotExist) when the key is absent. Implementations are goroutine-safe.
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client is the per-base age-encrypting replica client.
func New ¶
New builds an encrypting client over blobs for one base. recipient encrypts, identity decrypts — both are the base's key (store.OrgKey).
func (*Client) DeleteLTXFiles ¶
DeleteLTXFiles removes the named LTX files.
func (*Client) LTXFiles ¶
func (c *Client) LTXFiles(ctx context.Context, level int, seek ltx.TXID, useMetadata bool) (ltx.FileIterator, error)
LTXFiles enumerates stored LTX files at a level, reading the cleartext prefix (size + timestamp) so restore gets accurate FileInfo without decrypting.
type LocalBlobs ¶
type LocalBlobs struct {
// contains filtered or unexported fields
}
LocalBlobs is a directory-backed Blobs for dev/test. Production swaps in an S3- or hanzoai/vfs-backed Blobs; the age encryption boundary lives in Client and is identical for every backend.
func NewLocalBlobs ¶
func NewLocalBlobs(dir string) *LocalBlobs
NewLocalBlobs returns a directory-backed Blobs rooted at dir.
func (*LocalBlobs) Delete ¶
func (b *LocalBlobs) Delete(_ context.Context, key string) error
Delete removes key; a missing key is not an error.
func (*LocalBlobs) DeleteAll ¶
func (b *LocalBlobs) DeleteAll(_ context.Context) error
DeleteAll removes every blob for this base.
func (*LocalBlobs) Get ¶
Get returns key's bytes; a missing key yields an error satisfying errors.Is(err, os.ErrNotExist).