@ainra/middleware 0.6.0 → 0.8.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.
- package/README.md +1 -1
- package/dist/index.js +20 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -75,7 +75,7 @@ depends on the lenient path.
|
|
|
75
75
|
## Underneath
|
|
76
76
|
|
|
77
77
|
Verification is [`@ainra/sdk`](https://www.npmjs.com/package/@ainra/sdk) — one of the three implementations that
|
|
78
|
-
agree on all
|
|
78
|
+
agree on all 1169 conformance vectors, on verdict and reason. This package adds only the request plumbing: header decoding, the 403, the
|
|
79
79
|
verdict event, and `req.ainra`.
|
|
80
80
|
|
|
81
81
|
Licensed Apache-2.0 OR MIT.
|
package/dist/index.js
CHANGED
|
@@ -120,6 +120,22 @@ export function checkRequest(verifier, bundle, opts = {}) {
|
|
|
120
120
|
}
|
|
121
121
|
return { allow, reason, verdict, event: verdictEvent(parsed, verdict, now) };
|
|
122
122
|
}
|
|
123
|
+
/** Does the request carry a body the gate was not given the raw bytes of? */
|
|
124
|
+
function bodyUnseen(req) {
|
|
125
|
+
if (req.rawBody !== undefined)
|
|
126
|
+
return false;
|
|
127
|
+
const h = (k) => { const v = req.headers[k]; return Array.isArray(v) ? v[0] : v; };
|
|
128
|
+
if (Number(h("content-length") ?? 0) > 0 || h("transfer-encoding") !== undefined || h("content-digest") !== undefined)
|
|
129
|
+
return true;
|
|
130
|
+
const b = req.body;
|
|
131
|
+
if (typeof b === "string")
|
|
132
|
+
return b.length > 0;
|
|
133
|
+
if (b && typeof b === "object") {
|
|
134
|
+
const keys = Object.keys(b).filter((k) => k !== "ainra_passport");
|
|
135
|
+
return keys.length > 0;
|
|
136
|
+
}
|
|
137
|
+
return false;
|
|
138
|
+
}
|
|
123
139
|
/** Build the signed-over view of an Express/Node request. `authority` comes from the Host header, which is what
|
|
124
140
|
* the client addressed and therefore what it signed. */
|
|
125
141
|
function bindingFromReq(req) {
|
|
@@ -188,7 +204,10 @@ export function ainraGate(verifier, opts = {}) {
|
|
|
188
204
|
return (req, res, next) => {
|
|
189
205
|
const raw = req.headers[header] ?? req.body?.ainra_passport;
|
|
190
206
|
const popRaw = req.headers[popHeader];
|
|
191
|
-
|
|
207
|
+
// A signed request whose body the gate cannot see is refused, not checked as if it had none: a signature captured
|
|
208
|
+
// on a bodyless request would otherwise pass with any body attached (2026-11-07 review).
|
|
209
|
+
const blind = opts.requireSignature === true && bodyUnseen(req);
|
|
210
|
+
const result = raw === undefined || blind
|
|
192
211
|
? { allow: false, reason: "schema_violation", verdict: DENY_SCHEMA, event: verdictEvent({}, DENY_SCHEMA, (opts.now ?? (() => Math.floor(Date.now() / 1000)))()) }
|
|
193
212
|
: checkRequest(verifier, Array.isArray(raw) ? raw[0] : raw, {
|
|
194
213
|
...opts,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ainra/middleware",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "AINRA verifier middleware — a fail-closed gate (Connect/Express + framework-agnostic) that verifies an AINRA passport on a request, over @ainra/sdk. The verification wedge: local, offline, ~5-line integration.",
|
|
5
5
|
"license": "Apache-2.0 OR MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"test": "node --test"
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"@ainra/sdk": "^0.
|
|
17
|
+
"@ainra/sdk": "^0.8.0"
|
|
18
18
|
},
|
|
19
19
|
"devDependencies": {
|
|
20
20
|
"@types/node": "^26.1.1",
|