meta

package
v0.6.1 Latest Latest
Warning

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

Go to latest
Published: Apr 23, 2026 License: MIT Imports: 25 Imported by: 0

Documentation

Index

Constants

View Source
const (
	ActionBucketList        = "bucket:list"
	ActionBucketReadMeta    = "bucket:read-meta"
	ActionBucketWriteMeta   = "bucket:write-meta"
	ActionObjectGet         = "object:get"
	ActionObjectPut         = "object:put"
	ActionObjectDelete      = "object:delete"
	ActionObjectList        = "object:list"
	ActionMultipartCreate   = "multipart:create"
	ActionMultipartUpload   = "multipart:upload-part"
	ActionMultipartComplete = "multipart:complete"
	ActionMultipartAbort    = "multipart:abort"
)

Actions

View Source
const MaxBucketsPerAccount = 1000

MaxBucketsPerAccount is the maximum number of buckets a single account may own.

View Source
const MaxMultipartParts = 10000

Variables

View Source
var (
	ErrBucketExists        = errors.New("bucket already exists")
	ErrBucketNotFound      = errors.New("bucket not found")
	ErrBucketNotEmpty      = errors.New("bucket is not empty")
	ErrBucketLimitExceeded = errors.New("account bucket limit exceeded")
)
View Source
var (
	ErrUploadNotFound    = errors.New("upload not found")
	ErrUploadNotActive   = errors.New("upload is not active")
	ErrInvalidPartNumber = errors.New("part number must be between 1 and 10000")
	ErrTooManyParts      = errors.New("upload exceeds maximum number of parts (10000)")
)
View Source
var (
	ErrTokenNotFound   = errors.New("token not found")
	ErrAccountNotFound = errors.New("account not found")
)

AllActions is the full set of actions for admin/full-access tokens.

View Source
var (
	ErrObjectNotFound = errors.New("object not found")
)

Functions

func DeriveKEK

func DeriveKEK(signingSecret string) [32]byte

DeriveKEK derives a 32-byte AES-256 key from signingSecret using HKDF-SHA256.

func ValidBucketName

func ValidBucketName(name string) bool

ValidBucketName returns true if name is a legal S3-style bucket name.

Types

type Account

type Account struct {
	AccountID string    `json:"account_id"`
	Name      string    `json:"name"`
	CreatedAt time.Time `json:"created_at"`
	Status    string    `json:"status"` // "active", "suspended"
}

type Bucket

type Bucket struct {
	ID             string          `json:"id"`
	Name           string          `json:"name"`
	OwnerAccountID string          `json:"owner_account_id"`
	CreatedAt      time.Time       `json:"created_at"`
	Visibility     string          `json:"visibility"` // "private", "public-read"
	PolicyJSON     json.RawMessage `json:"policy_json,omitempty"`
	Status         string          `json:"status"` // "active", "deleting"
}

type DB

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

DB wraps a bbolt database for Jay metadata.

func Open

func Open(path string) (*DB, error)

Open opens or creates the bbolt database at the given path. It creates the parent directory if needed and bootstraps top-level buckets.

func (*DB) AbortMultipartUpload

func (db *DB) AbortMultipartUpload(uploadID string) (*MultipartUpload, error)

AbortMultipartUpload marks the upload as aborted.

func (*DB) AddMultipartPart

func (db *DB) AddMultipartPart(uploadID string, part MultipartPart) error

AddMultipartPart adds or replaces a part in a multipart upload.

func (*DB) Backup

func (db *DB) Backup(w io.Writer) error

Backup writes a consistent hot copy of the bbolt database to w using the existing handle. It runs inside a read transaction, so callers do not need to (and must not) open a second bolt handle on the same file.

func (*DB) BucketStats

func (db *DB) BucketStats(bucketID string) (count int64, totalSize int64, err error)

BucketStats returns the count and total size of active objects in a bucket by reading the maintained counter in O(1). A missing entry returns (0, 0, nil).

func (*DB) CleanupExpiredUploads

func (db *DB) CleanupExpiredUploads(maxAge time.Duration) ([]MultipartUpload, error)

CleanupExpiredUploads removes uploads older than maxAge.

func (*DB) Close

func (db *DB) Close() error

Close closes the underlying bbolt database.

