import type { FilesPlugin } from "../index.js"; /** * A master key (KEK) for {@link encryption}. Either a Web Crypto * {@link CryptoKey} usable for `encrypt`/`decrypt`, or raw AES key bytes of 16, * 24, or 32 bytes (e.g. a secret pulled from an environment variable, imported * for you on first use). */ export type EncryptionKey = CryptoKey | Uint8Array | ArrayBuffer; /** * Generate a fresh 256-bit AES-GCM master key for {@link encryption}. The key * is extractable, so you can `crypto.subtle.exportKey("raw", key)` it to persist * in a secret manager and re-import it (or pass the raw bytes back to * {@link encryption}) later. */ export declare const generateEncryptionKey: () => Promise; /** * Envelope-encrypt object bodies at rest. On `upload` a fresh per-object data * key (DEK) encrypts the body with AES-256-GCM; the master key (KEK) you pass in * encrypts ("wraps") that DEK, and both the wrapped DEK and the IVs ride along in * the object's `metadata`. On `download` the DEK is unwrapped and the body * decrypted — transparently, in the right order, for `upload([...])` / * `download([...])` bulk calls too. * * Provider-agnostic: it uses only the Web Crypto API (no native deps) and the * `metadata` the SDK already round-trips, so it works on any adapter that * supports metadata. * * Place it **last** in the plugin array so it's the innermost layer — anything * that needs to see plaintext (compression, validation, virus scanning) must run * before it: `plugins: [compression(), encryption(key)]`. * * Trade-offs, by design: * - **Buffers the whole body** to compute the GCM tag, so it's unsuitable for * unknown-length streams and resumable uploads. * - **Range downloads throw** — a slice of a GCM ciphertext can't be decrypted. * - **`url()` / `signedUploadUrl()` throw** — presigned URLs bypass the plugin, * handing out ciphertext or letting a client store plaintext. * - **`copy` / `move` just work** — the wrapped DEK travels with the object. * - Objects without this plugin's marker (pre-existing or written elsewhere) * **pass through** on read, so it's safe to enable on a mixed bucket. * * Threat model: this protects **confidentiality at rest** — a party who reads * raw provider bytes (or metadata) learns nothing about the plaintext beyond * its length, and any tampering with the ciphertext, the wrapped DEK, the * IVs, or the declared size fails loudly at decrypt time. It is **not** * integrity binding between an envelope and its key: an attacker with raw * provider *write* access can copy one object's whole envelope (ciphertext + * `fsenc_*` metadata) onto another key, and a later download of that key will * decrypt cleanly to the other object's plaintext. Binding envelopes to keys * (à la KMS encryption context) would break the server-side `copy`/`move` * and key-aliasing plugin compositions above by design — if cross-object * splicing is in your threat model, isolate tenants with separate KEKs and * lock down provider write access. * * @param key the master key — a {@link CryptoKey} or raw 16/24/32 key bytes. * @example * ```ts * import { createFiles } from "files-sdk"; * import { s3 } from "files-sdk/s3"; * import { encryption, generateEncryptionKey } from "files-sdk/encryption"; * * const files = createFiles({ * adapter: s3({ bucket: "uploads" }), * plugins: [encryption(await generateEncryptionKey())], * }); * * await files.upload("secret.txt", "hello"); // stored encrypted * await (await files.download("secret.txt")).text(); // "hello" * ``` */ export declare const encryption: (key: EncryptionKey) => FilesPlugin; //# sourceMappingURL=index.d.ts.map