@blamejs/core 0.4.1

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 (160) hide show
  1. package/CHANGELOG.md +230 -0
  2. package/LICENSE +201 -0
  3. package/LTS-CALENDAR.md +29 -0
  4. package/MIGRATING.md +7 -0
  5. package/NOTICE +59 -0
  6. package/README.md +100 -0
  7. package/bin/blamejs.js +13 -0
  8. package/index.js +253 -0
  9. package/lib/api-key.js +705 -0
  10. package/lib/api-snapshot.js +335 -0
  11. package/lib/app-shutdown.js +381 -0
  12. package/lib/app.js +364 -0
  13. package/lib/atomic-file.js +525 -0
  14. package/lib/audit-chain.js +168 -0
  15. package/lib/audit-sign.js +319 -0
  16. package/lib/audit-tools.js +682 -0
  17. package/lib/audit.js +753 -0
  18. package/lib/auth/jwt.js +280 -0
  19. package/lib/auth/oauth.js +691 -0
  20. package/lib/auth/passkey.js +185 -0
  21. package/lib/auth/password.js +139 -0
  22. package/lib/auth/totp.js +17 -0
  23. package/lib/auth-header.js +81 -0
  24. package/lib/backup/bundle.js +219 -0
  25. package/lib/backup/crypto.js +174 -0
  26. package/lib/backup/index.js +490 -0
  27. package/lib/backup/manifest.js +275 -0
  28. package/lib/bundler.js +295 -0
  29. package/lib/cache.js +819 -0
  30. package/lib/chain-writer.js +234 -0
  31. package/lib/cli-helpers.js +201 -0
  32. package/lib/cli.js +1377 -0
  33. package/lib/cluster-provider-db.js +245 -0
  34. package/lib/cluster-storage.js +166 -0
  35. package/lib/cluster.js +691 -0
  36. package/lib/consent.js +222 -0
  37. package/lib/constants.js +186 -0
  38. package/lib/cookies.js +293 -0
  39. package/lib/credential-hash.js +303 -0
  40. package/lib/crypto-field.js +159 -0
  41. package/lib/crypto.js +250 -0
  42. package/lib/db-query.js +297 -0
  43. package/lib/db-schema.js +250 -0
  44. package/lib/db.js +1054 -0
  45. package/lib/deprecate.js +226 -0
  46. package/lib/dev.js +324 -0
  47. package/lib/error-page.js +424 -0
  48. package/lib/events.js +135 -0
  49. package/lib/external-db.js +422 -0
  50. package/lib/forms.js +378 -0
  51. package/lib/framework-error.js +189 -0
  52. package/lib/framework-schema.js +604 -0
  53. package/lib/handlers.js +350 -0
  54. package/lib/html-balance.js +227 -0
  55. package/lib/http-client.js +615 -0
  56. package/lib/i18n.js +780 -0
  57. package/lib/jobs.js +181 -0
  58. package/lib/lazy-require.js +48 -0
  59. package/lib/log-stream-local.js +137 -0
  60. package/lib/log-stream-webhook.js +170 -0
  61. package/lib/log-stream.js +211 -0
  62. package/lib/log.js +355 -0
  63. package/lib/mail-bounce.js +507 -0
  64. package/lib/mail.js +701 -0
  65. package/lib/metrics.js +647 -0
  66. package/lib/middleware/api-encrypt.js +553 -0
  67. package/lib/middleware/attach-user.js +156 -0
  68. package/lib/middleware/body-parser.js +883 -0
  69. package/lib/middleware/bot-guard.js +148 -0
  70. package/lib/middleware/compression.js +436 -0
  71. package/lib/middleware/cors.js +236 -0
  72. package/lib/middleware/csp-nonce.js +332 -0
  73. package/lib/middleware/csrf-protect.js +275 -0
  74. package/lib/middleware/error-handler.js +46 -0
  75. package/lib/middleware/health.js +358 -0
  76. package/lib/middleware/index.js +52 -0
  77. package/lib/middleware/rate-limit.js +319 -0
  78. package/lib/middleware/request-id.js +53 -0
  79. package/lib/middleware/require-auth.js +95 -0
  80. package/lib/middleware/security-headers.js +91 -0
  81. package/lib/migrations.js +353 -0
  82. package/lib/mtls-ca.js +333 -0
  83. package/lib/mtls-engine-default.js +285 -0
  84. package/lib/nonce-store.js +177 -0
  85. package/lib/notify.js +643 -0
  86. package/lib/ntp-check.js +178 -0
  87. package/lib/object-store/azure-blob.js +467 -0
  88. package/lib/object-store/gcs.js +469 -0
  89. package/lib/object-store/http-put.js +153 -0
  90. package/lib/object-store/index.js +140 -0
  91. package/lib/object-store/local.js +163 -0
  92. package/lib/object-store/retry.js +15 -0
  93. package/lib/object-store/sigv4.js +535 -0
  94. package/lib/observability.js +114 -0
  95. package/lib/pagination.js +371 -0
  96. package/lib/parsers/index.js +64 -0
  97. package/lib/parsers/safe-csv.js +224 -0
  98. package/lib/parsers/safe-env.js +614 -0
  99. package/lib/parsers/safe-toml.js +745 -0
  100. package/lib/parsers/safe-xml.js +379 -0
  101. package/lib/parsers/safe-yaml.js +977 -0
  102. package/lib/permissions.js +430 -0
  103. package/lib/pqc-agent.js +85 -0
  104. package/lib/pqc-gate.js +266 -0
  105. package/lib/protocol-dispatcher.js +144 -0
  106. package/lib/queue-local.js +327 -0
  107. package/lib/queue.js +430 -0
  108. package/lib/redact.js +192 -0
  109. package/lib/render.js +193 -0
  110. package/lib/request-helpers.js +178 -0
  111. package/lib/restore-bundle.js +239 -0
  112. package/lib/restore-rollback.js +254 -0
  113. package/lib/restore.js +301 -0
  114. package/lib/retry.js +329 -0
  115. package/lib/router.js +437 -0
  116. package/lib/safe-async.js +520 -0
  117. package/lib/safe-buffer.js +162 -0
  118. package/lib/safe-json.js +532 -0
  119. package/lib/safe-schema.js +1176 -0
  120. package/lib/safe-sql.js +157 -0
  121. package/lib/safe-url.js +109 -0
  122. package/lib/scheduler.js +680 -0
  123. package/lib/seeders.js +622 -0
  124. package/lib/session.js +304 -0
  125. package/lib/slug.js +243 -0
  126. package/lib/static.js +268 -0
  127. package/lib/storage.js +470 -0
  128. package/lib/subject.js +281 -0
  129. package/lib/template.js +781 -0
  130. package/lib/testing.js +621 -0
  131. package/lib/totp.js +285 -0
  132. package/lib/tracing.js +484 -0
  133. package/lib/validate-opts.js +56 -0
  134. package/lib/vault/index.js +299 -0
  135. package/lib/vault/passphrase-ops.js +311 -0
  136. package/lib/vault/passphrase-source.js +198 -0
  137. package/lib/vault/rotate.js +761 -0
  138. package/lib/vault/wrap.js +289 -0
  139. package/lib/vendor/MANIFEST.json +84 -0
  140. package/lib/vendor/argon2/argon2.cjs +466 -0
  141. package/lib/vendor/argon2/argon2.d.cts +62 -0
  142. package/lib/vendor/argon2/package.json +1 -0
  143. package/lib/vendor/argon2/prebuilds/darwin-arm64/argon2.armv8.glibc.node +0 -0
  144. package/lib/vendor/argon2/prebuilds/darwin-x64/argon2.glibc.node +0 -0
  145. package/lib/vendor/argon2/prebuilds/freebsd-arm64/argon2.armv8.glibc.node +0 -0
  146. package/lib/vendor/argon2/prebuilds/freebsd-x64/argon2.glibc.node +0 -0
  147. package/lib/vendor/argon2/prebuilds/linux-arm/argon2.armv7.glibc.node +0 -0
  148. package/lib/vendor/argon2/prebuilds/linux-arm/argon2.armv7.musl.node +0 -0
  149. package/lib/vendor/argon2/prebuilds/linux-arm64/argon2.armv8.glibc.node +0 -0
  150. package/lib/vendor/argon2/prebuilds/linux-arm64/argon2.armv8.musl.node +0 -0
  151. package/lib/vendor/argon2/prebuilds/linux-x64/argon2.glibc.node +0 -0
  152. package/lib/vendor/argon2/prebuilds/linux-x64/argon2.musl.node +0 -0
  153. package/lib/vendor/argon2/prebuilds/win32-x64/argon2.glibc.node +0 -0
  154. package/lib/vendor/noble-ciphers.cjs +9 -0
  155. package/lib/vendor/pki.cjs +181 -0
  156. package/lib/vendor/simplewebauthn-server.cjs +328 -0
  157. package/lib/webhook.js +632 -0
  158. package/lib/websocket-channels.js +413 -0
  159. package/lib/websocket.js +833 -0
  160. package/package.json +39 -0
