@filelayer/core 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/CHANGELOG.md +338 -0
  2. package/LICENSE +202 -0
  3. package/MIGRATIONS.md +328 -0
  4. package/NOTICE +37 -0
  5. package/README.md +343 -0
  6. package/SEMANTICS.md +729 -0
  7. package/dist/authz.d.ts +524 -0
  8. package/dist/authz.d.ts.map +1 -0
  9. package/dist/authz.js +889 -0
  10. package/dist/authz.js.map +1 -0
  11. package/dist/db.d.ts +145 -0
  12. package/dist/db.d.ts.map +1 -0
  13. package/dist/db.js +217 -0
  14. package/dist/db.js.map +1 -0
  15. package/dist/delivery.d.ts +293 -0
  16. package/dist/delivery.d.ts.map +1 -0
  17. package/dist/delivery.js +519 -0
  18. package/dist/delivery.js.map +1 -0
  19. package/dist/errors.d.ts +16 -0
  20. package/dist/errors.d.ts.map +1 -0
  21. package/dist/errors.js +21 -0
  22. package/dist/errors.js.map +1 -0
  23. package/dist/filelayer.d.ts +542 -0
  24. package/dist/filelayer.d.ts.map +1 -0
  25. package/dist/filelayer.js +1360 -0
  26. package/dist/filelayer.js.map +1 -0
  27. package/dist/index.d.ts +8 -0
  28. package/dist/index.d.ts.map +1 -0
  29. package/dist/index.js +8 -0
  30. package/dist/index.js.map +1 -0
  31. package/dist/simple.d.ts +297 -0
  32. package/dist/simple.d.ts.map +1 -0
  33. package/dist/simple.js +492 -0
  34. package/dist/simple.js.map +1 -0
  35. package/dist/storage.d.ts +269 -0
  36. package/dist/storage.d.ts.map +1 -0
  37. package/dist/storage.js +700 -0
  38. package/dist/storage.js.map +1 -0
  39. package/dist/store.d.ts +432 -0
  40. package/dist/store.d.ts.map +1 -0
  41. package/dist/store.js +862 -0
  42. package/dist/store.js.map +1 -0
  43. package/package.json +77 -0
  44. package/schema.sql +1190 -0
  45. package/src/authz.ts +1398 -0
  46. package/src/db.ts +271 -0
  47. package/src/delivery.ts +737 -0
  48. package/src/errors.ts +24 -0
  49. package/src/filelayer.ts +1836 -0
  50. package/src/index.ts +7 -0
  51. package/src/simple.ts +666 -0
  52. package/src/storage.ts +917 -0
  53. package/src/store.ts +1072 -0
  54. package/test/delivery.test.ts +0 -0
  55. package/test/group-subjects.test.ts +1072 -0
  56. package/test/helpers.ts +65 -0
  57. package/test/listing.test.ts +689 -0
  58. package/test/local-s3.d.mts +33 -0
  59. package/test/local-s3.mjs +400 -0
  60. package/test/persistence.test.ts +953 -0
  61. package/test/regression.test.ts +619 -0
  62. package/test/s3-live.test.ts +322 -0
  63. package/test/security.test.ts +1652 -0
  64. package/test/semantics.test.ts +888 -0
  65. package/test/storage.test.ts +437 -0
  66. package/test/tiers.test.ts +432 -0
  67. package/test/vault-example.test.ts +302 -0
  68. package/tsconfig.build.json +29 -0
  69. package/tsconfig.json +19 -0