func (*DB) CompleteMultipartUpload

func (db *DB) CompleteMultipartUpload(uploadID string, partNumbers []int) (*MultipartUpload, error)

CompleteMultipartUpload marks the upload as completed and returns the sorted parts.

func (*DB) CreateAccount

func (db *DB) CreateAccount(a *Account) error

CreateAccount creates a new account.

func (*DB) CreateAccountIfNotExists

func (db *DB) CreateAccountIfNotExists(name string) (*Account, bool, error)

CreateAccountIfNotExists looks up an account by Name. If found, returns it with created=false. If not found, creates a new one with a uuid ID.

func (*DB) CreateBucket

func (db *DB) CreateBucket(b *Bucket) error

CreateBucket creates a new bucket. Returns ErrBucketExists if the name is taken.

func (*DB) CreateMultipartUpload

func (db *DB) CreateMultipartUpload(upload *MultipartUpload) error

CreateMultipartUpload starts a new multipart upload.

func (*DB) CreateToken

func (db *DB) CreateToken(t *Token) error

CreateToken stores a new token in bbolt. The caller passes a Token with a plaintext SecretKey; it is encrypted before being persisted.

func (*DB) CreateTokenIfNotExists

func (db *DB) CreateTokenIfNotExists(tokenID, accountID, name, secretHash, plaintextSecret string, allowedActions []string) (*Token, TokenSeedStatus, error)

CreateTokenIfNotExists creates a token with a caller-provided ID. If a token with the same ID already exists, it compares the plaintext secret against the stored bcrypt hash:

  • match -> returns TokenSeedReused (no write)
  • mismatch -> returns TokenSeedMismatch (no write)

Otherwise creates a new token with the supplied hash and returns TokenSeedCreated.

func (*DB) DeleteBucket

func (db *DB) DeleteBucket(name string) error

DeleteBucket removes a bucket by name. Fails if objects exist in it.

func (*DB) DeleteMultipartUpload

func (db *DB) DeleteMultipartUpload(uploadID string) error

DeleteMultipartUpload removes a completed/aborted upload record.

func (*DB) DeleteObjectMeta

func (db *DB) DeleteObjectMeta(bucketID, key string) (*Object, error)

DeleteObjectMeta marks an object as deleted and returns it for physical GC.

func (*DB) DeleteObjectMetaAny

func (db *DB) DeleteObjectMetaAny(bucketID, key string) error

DeleteObjectMetaAny removes object metadata regardless of state.

func (*DB) ForEachObject

func (db *DB) ForEachObject(bucketID string, fn func(Object) error) error

ForEachObject iterates all objects in a bucket (all states) and calls fn for each.

func (*DB) ForEachObjectFrom

func (db *DB) ForEachObjectFrom(bucketID, startKey string, limit int, fn func(Object) error) (lastKey string, err error)

ForEachObjectFrom iterates objects starting from startKey (exclusive), up to limit. Returns the key of the last object visited (for resumption) and any error.

func (*DB) GetAccount

func (db *DB) GetAccount(id string) (*Account, error)

GetAccount retrieves an account by ID.

func (*DB) GetBucket

func (db *DB) GetBucket(name string) (*Bucket, error)

GetBucket retrieves a bucket by name.

func (*DB) GetBucketAndObject

func (db *DB) GetBucketAndObject(bucketName, key string) (*Bucket, *Object, error)

GetBucketAndObject resolves a bucket by name and fetches an active object by key in a single bbolt View transaction. Returns ErrBucketNotFound if the bucket is missing and ErrObjectNotFound if the object is missing or not in the "active" state. When the bucket exists but the object does not, the bucket pointer is still returned alongside ErrObjectNotFound so callers can authorize without issuing a second view transaction.

func (*DB) GetBucketByID

func (db *DB) GetBucketByID(id string) (*Bucket, error)

GetBucketByID retrieves a bucket by its ID.

func (*DB) GetMultipartUpload

func (db *DB) GetMultipartUpload(uploadID string) (*MultipartUpload, error)

GetMultipartUpload retrieves a multipart upload by ID.

func (*DB) GetObjectMeta

func (db *DB) GetObjectMeta(bucketID, key string) (*Object, error)