@@ -0,0 +1,156 @@
1
+ "use strict";
2
+ /**
3
+ * attach-user middleware — populates req.user (and req.session) from a
4
+ * verified session token.
5
+ *
6
+ * Token sources, tried in order:
7
+ * 1. Cookie named opts.cookieName (default "blamejs_session")
8
+ * 2. Authorization: Bearer <token> header
9
+ * The first one that produces a verified session wins. Operators who
10
+ * want only one path can disable the other via opts.tokenFrom.
11
+ *
12
+ * Sealed cookies (access-gated): when opts.sealed is true and opts.vault
13
+ * is provided, the cookie value is read via cookies.readSealed (which
14
+ * vault-unseals and recovers the original session token). Without the
15
+ * framework's vault key no client can hand-craft a valid cookie, so the
16
+ * API is unreachable via curl-with-arbitrary-cookies. Default off for
17
+ * back-compat with apps that put the raw token in the cookie.
18
+ *
19
+ * The framework can't know the application's user schema, so the
20
+ * middleware delegates user-record loading to opts.userLoader — an
21
+ * async function `(verifiedSession) => user | null`. Operators
22
+ * typically look up by userId in their own users table.
23
+ *
24
+ * Failure modes (none of which throw):
25
+ * - No token in either source → req.user = null, next()
26
+ * - Sealed cookie present but unsealable → req.user = null, next()
27
+ * - Token present but session.verify rejects → req.user = null, next()
28
+ * - Session valid but userLoader returns null/undefined → req.user
29
+ * = null, next() + audit emit (with outcome=failure)
30
+ *
31
+ * Always calls next() — the gating decision is downstream's job (use
32
+ * middleware.requireAuth for that). This middleware only ATTACHES.
33
+ *
34
+ * Options:
35
+ * {
36
+ * cookieName: 'blamejs_session' (cookie name to read)
37
+ * tokenFrom: 'both' | 'cookie' | 'header' (default 'both')
38
+ * sealed: false (use cookies.readSealed)
39
+ * vault: b.vault (required when sealed)
40
+ * userLoader: async (verifiedSession) => user (REQUIRED)
41
+ * audit: true (emit user-load audits)
42
+ * }
43
+ */
44
+ var lazyRequire = require("../lazy-require");
45
+ var cookies = require("../cookies");
46
+ var validateOpts = require("../validate-opts");
47
+ var session = lazyRequire(function () { return require("../session"); });
48
+ var audit = lazyRequire(function () { return require("../audit"); });
49
+
50
+ // Back-compat helper: read a single named cookie from a Cookie: header
51
+ // string. Delegates to cookies.parse so the parser is one place.
52
+ function _readCookie(cookieHeader, name) {
53
+ if (!cookieHeader || typeof cookieHeader !== "string") return null;
54
+ var jar = cookies.parse(cookieHeader);
55
+ return Object.prototype.hasOwnProperty.call(jar, name) ? jar[name] : null;
56
+ }
57
+
58
+ function _readBearer(authHeader) {
59
+ if (!authHeader || typeof authHeader !== "string") return null;
60
+ // case-insensitive scheme match
61
+ var m = authHeader.match(/^Bearer\s+(.+)$/i);
62
+ return m ? m[1].trim() : null;
63
+ }
64
+
65
+ function create(opts) {
66
+ opts = opts || {};
67
+ validateOpts(opts, [
68
+ "cookieName", "tokenFrom", "sealed", "vault", "userLoader", "audit",
69
+ ], "middleware.attachUser");
70
+ if (typeof opts.userLoader !== "function") {
71
+ throw new Error("middleware.attachUser: opts.userLoader is required " +
72
+ "(async function (verifiedSession) → user | null)");
73
+ }
74
+ var cookieName = opts.cookieName || "blamejs_session";
75
+ var tokenFrom = opts.tokenFrom || "both";
76
+ var auditOn = opts.audit !== false;
77
+ var sealed = !!opts.sealed;
78
+ if (sealed && (!opts.vault || typeof opts.vault.unseal !== "function")) {
79
+ throw new Error("middleware.attachUser: opts.sealed requires opts.vault " +
80
+ "with a .unseal method (typically b.vault)");
81
+ }
82
+ // Cookie reader: instance bound to the operator's vault when sealed,
83
+ // otherwise the stateless plain reader.
84
+ var cookieJar = sealed ? cookies.create({ vault: opts.vault }) : null;
85
+
86
+ return async function attachUser(req, res, next) {
87
+ req.user = null;
88
+ req.session = null;
89
+
90
+ var token = null;
91
+ if (tokenFrom === "cookie" || tokenFrom === "both") {
92
+ token = sealed
93
+ ? cookieJar.readSealed(req, cookieName)
94
+ : _readCookie(req.headers && req.headers.cookie, cookieName);
95
+ }
96
+ if (!token && (tokenFrom === "header" || tokenFrom === "both")) {
97
+ token = _readBearer(req.headers && req.headers.authorization);
98
+ }
99
+ if (!token) return next();
100
+
101
+ var verified;
102
+ try {
103
+ verified = await session().verify(token);
104
+ } catch (_e) {
105
+ // session.verify is tolerant — shouldn't normally throw, but if it
106
+ // does (DB hiccup), don't propagate; treat as "no user" and let
107
+ // downstream require-auth produce a 401.
108
+ return next();
109
+ }
110
+ if (!verified) return next();
111
+
112
+ var user;
113
+ try {
114
+ user = await opts.userLoader(verified);
115
+ } catch (e) {
116
+ // userLoader threw — treat as "no user" but record so the
117
+ // operator can investigate. Don't surface to the response.
118
+ if (auditOn) {
119
+ try {
120
+ audit().emit({
121
+ action: "auth.session.user_loader_threw",
122
+ outcome: "failure",
123
+ actor: { userId: verified.userId, ip: req.socket && req.socket.remoteAddress },
124
+ reason: (e && e.message) || String(e),
125
+ });
126
+ } catch (_ignored) { /* audit best-effort */ }
127
+ }
128
+ return next();
129
+ }
130
+ if (!user) {
131
+ // Session valid but user record is gone (deleted) or rejected
132
+ // (suspended, etc.). Record + don't attach.
133
+ if (auditOn) {
134
+ try {
135
+ audit().emit({
136
+ action: "auth.session.user_unloadable",
137
+ outcome: "failure",
138
+ actor: { userId: verified.userId, ip: req.socket && req.socket.remoteAddress },
139
+ });
140
+ } catch (_ignored) { /* audit best-effort */ }
141
+ }
142
+ return next();
143
+ }
144
+
145
+ req.user = user;
146
+ req.session = verified;
147
+ return next();
148
+ };
149
+ }
150
+
151
+ module.exports = {
152
+ create: create,
153
+ // Exported for tests and operator-side cookie reading
154
+ _readCookie: _readCookie,
155
+ _readBearer: _readBearer,
156
+ };