cursedbelt-server 3.0.1 → 4.1.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 (84) hide show
  1. package/dist/server/auth/jwt.d.ts +1 -1
  2. package/dist/server/auth/jwt.js +2 -2
  3. package/dist/server/master-lock/accountsPage.d.ts +39 -0
  4. package/dist/server/master-lock/accountsPage.js +455 -0
  5. package/dist/server/master-lock/guard.js +39 -1
  6. package/dist/server/master-lock/index.d.ts +10 -2
  7. package/dist/server/master-lock/index.js +10 -2
  8. package/dist/server/master-lock/lockPage.d.ts +9 -0
  9. package/dist/server/master-lock/lockPage.js +44 -36
  10. package/dist/server/media-bun/streaming.d.ts +0 -1
  11. package/dist/server/media-bun/streaming.js +1 -1
  12. package/dist/server/storage/binaryStore.d.ts +385 -0
  13. package/dist/server/storage/binaryStore.js +739 -0
  14. package/dist/server/storage/binaryStoreFake.d.ts +56 -0
  15. package/dist/server/storage/binaryStoreFake.js +63 -0
  16. package/dist/server/storage/files/catalogue.d.ts +2 -2
  17. package/dist/server/storage/files/catalogue.js +18 -208
  18. package/dist/server/storage/files/fileRoutes.d.ts +2 -20
  19. package/dist/server/storage/files/fileRoutes.js +1 -74
  20. package/dist/server/storage/files/index.d.ts +1 -1
  21. package/dist/server/storage/files/index.js +1 -1
  22. package/dist/server/storage/files/migrations.js +9 -6
  23. package/dist/server/storage/files/stack.d.ts +6 -31
  24. package/dist/server/storage/files/stack.js +0 -27
  25. package/dist/server/storage/files/types.d.ts +10 -60
  26. package/dist/server/storage/files/types.js +9 -0
  27. package/dist/server/storage/index.d.ts +2 -2
  28. package/dist/server/storage/index.js +1 -1
  29. package/dist/server/storage/mountMediaRoutes.d.ts +1 -4
  30. package/dist/server/storage/types.d.ts +0 -9
  31. package/dist/server/storage/types.js +2 -9
  32. package/package.json +14 -2
  33. package/src/leafSubpathsImportNothing.spec.ts +30 -4
  34. package/src/server/auth/jwt.ts +2 -2
  35. package/src/server/master-lock/accountsPage.spec.ts +231 -0
  36. package/src/server/master-lock/accountsPage.ts +465 -0
  37. package/src/server/master-lock/guard.ts +44 -1
  38. package/src/server/master-lock/index.ts +22 -2
  39. package/src/server/master-lock/lockPage.spec.ts +20 -16
  40. package/src/server/master-lock/lockPage.ts +45 -36
  41. package/src/server/media-bun/streaming.ts +0 -6
  42. package/src/server/storage/binaryStore.spec.ts +908 -0
  43. package/src/server/storage/binaryStore.ts +1049 -0
  44. package/src/server/storage/binaryStoreFake.ts +111 -0
  45. package/src/server/storage/fileUploadClient.integration.spec.ts +2 -21
  46. package/src/server/storage/files/adapter.photo.display.spec.ts +2 -2
  47. package/src/server/storage/files/adapter.photo.spec.ts +2 -2
  48. package/src/server/storage/files/adapter.spec.ts +0 -1
  49. package/src/server/storage/files/catalogue.media-host.spec.ts +6 -71
  50. package/src/server/storage/files/catalogue.recover.spec.ts +14 -23
  51. package/src/server/storage/files/catalogue.ts +19 -240
  52. package/src/server/storage/files/fileRoutes.replace.spec.ts +2 -2
  53. package/src/server/storage/files/fileRoutes.spec.ts +3 -97
  54. package/src/server/storage/files/fileRoutes.ts +2 -96
  55. package/src/server/storage/files/index.ts +1 -4
  56. package/src/server/storage/files/migrations.ts +9 -7
  57. package/src/server/storage/files/stack.spec.ts +11 -111
  58. package/src/server/storage/files/stack.ts +9 -61
  59. package/src/server/storage/files/types.ts +20 -68
  60. package/src/server/storage/index.ts +0 -4
  61. package/src/server/storage/mountMediaRoutes.ts +1 -7
  62. package/src/server/storage/types.ts +2 -11
  63. package/src/shippedFilesAreTracked.spec.ts +3 -2
  64. package/dist/server/private-media/crypto.d.ts +0 -37
  65. package/dist/server/private-media/crypto.js +0 -111
  66. package/dist/server/private-media/index-store.d.ts +0 -31
  67. package/dist/server/private-media/index-store.js +0 -36
  68. package/dist/server/private-media/mountPrivateRoutes.d.ts +0 -26
  69. package/dist/server/private-media/mountPrivateRoutes.js +0 -219
  70. package/dist/server/private-media/pipeline.d.ts +0 -37
  71. package/dist/server/private-media/pipeline.js +0 -97
  72. package/dist/server/private-media/unlock.d.ts +0 -52
  73. package/dist/server/private-media/unlock.js +0 -55
  74. package/src/server/private-media/blobRoute.spec.ts +0 -165
  75. package/src/server/private-media/crypto.spec.ts +0 -81
  76. package/src/server/private-media/crypto.ts +0 -155
  77. package/src/server/private-media/gatePolicy.spec.ts +0 -98
  78. package/src/server/private-media/index-store.ts +0 -83
  79. package/src/server/private-media/mountPrivateRoutes.ts +0 -265
  80. package/src/server/private-media/pipeline.spec.ts +0 -111
  81. package/src/server/private-media/pipeline.ts +0 -170
  82. package/src/server/private-media/routes.spec.ts +0 -265
  83. package/src/server/private-media/unlock.ts +0 -112
  84. package/src/server/storage/files/catalogue.private.spec.ts +0 -106