GetObjectMeta retrieves object metadata by bucket ID and key.

func (*DB) GetObjectMetaAny

func (db *DB) GetObjectMetaAny(bucketID, key string) (*Object, error)

GetObjectMetaAny retrieves object metadata regardless of state.

func (*DB) GetToken

func (db *DB) GetToken(tokenID string) (*Token, error)

GetToken retrieves a token by ID and transparently decrypts SecretKey.

func (*DB) ListBuckets

func (db *DB) ListBuckets(ownerAccountID string) ([]Bucket, error)

ListBuckets returns all buckets, optionally filtered by owner account.

func (*DB) ListMultipartUploads

func (db *DB) ListMultipartUploads(bucketID string) ([]MultipartUpload, error)

ListMultipartUploads returns active uploads for a bucket.

func (*DB) ListObjects

func (db *DB) ListObjects(bucketID, prefix, delimiter, startAfter string, maxKeys int) (*ListObjectsResult, error)

ListObjects lists objects in a bucket with prefix, delimiter, pagination support.

Iteration is split into short read transactions (batchSize keys each) so that long listings do not starve bbolt writers (bbolt allows a single writer and blocks it for the entire lifetime of any overlapping read tx). Between batches the read tx is released, giving writers a chance to commit; the next batch resumes from the last key seen.

Externally observable semantics (returned object set, CommonPrefixes, IsTruncated, NextStartAfter, delimiter handling, prefix matching, maxKeys cap) are preserved bit-identical to the previous single-tx implementation.

func (*DB) ListTokens

func (db *DB) ListTokens(accountID string) ([]Token, error)

ListTokens returns all tokens, optionally filtered by account. SecretHash and SecretKey are zeroed in the response.

func (*DB) MigrateLegacyObject

func (db *DB) MigrateLegacyObject(bucketID, key string) (bool, error)

MigrateLegacyObject rewrites a single object record from the legacy JSON format to the current binary envelope. Returns true if the record was actually rewritten, false if it was already in binary format, missing, or the bucket no longer exists.

Designed to be called from the scrubber after a healthy checksum verify so we only persist re-encoded values for records we have just validated. A single write transaction per object keeps bbolt writer contention low; at the scrub throttle rates (default 10% / 6h) total migration finishes in a handful of cycles without a dedicated batch job.

Does not touch bucket statistics — the record's logical content is unchanged, only its on-disk envelope.

func (*DB) MigrateTokenSecrets

func (db *DB) MigrateTokenSecrets() (migrated int, err error)

MigrateTokenSecrets scans the tokens bucket and re-encrypts any token where SecretKey is stored as plaintext (no "enc:v1:" prefix). Returns the number of tokens migrated. Idempotent — already-encrypted entries are skipped.

func (*DB) Path

func (db *DB) Path() string

Path returns the filesystem path of the database file.

func (*DB) PutObjectMeta

func (db *DB) PutObjectMeta(obj *Object) (*Object, error)

PutObjectMeta creates or updates object metadata within a bbolt write transaction. Returns the previous object (if overwriting) for GC of the old physical file.

func (*DB) QuarantineObject

func (db *DB) QuarantineObject(bucketID, key string) error

QuarantineObject marks an object as quarantined in metadata.

func (*DB) RebuildAllBucketStatsIfMissing

func (db *DB) RebuildAllBucketStatsIfMissing() error

RebuildAllBucketStatsIfMissing iterates every bucket and rebuilds the maintained stats entry only for those whose counter is absent. Existing entries (including zero-valued ones) are left untouched.

func (*DB) RebuildBucketStats

func (db *DB) RebuildBucketStats(bucketID string) error

RebuildBucketStats walks obj:<bucketID> and recomputes the maintained counter from active object records.

func (*DB) RekeyTokens

func (db *DB) RekeyTokens(oldSecret, newSecret string) (int, error)

RekeyTokens decrypts every token secret with oldSecret and re-encrypts it with newSecret. Jay must be stopped before calling this — bbolt enforces an exclusive file lock that will block if another process has the DB open. Returns the number of tokens rekeyed. Idempotent if run again with same args.

func (*DB) RestoreObject

func (db *DB) RestoreObject(bucketID, key string) error

RestoreObject sets a quarantined object's state back to "active".