@@ -0,0 +1,293 @@
1
+ /**
2
+ * BYTE DELIVERY -- the library owns the response, not the developer.
3
+ *
4
+ * A security review found three live defects here and correctly identified their
5
+ * common root cause: `read()` and `redeem()` handed back a `Uint8Array` and
6
+ * left everything that happens to those bytes on the way to a browser as the
7
+ * application's problem. Three of the four security-sensitive decisions the
8
+ * library was still leaving to the developer lived in that gap:
9
+ *
10
+ * - no `X-Content-Type-Options: nosniff` / `Content-Disposition` on the
11
+ * authenticated read -> a user-uploaded .html or .svg executes in OUR OWN
12
+ * origin. Stored XSS with full session access, cross-tenant reach.
13
+ * - no `Cache-Control: no-store` on the share download -> a revoked link is
14
+ * replayable from disk cache or an intermediary. This one is worse than it
15
+ * sounds: immediate revocation is the product's headline property, and a
16
+ * cache replay partially defeats it.
17
+ * - the share password in the query string -> the secret AND the password
18
+ * land in access logs, proxy logs, browser history, and the `Referer`
19
+ * header of any outbound link inside the delivered document.
20
+ *
21
+ * The fix is not "document the headers". A decision the developer can forget is
22
+ * a decision they will eventually forget, which is the entire premise of this
23
+ * design. So:
24
+ *
25
+ * 1. `read()` and `redeem()` now return a DELIVERY DESCRIPTOR -- bytes plus
26
+ * the exact headers required to serve them safely. The headers are
27
+ * computed by the library from the file record; there is no argument that
28
+ * turns them off.
29
+ * 2. Framework-agnostic writers are provided (`toResponse` for anything with
30
+ * a WHATWG `Response`, `sendNodeResponse` for `node:http`), so the
31
+ * developer writes one line and cannot write the wrong headers.
32
+ * 3. For the share path the library owns the ROUTE, not just the response,
33
+ * because the password-in-the-URL defect is a routing decision rather than
34
+ * a response decision. `shareDownloadRoute()` reads the password from the
35
+ * request body and REFUSES, loudly, with 400, if a credential appears in
36
+ * the query string. A silent decision has been converted into a noisy one,
37
+ * which by our own definition means it stops being a security-sensitive
38
+ * decision at all.
39
+ *
40
+ * Residual, stated plainly: `delivery.body` is still a public field, so a
41
+ * developer who ignores the helpers and hand-writes `res.end(d.body)` gets the
42
+ * old behaviour. This is "hard to get wrong", not "impossible to get wrong".
43
+ * Making it impossible would mean never exposing the bytes, which would break
44
+ * every non-HTTP consumer (a queue worker, a virus scanner, a thumbnailer).
45
+ * We chose the weaker guarantee deliberately and state it rather than hide it.
46
+ */
47
+ import type { IncomingMessage, ServerResponse } from 'node:http';
48
+ import type { Filelayer } from './filelayer.ts';
49
+ import type { Principal } from './authz.ts';
50
+ export type Disposition = 'attachment' | 'inline';
51
+ export interface DeliverableFile {
52
+ name: string;
53
+ contentType: string;
54
+ sizeBytes?: number | null;
55
+ }
56
+ export interface FileDelivery {
57
+ file: DeliverableFile;
58
+ body: Uint8Array;
59
+ /**
60
+ * Everything that must be on the response. Lowercased, ready to spread into
61
+ * `res.writeHead()` or a `Headers` init.
62
+ */
63
+ headers: Record<string, string>;
64
+ }
65
+ export type DeliveryMode = 'proxy' | 'redirect';
66
+ /**
67
+ * The literal a developer must type to enable redirect delivery.
68
+ *
69
+ * A boolean would be typed once and forgotten. A sentence has to be read to be
70
+ * copied, it appears verbatim in the diff, and it shows up in a grep of the
71
+ * codebase when someone asks "do we ever hand out URLs that outlive a
72
+ * revocation?" -- which is the question this whole mode exists to make
73
+ * answerable.
74
+ */
75
+ export declare const REDIRECT_ACKNOWLEDGEMENT = "I accept a revocation window of up to ttlSeconds on redirected deliveries";
76
+ /**
77
+ * Our ceiling, not the object store's. Five minutes is long enough for a client
78
+ * to follow a redirect on a bad mobile connection and short enough that the
79
+ * residual window is something you can put in a compliance document without
80
+ * flinching.
81
+ */
82
+ export declare const MAX_REDIRECT_TTL_SECONDS = 300;
83
+ export declare const DEFAULT_REDIRECT_TTL_SECONDS = 60;
84
+ export interface RedirectDeliveryConfig {
85
+ /** Must be exactly `REDIRECT_ACKNOWLEDGEMENT`. Checked at runtime too. */
86
+ acknowledgeRevocationWindow: typeof REDIRECT_ACKNOWLEDGEMENT;
87
+ /** Clamped to [1, MAX_REDIRECT_TTL_SECONDS]. */
88
+ ttlSeconds?: number;
89
+ /**
90
+ * 'anonymous-grants-only' (DEFAULT) -- only a delivery authorized by an
91
+ * anonymous grant, i.e. something the customer has deliberately published,
92
+ * may be redirected. This is the setting where the residual window is a
93
+ * window onto an already-public object.
94
+ *
95
+ * 'all-grants' -- link and actor grants too. This is the setting that trades
96
+ * a real revocation window on genuinely private data for zero-proxy
97
+ * delivery. It is not the default and it never will be.
98
+ */
99
+ scope?: 'anonymous-grants-only' | 'all-grants';
100
+ }
101
+ export interface ResolvedRedirectConfig {
102
+ ttlSeconds: number;
103
+ scope: 'anonymous-grants-only' | 'all-grants';
104
+ }
105
+ export declare function resolveRedirectConfig(cfg: RedirectDeliveryConfig): ResolvedRedirectConfig;
106
+ /** A delivery whose bytes flow through this process. */
107
+ export interface ProxyDelivery {
108
+ mode: 'proxy';
109
+ file: DeliverableFile;
110
+ headers: Record<string, string>;
111
+ /** The bytes, as a stream. Nothing here is ever fully resident. */
112
+ body: ReadableStream<Uint8Array>;
113
+ /** Known length, when the store reported one. */
114
+ bytes: number | null;
115
+ }
116
+ /** A delivery answered with a 302 to a short-lived presigned URL. */
117
+ export interface RedirectDelivery {
118
+ mode: 'redirect';
119
+ file: DeliverableFile;
120
+ headers: Record<string, string>;
121
+ status: 302;
122
+ url: string;
123
+ /** When the presigned URL stops working. */
124
+ expiresAt: Date;
125
+ /**
126
+ * The number the compliance document needs: revocation is immediate at
127
+ * decision time, PLUS up to this many seconds of in-flight window.
128
+ */
129
+ revocationWindowSeconds: number;
130
+ }
131
+ export type StreamedDelivery = ProxyDelivery | RedirectDelivery;
132
+ export declare function isActiveContentType(contentType: string): boolean;
133
+ /**
134
+ * A content type we are willing to put on a response.
135
+ *
136
+ * A `content-type` is attacker-controlled: it is whatever the uploader sent.
137
+ * Anything with a CR, an LF or a NUL is a header-injection attempt and is not
138
+ * negotiable; anything that is not a plausible media type is served as bytes.
139
+ */
140
+ export declare function safeContentType(contentType: string, disposition: Disposition): string;
141
+ /**
142
+ * RFC 6266 `Content-Disposition`, with the filename encoded rather than
143
+ * interpolated.
144
+ *
145
+ * NEW FINDING, found while doing this work: the example app wrote
146
+ * `filename="${file.name}"` directly. `file.name` is whatever the uploader
147
+ * sent. A name containing a double quote truncates the header; a name
148
+ * containing CR/LF injects an arbitrary header, including a second
149
+ * `Content-Type` or a `Set-Cookie`. That is a response-splitting bug in the
150
+ * shipped example, and it is not one the comparable integrations have, because
151
+ * none of them interpolate the name unescaped. It is fixed here, once, for
152
+ * every caller.
153
+ */
154
+ export declare function contentDisposition(name: string, disposition: Disposition): string;
155
+ /**
156
+ * The headers every Filelayer byte response carries. There is no option to
157
+ * omit any of them.
158
+ *
159
+ * nosniff - stops content-type sniffing turning a .txt into HTML.
160
+ * Content-Disposition- attachment by default; the browser never renders it.
161
+ * Cache-Control - `private, no-store` + `no-cache` + `must-revalidate`.
162
+ * This is the one that matters most: it is what makes
163
+ * "revocation is immediate" true at the browser and at
164
+ * every intermediary, not just at our origin.
165
+ * Pragma / Expires - the HTTP/1.0 spelling of the same thing, because
166
+ * corporate proxies are real.
167
+ * Referrer-Policy - `no-referrer`. A share link's secret is in the URL. Any
168
+ * outbound link inside a delivered document would leak it
169
+ * in the Referer header. This closes the third vector of
170
+ * the credential-in-the-URL defect, the one that survives
171
+ * moving the password out of the query string.
172
+ * CSP sandbox - defence in depth for the inline case and for any future
173
+ * caller that overrides disposition.
174
+ * X-Frame-Options - the delivered bytes cannot be framed by a third party.
175
+ */
176
+ export declare function deliveryHeaders(file: DeliverableFile, opts?: {
177
+ disposition?: Disposition;
178
+ }): Record<string, string>;
179
+ /** The same headers, minus the body ones, for a JSON error on a delivery path. */
180
+ export declare function errorHeaders(): Record<string, string>;
181
+ /**
182
+ * The headers on a 302 to a presigned URL.
183
+ *
184
+ * `cacheable` is true for an ANONYMOUS grant and only for an anonymous grant.
185
+ * That is the "public/anonymous grants should be able to use a cacheable path"
186
+ * requirement, and the negative half of it is the important half: nothing that
187
+ * was not already public becomes cacheable by a shared cache, ever.
188
+ *
189
+ * The cache lifetime is HALF the presigned URL's TTL. A cached 302 hands a
190
+ * client a URL that is already partly used up, so caching for the full TTL
191
+ * would let a client receive a redirect with milliseconds of life left and see
192
+ * a spurious 403. Half guarantees at least half the TTL remains.
193
+ *
194
+ * The 302 itself carries no bytes, so it carries no content-type protections;
195
+ * those are pinned INTO the presigned URL by the caller (see
196
+ * `Filelayer.readStream`), which is what stops a redirect from being a way to
197
+ * lose them.
198
+ */
199
+ export declare function redirectHeaders(url: string, opts: {
200
+ ttlSeconds: number;
201
+ cacheable: boolean;
202
+ }): Record<string, string>;
203
+ /** WHATWG `Response` -- Workers, Deno, Bun, Next.js route handlers, Hono. */
204
+ export declare function toResponse(delivery: FileDelivery, status?: number): Response;
205
+ /**
206
+ * The streaming/redirect equivalent. One function for both modes, because the
207
+ * developer must not have to branch on the mode -- branching is where the
208
+ * `Cache-Control` gets copied from the wrong arm.
209
+ */
210
+ export declare function toStreamResponse(delivery: StreamedDelivery): Response;
211
+ /** `node:http` / Express. */
212
+ export declare function sendNodeResponse(res: ServerResponse, delivery: FileDelivery, status?: number): void;
213
+ /**
214
+ * `node:http`, streaming. Nothing is buffered: the object's bytes go from the
215
+ * store's socket to the client's socket a chunk at a time.
216
+ *
217
+ * The `content-length` from the record is dropped unless the STORE reported one
218
+ * for this response, for the same reason `sendNodeResponse` recomputes it: a
219
+ * `size_bytes` that disagrees with the object truncates or hangs the response,
220
+ * and on a streamed response the hang is the one you notice in production
221
+ * rather than in a test.
222
+ */
223
+ export declare function sendNodeStream(res: ServerResponse, delivery: StreamedDelivery): Promise<void>;
224
+ export interface ShareRouteOptions {
225
+ /** Path prefix the share links are served under. Must match `baseUrl`. */
226
+ prefix?: string;
227
+ disposition?: Disposition;
228
+ /**
229
+ * 'auto' (default) applies the INSTANCE's redirect policy -- which is "never"
230
+ * unless `redirectDelivery` was configured and acknowledged, so the default
231
+ * is proxying for everybody who has not opted in. 'proxy' forces proxying for
232
+ * this route even on an instance that has opted in.
233
+ *
234
+ * There is no 'redirect' value. A route cannot demand a mode the instance was
235
+ * not configured (and acknowledged) for; the opt-in lives in exactly one
236
+ * place and it is the place with the acknowledgement string next to it.
237
+ */
238
+ mode?: 'proxy' | 'auto';
239
+ }
240
+ /**
241
+ * `GET|POST <prefix>/:secret` -- the entire public share-link download path.
242
+ *
243
+ * The application supplies nothing. Identity is the secret itself, the password
244
+ * is read from the body, the counter is consumed by `redeem()`, and the
245
+ * response headers come from `deliveryHeaders()`. There is no parameter here
246
+ * whose wrong value leaks data.
247
+ *
248
+ * Returns true if it handled the request, so it can be dropped into any router.
249
+ */
250
+ export declare function shareDownloadRoute(fl: Filelayer, opts?: ShareRouteOptions): (req: IncomingMessage, res: ServerResponse) => Promise<boolean>;
251
+ export interface FileRouteOptions {
252
+ prefix?: string;
253
+ disposition?: Disposition;
254
+ /** See `ShareRouteOptions.mode`. */
255
+ mode?: 'proxy' | 'auto';
256
+ /** The application's own authentication. Filelayer never guesses identity. */
257
+ principal: (req: IncomingMessage) => Principal | Promise<Principal>;
258
+ }
259
+ /**
260
+ * `GET <prefix>/:fileId` -- the authenticated read path, headers included.
261
+ *
262
+ * The one thing the application must supply is who the caller is, because that
263
+ * is the one thing Filelayer cannot know. Everything downstream of that -- the
264
+ * decision, the audit event, the status code, and every response header -- is
265
+ * the library's.
266
+ */
267
+ export declare function fileDownloadRoute(fl: Filelayer, opts: FileRouteOptions): (req: IncomingMessage, res: ServerResponse) => Promise<boolean>;
268
+ export interface DeliveryHandlerOptions {
269
+ /** Where authorized file reads are served. Must match `publicUrl()`. */
270
+ filePrefix?: string;
271
+ /** Where share links are served. Must match `baseUrl` + `/d`. */
272
+ sharePrefix?: string;
273
+ disposition?: Disposition;
274
+ /** See `ShareRouteOptions.mode`. Applies to both routes. */
275
+ mode?: 'proxy' | 'auto';
276
+ /**
277
+ * The application's authentication. Omitted means every request to the file
278
+ * path is ANONYMOUS -- which is safe, because an anonymous principal can only
279
+ * reach a file carrying an explicit `anonymous` grant (P1). It is not a
280
+ * "public mode"; there is no public mode.
281
+ */
282
+ principal?: (req: IncomingMessage) => Principal | Promise<Principal>;
283
+ }
284
+ /**
285
+ * The whole byte-delivery surface as one `node:http` request listener.
286
+ *
287
+ * `createServer(deliveryHandler(fl))` is a complete, correct file server: both
288
+ * delivery paths, every security header, the query-string credential refusal,
289
+ * and a 404 for everything else. The developer writes no header and no status
290
+ * code, which means there is no header or status code for them to get wrong.
291
+ */
292
+ export declare function deliveryHandler(fl: Filelayer, opts?: DeliveryHandlerOptions): (req: IncomingMessage, res: ServerResponse) => Promise<void>;
293
+ //# sourceMappingURL=delivery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delivery.d.ts","sourceRoot":"","sources":["../src/delivery.ts"],"names":[],"mappings":"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"}