@@ -12,13 +12,18 @@
12
12
  * keep a wall that strict. Two same-origin files cost one round trip each and let the page
13
13
  * ship under `script-src 'self'` with no nonce plumbing.
14
14
  *
15
- * ── 🔴 The derivation in `LOCK_SCRIPT` is a HAND COPY of `deriveMasterLockVerifier` ──────
15
+ * ── 🔴 The derivation in `MASTER_LOCK_DERIVE_SOURCE` is a HAND COPY of
16
+ * `deriveMasterLockVerifier` ────────────────────────────────────────────
16
17
  * It cannot import it: this file is served to a browser as plain text, outside every build.
17
18
  * A copy that drifts derives a verifier that can never match, and the symptom would be "my
18
19
  * correct password is refused" — the same shape of bug that cost `apps/collections` a day.
19
- * So `lockPage.spec.ts` EVALUATES the script's function out of this source and asserts it
20
- * agrees with the TypeScript one on a fixed vector. Change one, the spec fails until you
21
- * change the other.
20
+ * So `lockPage.spec.ts` EVALUATES the function out of this source and asserts it agrees with
21
+ * the TypeScript one on a fixed vector. Change one, the spec fails until you change the other.
22
+ *
23
+ * 🔴 It is its OWN exported constant, and there is exactly ONE of it. `accountsPage.ts` serves
24
+ * a second browser script that has to derive the same way — a second hand copy would be a
25
+ * second thing to keep in step, and the pinning spec would only be watching one of them. Both
26
+ * scripts interpolate this string, and the spec asserts that they do.
22
27
  */
23
28
  import { MASTER_LOCK_PATHS } from "cursedbelt-core/master-lock";
24
29
 