func (*DB) RevokeToken

func (db *DB) RevokeToken(tokenID string) error

RevokeToken marks a token as revoked.

func (*DB) SetDeletionHook

func (db *DB) SetDeletionHook(fn func())

SetDeletionHook registers a callback invoked after a successful DeleteObjectMeta commit. Safe to call with nil to clear. Single callback per DB instance — a second call overwrites.

func (*DB) SetSigningSecret

func (db *DB) SetSigningSecret(s string)

SetSigningSecret derives and caches the KEK used to encrypt/decrypt Token.SecretKey at rest. Must be called before any token read/write.

func (*DB) SetTokenInvalidateHook

func (db *DB) SetTokenInvalidateHook(fn func(tokenID string))

SetTokenInvalidateHook registers a callback invoked after a token is persisted with a mutated state (revoke/update/delete). The auth layer wires its cache invalidator here so stale cache entries are purged immediately instead of waiting for TTL expiration.

Passing nil clears the hook. Safe to call at any time; invocations are serialized via hookMu.

func (*DB) UpdateBucketPolicy

func (db *DB) UpdateBucketPolicy(name string, policy json.RawMessage) error

UpdateBucketPolicy updates the policy JSON for a bucket.

type ListObjectsResult

type ListObjectsResult struct {
	Objects        []Object
	CommonPrefixes []string
	IsTruncated    bool
	NextStartAfter string
}

ListObjectsResult holds the result of a ListObjects call.

type MultipartPart

type MultipartPart struct {
	PartNumber     int       `json:"part_number"`
	Size           int64     `json:"size"`
	ETag           string    `json:"etag"`
	ChecksumSHA256 string    `json:"checksum_sha256"`
	LocationRef    string    `json:"location_ref"`
	CreatedAt      time.Time `json:"created_at"`
}

MultipartPart represents a single part in a multipart upload.

type MultipartUpload

type MultipartUpload struct {
	UploadID    string          `json:"upload_id"`
	BucketID    string          `json:"bucket_id"`
	ObjectKey   string          `json:"object_key"`
	ContentType string          `json:"content_type,omitempty"`
	InitiatedBy string          `json:"initiated_by"`
	CreatedAt   time.Time       `json:"created_at"`
	State       string          `json:"state"` // "initiated", "completed", "aborted"
	Parts       []MultipartPart `json:"parts,omitempty"`
}

MultipartUpload tracks an in-progress multipart upload.

type Object

type Object struct {
	BucketID        string            `json:"bucket_id"`
	Key             string            `json:"key"`
	ObjectID        string            `json:"object_id"`
	State           string            `json:"state"` // "active", "deleted", "quarantined"
	SizeBytes       int64             `json:"size_bytes"`
	ContentType     string            `json:"content_type"`
	ETag            string            `json:"etag"`
	ChecksumSHA256  string            `json:"checksum_sha256"`
	LocationRef     string            `json:"location_ref"`
	CreatedAt       time.Time         `json:"created_at"`
	UpdatedAt       time.Time         `json:"updated_at"`
	MetadataHeaders map[string]string `json:"metadata_headers,omitempty"`
}

type Token

type Token struct {
	TokenID        string     `json:"token_id"`
	AccountID      string     `json:"account_id"`
	Name           string     `json:"name"`
	SecretHash     string     `json:"secret_hash"`
	SecretKey      string     `json:"secret_key,omitempty"` // plaintext secret for SigV4 HMAC computation
	AllowedActions []string   `json:"allowed_actions"`
	BucketScope    []string   `json:"bucket_scope,omitempty"`
	PrefixScope    []string   `json:"prefix_scope,omitempty"`
	CreatedAt      time.Time  `json:"created_at"`
	ExpiresAt      *time.Time `json:"expires_at,omitempty"`
	Status         string     `json:"status"` // "active", "revoked"
}

type TokenSeedStatus

type TokenSeedStatus int

TokenSeedStatus describes the outcome of CreateTokenIfNotExists.

const (
	TokenSeedCreated  TokenSeedStatus = iota // brand new token persisted
	TokenSeedReused                          // token existed with matching secret hash
	TokenSeedMismatch                        // token existed but secret hash didn't match
)

Jump to

Keyboard shortcuts

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