@@ -159,35 +164,14 @@ button.quiet[disabled]{opacity:.5}
159
164
  `;
160
165
 
161
166
  /**
162
- * The page's script.
167
+ * 🔴 The ONE browser copy of `deriveMasterLockVerifier`, shared by every page this feature
168
+ * serves. Pinned by `lockPage.spec.ts`, which evaluates it and compares against the
169
+ * TypeScript one. Do not "tidy" it apart, and do not write a second copy — interpolate this.
163
170
  *
164
- * Derives in the browser and sends only the verifier — the password itself never crosses
165
- * the network, which is what makes "saved nowhere" true rather than aspirational.
166
- *
167
- * 600,000 PBKDF2 rounds take a beat on a phone, so the button says so; a page that looks
168
- * frozen gets clicked again, and every extra click is another 600k rounds.
171
+ * It ends by publishing the function on `globalThis`, which is the seam the spec pulls it
172
+ * out through and the seam the accounts page's script calls it back through.
169
173
  */
170
- export const LOCK_SCRIPT = `const paths = ${JSON.stringify(MASTER_LOCK_PATHS)};
171
-
172
- const form = document.getElementById("ml-form");
173
- const input = document.getElementById("ml-input");
174
- const confirmInput = document.getElementById("ml-confirm");
175
- const hintInput = document.getElementById("ml-hint");
176
- const submit = document.getElementById("ml-submit");
177
- const status = document.getElementById("ml-status");
178
- const forgot = document.getElementById("ml-forgot");
179
- const hints = document.getElementById("ml-hints");
180
-
181
- function say(message, tone) {
182
- status.textContent = message;
183
- if (tone) status.setAttribute("data-tone", tone);
184
- else status.removeAttribute("data-tone");
185
- }
186
-
187
- // ── derivation ───────────────────────────────────────────────────────────────
188
- // 🔴 Byte-identical to deriveMasterLockVerifier in cursedbelt-core/master-lock. Pinned by
189
- // lockPage.spec.ts, which evaluates THIS function and compares. Do not "tidy" it apart.
190
- function unb64u(text) {
174
+ export const MASTER_LOCK_DERIVE_SOURCE = `function unb64u(text) {
191
175
  const padded = text.replace(/-/g, "+").replace(/_/g, "/");
192
176
  const binary = atob(padded + "=".repeat((4 - (padded.length % 4)) % 4));
193
177
  const out = new Uint8Array(binary.length);
@@ -214,13 +198,38 @@ async function deriveVerifier(password, kdf) {
214
198
  joined.set(bytes, kek.length);
215
199
  return b64u(await pbkdf2(joined, salt, 1));
216
200
  }
217
- globalThis.__masterLockDerive = deriveVerifier;
201
+ globalThis.__masterLockDerive = deriveVerifier;`;
202
+
203
+ /**
204
+ * The page's script.
205
+ *
206
+ * Derives in the browser and sends only the verifier — the password itself never crosses
207
+ * the network, which is what makes "saved nowhere" true rather than aspirational.
208
+ *
209
+ * 600,000 PBKDF2 rounds take a beat on a phone, so the button says so; a page that looks
210
+ * frozen gets clicked again, and every extra click is another 600k rounds.
211
+ */
212
+ export const LOCK_SCRIPT = `const paths = ${JSON.stringify(MASTER_LOCK_PATHS)};
213
+
214
+ // ── derivation ───────────────────────────────────────────────────────────────
215
+ ${MASTER_LOCK_DERIVE_SOURCE}
216
+
217
+ const form = document.getElementById("ml-form");
218
+ const input = document.getElementById("ml-input");
219
+ const confirmInput = document.getElementById("ml-confirm");
220
+ const hintInput = document.getElementById("ml-hint");
221
+ const submit = document.getElementById("ml-submit");
222
+ const status = document.getElementById("ml-status");
223
+ const forgot = document.getElementById("ml-forgot");
224
+ const hints = document.getElementById("ml-hints");
225
+
226
+ function say(message, tone) {
227
+ status.textContent = message;
228
+ if (tone) status.setAttribute("data-tone", tone);
229
+ else status.removeAttribute("data-tone");
230
+ }
218
231
 
219
232
  // ── the page ─────────────────────────────────────────────────────────────────
220
- // 🔴 Everything below this line touches \`document\` beyond \`getElementById\`, and
221
- // lockPage.spec.ts cuts the source at the marker above to evaluate the derivation with a
222
- // stub. Keep page state here, not in the prelude, or that test throws instead of running.
223
- //
224
233
  // Rendered by the server from THIS principal's own record. The server re-decides it on
225
234
  // every POST, so this only chooses which form to submit — it cannot grant anything.
226
235
  const enrolling = document.body.dataset.mode === "enroll";
@@ -166,11 +166,6 @@ export const hlsLadderArgs = (
166
166
  heights: number[];
167
167
  crf: number;
168
168
  hasAudio: boolean;
169
- // When set, ffmpeg AES-128-encrypts every segment using this key-info file (line 1 = the
170
- // key URI written into the playlist's #EXT-X-KEY, line 2 = the raw 16-byte key file, line 3
171
- // = IV hex). Yields encrypted-at-rest, edge-cacheable segments the player decrypts. Used by
172
- // the private-media pipeline; omit for public (plaintext) media.
173
- keyInfoFile?: string;
174
169
  },
175
170
  ): string[] => {
176
171
  const hs = opts.heights.length ? opts.heights : [720];
@@ -218,7 +213,6 @@ export const hlsLadderArgs = (
218
213
  'vod',
219
214
  '-hls_segment_type',
220
215
  'mpegts',
221
- ...(opts.keyInfoFile ? ['-hls_key_info_file', opts.keyInfoFile] : []),
222
216
  '-master_pl_name',
223
217
  'master.m3u8',
224
218
  '-hls_segment_filename',