@izagood/avcs 0.25.1 → 0.26.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/dist/hub/hubClient.d.ts.map +1 -1
- package/dist/hub/hubClient.js +29 -11
- package/dist/hub/hubClient.js.map +1 -1
- package/dist/hub/transportAuth.d.ts +28 -1
- package/dist/hub/transportAuth.d.ts.map +1 -1
- package/dist/hub/transportAuth.js +48 -6
- package/dist/hub/transportAuth.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hubClient.d.ts","sourceRoot":"","sources":["../../src/hub/hubClient.ts"],"names":[],"mappings":"AAcA;;wFAEwF;AACxF,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;CACpB;
|
|
1
|
+
{"version":3,"file":"hubClient.d.ts","sourceRoot":"","sources":["../../src/hub/hubClient.ts"],"names":[],"mappings":"AAcA;;wFAEwF;AACxF,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;CACpB;AAqFD;;;;GAIG;AACH,wBAAsB,SAAS,CAAC,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CA8BzI;AAED;;;;;;GAMG;AACH,wBAAsB,WAAW,CAAC,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC,CAwC7I;AAED;;;;;;;GAOG;AACH,wBAAsB,gBAAgB,CACpC,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,SAAS,CAAA;CAAE,GAC9F,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CA6BxE;AAED;;;;;GAKG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,MAAM,EACd,IAAI,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,GACrI,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,OAAO,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAejF"}
|
package/dist/hub/hubClient.js
CHANGED
|
@@ -9,12 +9,30 @@ import { join } from "node:path";
|
|
|
9
9
|
import { ObjectStore } from "../store/objectStore.js";
|
|
10
10
|
import { keysOf } from "../reducer/reducer.js";
|
|
11
11
|
import { buildAuthHeader } from "./transportAuth.js";
|
|
12
|
+
/**
|
|
13
|
+
* The repository this remote addresses, as the signed `scope` (issue #49).
|
|
14
|
+
*
|
|
15
|
+
* The pathname of the remote base: `https://host/acme/web` → "/acme/web", and a rootless
|
|
16
|
+
* `https://host` → "" (unscoped, exactly as before). A multi-tenant hub mounts per
|
|
17
|
+
* repository, so this is the same prefix it strips to recover the endpoint the client
|
|
18
|
+
* signed — which is why both sides can agree on it without the client knowing the
|
|
19
|
+
* server's routing.
|
|
20
|
+
*/
|
|
21
|
+
function scopeOf(hubUrl) {
|
|
22
|
+
try {
|
|
23
|
+
const p = new URL(hubUrl).pathname.replace(/\/$/, "");
|
|
24
|
+
return p === "/" ? "" : p;
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return "";
|
|
28
|
+
}
|
|
29
|
+
}
|
|
12
30
|
/** Build fetch headers for a hub write, attaching an AVCS-Sig Authorization header when a
|
|
13
31
|
* signer is supplied. `path` must equal the server's pathname or the signature won't verify. */
|
|
14
|
-
function writeHeaders(signer, method, path, body) {
|
|
32
|
+
function writeHeaders(signer, method, path, body, scope = "") {
|
|
15
33
|
const headers = { "content-type": "application/json" };
|
|
16
34
|
if (signer)
|
|
17
|
-
headers["authorization"] = buildAuthHeader({ keyId: signer.keyId, privateKey: signer.privateKey, method, path, body });
|
|
35
|
+
headers["authorization"] = buildAuthHeader({ keyId: signer.keyId, privateKey: signer.privateKey, method, path, body, scope });
|
|
18
36
|
return headers;
|
|
19
37
|
}
|
|
20
38
|
/**
|
|
@@ -28,14 +46,14 @@ function writeHeaders(signer, method, path, body) {
|
|
|
28
46
|
* Best-effort by design: no signer, no header, and a read-public hub is unaffected. The
|
|
29
47
|
* signature covers the method, so a captured GET credential cannot be replayed as a write.
|
|
30
48
|
*/
|
|
31
|
-
function readHeaders(signer, path) {
|
|
49
|
+
function readHeaders(signer, path, scope = "") {
|
|
32
50
|
if (!signer)
|
|
33
51
|
return {};
|
|
34
|
-
return { authorization: buildAuthHeader({ keyId: signer.keyId, privateKey: signer.privateKey, method: "GET", path, body: "" }) };
|
|
52
|
+
return { authorization: buildAuthHeader({ keyId: signer.keyId, privateKey: signer.privateKey, method: "GET", path, body: "", scope }) };
|
|
35
53
|
}
|
|
36
54
|
/** GET /have → the set of oids the hub holds. */
|
|
37
55
|
async function hubHave(hubUrl, signer) {
|
|
38
|
-
const res = await fetch(`${hubUrl.replace(/\/$/, "")}/have`, { headers: readHeaders(signer, "/have") });
|
|
56
|
+
const res = await fetch(`${hubUrl.replace(/\/$/, "")}/have`, { headers: readHeaders(signer, "/have", scopeOf(hubUrl)) });
|
|
39
57
|
if (!res.ok)
|
|
40
58
|
throw new Error(`GET /have failed: ${res.status} ${res.statusText}`);
|
|
41
59
|
const oids = (await res.json());
|
|
@@ -61,7 +79,7 @@ async function readCursors(root) {
|
|
|
61
79
|
*/
|
|
62
80
|
async function discover(base, since, signer) {
|
|
63
81
|
try {
|
|
64
|
-
const res = await fetch(`${base}/sync?since=${since}`, { headers: readHeaders(signer, "/sync") });
|
|
82
|
+
const res = await fetch(`${base}/sync?since=${since}`, { headers: readHeaders(signer, "/sync", scopeOf(base)) });
|
|
65
83
|
if (res.ok) {
|
|
66
84
|
const j = (await res.json());
|
|
67
85
|
return { oids: j.oids, cursor: j.cursor };
|
|
@@ -99,7 +117,7 @@ export async function pushToHub(localRepoDir, hubUrl, signWith) {
|
|
|
99
117
|
const body = JSON.stringify(obj);
|
|
100
118
|
const res = await fetch(`${base}/objects`, {
|
|
101
119
|
method: "POST",
|
|
102
|
-
headers: writeHeaders(signWith, "POST", "/objects", body),
|
|
120
|
+
headers: writeHeaders(signWith, "POST", "/objects", body, scopeOf(base)),
|
|
103
121
|
body,
|
|
104
122
|
});
|
|
105
123
|
if (res.status === 401) {
|
|
@@ -138,7 +156,7 @@ export async function pullFromHub(localRepoDir, hubUrl, signWith) {
|
|
|
138
156
|
for (const oid of oids) {
|
|
139
157
|
if (await store.has(oid))
|
|
140
158
|
continue;
|
|
141
|
-
const res = await fetch(`${base}/objects/${encodeURIComponent(oid)}`, { headers: readHeaders(signWith, `/objects/${encodeURIComponent(oid)}
|
|
159
|
+
const res = await fetch(`${base}/objects/${encodeURIComponent(oid)}`, { headers: readHeaders(signWith, `/objects/${encodeURIComponent(oid)}`, scopeOf(base)) });
|
|
142
160
|
if (res.status === 404)
|
|
143
161
|
continue; // raced eviction; skip
|
|
144
162
|
if (!res.ok)
|
|
@@ -159,7 +177,7 @@ export async function pullFromHub(localRepoDir, hubUrl, signWith) {
|
|
|
159
177
|
// Governance distribution: adopt the hub's authoritative governance refs (policy,
|
|
160
178
|
// membership, protection, protected heads). The objects they point to were just
|
|
161
179
|
// pulled above, so the refs resolve. Working refs (view:*/checkpoint:*) stay local.
|
|
162
|
-
const refsRes = await fetch(`${base}/refs`, { headers: readHeaders(signWith, "/refs") });
|
|
180
|
+
const refsRes = await fetch(`${base}/refs`, { headers: readHeaders(signWith, "/refs", scopeOf(base)) });
|
|
163
181
|
if (refsRes.ok) {
|
|
164
182
|
const { refs } = (await refsRes.json());
|
|
165
183
|
for (const [name, refOid] of Object.entries(refs)) {
|
|
@@ -195,7 +213,7 @@ export async function integrateWithHub(localRepoDir, hubUrl, args) {
|
|
|
195
213
|
body.sig = { keyId: args.signWith.keyId, alg: "ed25519", sig: signMessage(args.signWith.privateKey, msg) };
|
|
196
214
|
}
|
|
197
215
|
const raw = JSON.stringify(body);
|
|
198
|
-
const res = await fetch(`${base}/integrate`, { method: "POST", headers: writeHeaders(args.signWith, "POST", "/integrate", raw), body: raw });
|
|
216
|
+
const res = await fetch(`${base}/integrate`, { method: "POST", headers: writeHeaders(args.signWith, "POST", "/integrate", raw, scopeOf(base)), body: raw });
|
|
199
217
|
const j = (await res.json().catch(() => ({})));
|
|
200
218
|
// 3. needs_evidence: fetch exactly the head-side delta so `materializeAt` can reproduce
|
|
201
219
|
// the integrated tree locally (determinism guarantees the same treeHash).
|
|
@@ -232,7 +250,7 @@ export async function finalizeOnHub(hubUrl, args) {
|
|
|
232
250
|
// Two distinct signatures: body.sig authenticates the finalize INTENT (object layer), the
|
|
233
251
|
// Authorization header authenticates the REQUEST (transport layer). Both use one keypair.
|
|
234
252
|
const raw = JSON.stringify(body);
|
|
235
|
-
const res = await fetch(`${base}/finalize`, { method: "POST", headers: writeHeaders(args.signWith, "POST", "/finalize", raw), body: raw });
|
|
253
|
+
const res = await fetch(`${base}/finalize`, { method: "POST", headers: writeHeaders(args.signWith, "POST", "/finalize", raw, scopeOf(base)), body: raw });
|
|
236
254
|
const j = (await res.json().catch(() => ({})));
|
|
237
255
|
return { status: res.status, finalized: j.finalized ?? false, head: j.head, reason: j.reason };
|
|
238
256
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hubClient.js","sourceRoot":"","sources":["../../src/hub/hubClient.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,EAAE;AACF,wFAAwF;AACxF,mFAAmF;AACnF,+DAA+D;AAE/D,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAC/C,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAWrD;iGACiG;AACjG,SAAS,YAAY,CAAC,MAA6B,EAAE,MAAc,EAAE,IAAY,EAAE,IAAY;
|
|
1
|
+
{"version":3,"file":"hubClient.js","sourceRoot":"","sources":["../../src/hub/hubClient.ts"],"names":[],"mappings":"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"}
|
|
@@ -9,13 +9,29 @@ export interface AuthCredential {
|
|
|
9
9
|
ts: string;
|
|
10
10
|
nonce: string;
|
|
11
11
|
sig: string;
|
|
12
|
+
/** The repository the client believes it is addressing (issue #49). Absent on an
|
|
13
|
+
* unscoped credential — which is every credential written before this existed. */
|
|
14
|
+
scope?: string;
|
|
15
|
+
/** Signature over the scope-bearing material. Present iff `scope` is. Separate from
|
|
16
|
+
* `sig` so a scope-unaware verifier can still check `sig` and accept the request. */
|
|
17
|
+
bsig?: string;
|
|
12
18
|
}
|
|
13
19
|
/**
|
|
14
20
|
* The exact byte string both sides sign/verify. Binds the signature to the method, the
|
|
15
21
|
* request target, a timestamp (freshness) and a nonce (replay), plus a hash of the body
|
|
16
22
|
* so a captured signature cannot be replayed against different content.
|
|
23
|
+
*
|
|
24
|
+
* `scope` (issue #49) additionally binds it to a REPOSITORY. The path a client signs is
|
|
25
|
+
* the endpoint suffix ("/objects"), because the reference hub sits at the root — so
|
|
26
|
+
* without a scope nothing in the signed material says which repository the write was for,
|
|
27
|
+
* and on a multi-tenant hub a credential captured for one repo is structurally valid for
|
|
28
|
+
* another. Signing the full path instead would couple the signature to the server's mount
|
|
29
|
+
* layout and break under ordinary path-rewriting proxies.
|
|
30
|
+
*
|
|
31
|
+
* Appended rather than inserted, and empty when absent, so an unscoped credential produces
|
|
32
|
+
* byte-identical material to what this function produced before scope existed.
|
|
17
33
|
*/
|
|
18
|
-
export declare function canonicalRequest(method: string, path: string, ts: string, nonce: string, body: string): string;
|
|
34
|
+
export declare function canonicalRequest(method: string, path: string, ts: string, nonce: string, body: string, scope?: string): string;
|
|
19
35
|
/** Build an `Authorization: AVCS-Sig …` header value, signing the request with the local
|
|
20
36
|
* actor's private key. `body` is the exact request body the client will send (""for none). */
|
|
21
37
|
export declare function buildAuthHeader(args: {
|
|
@@ -26,6 +42,8 @@ export declare function buildAuthHeader(args: {
|
|
|
26
42
|
body?: string;
|
|
27
43
|
ts?: string;
|
|
28
44
|
nonce?: string;
|
|
45
|
+
/** Repository this credential is for (issue #49). Omit, or pass "", to sign unscoped. */
|
|
46
|
+
scope?: string;
|
|
29
47
|
}): string;
|
|
30
48
|
/** Parse an AVCS-Sig Authorization header. Returns null on any scheme/field mismatch. */
|
|
31
49
|
export declare function parseAuthHeader(header: string | undefined | null): AuthCredential | null;
|
|
@@ -69,5 +87,14 @@ export declare function verifyAuth(args: {
|
|
|
69
87
|
now: number;
|
|
70
88
|
windowMs?: number;
|
|
71
89
|
nonceCache?: NonceCache;
|
|
90
|
+
/**
|
|
91
|
+
* The repository this request is actually for (issue #49). When set, the credential must
|
|
92
|
+
* name the same one — so a signature captured for another repo on a multi-tenant hub is
|
|
93
|
+
* refused even though key, method, path, body and freshness all still check out.
|
|
94
|
+
*
|
|
95
|
+
* Leave unset on a single-repo hub: there is nothing to compare against, and every
|
|
96
|
+
* existing credential keeps verifying exactly as before.
|
|
97
|
+
*/
|
|
98
|
+
expectedScope?: string;
|
|
72
99
|
}): Promise<AuthResult>;
|
|
73
100
|
//# sourceMappingURL=transportAuth.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transportAuth.d.ts","sourceRoot":"","sources":["../../src/hub/transportAuth.ts"],"names":[],"mappings":"AAsBA,wFAAwF;AACxF,eAAO,MAAM,WAAW,aAAa,CAAC;AAEtC;4FAC4F;AAC5F,eAAO,MAAM,sBAAsB,SAAU,CAAC;AAE9C,6DAA6D;AAC7D,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"transportAuth.d.ts","sourceRoot":"","sources":["../../src/hub/transportAuth.ts"],"names":[],"mappings":"AAsBA,wFAAwF;AACxF,eAAO,MAAM,WAAW,aAAa,CAAC;AAEtC;4FAC4F;AAC5F,eAAO,MAAM,sBAAsB,SAAU,CAAC;AAE9C,6DAA6D;AAC7D,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ;uFACmF;IACnF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;0FACsF;IACtF,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,SAAK,GAAG,MAAM,CAG1H;AAED;+FAC+F;AAC/F,wBAAgB,eAAe,CAAC,IAAI,EAAE;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,yFAAyF;IACzF,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GAAG,MAAM,CAgBT;AAED,yFAAyF;AACzF,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,cAAc,GAAG,IAAI,CAexF;AAED;;;;GAIG;AACH,qBAAa,UAAU;;gBAKT,KAAK,GAAE,MAA+B,EAAE,GAAG,SAAU;IAKjE,uEAAuE;IACvE,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO;CAkB3C;AAED;;0DAE0D;AAC1D,MAAM,MAAM,iBAAiB,GAAG,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;AAE1E,MAAM,MAAM,UAAU,GAAG;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAErF;;;;;;;;GAQG;AACH,wBAAsB,UAAU,CAAC,IAAI,EAAE;IACrC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAAC;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,gBAAgB,EAAE,iBAAiB,CAAC;IACpC,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB;;;;;;;OAOG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,GAAG,OAAO,CAAC,UAAU,CAAC,CAuCtB"}
|
|
@@ -27,17 +27,40 @@ export const DEFAULT_AUTH_WINDOW_MS = 300_000; // 5 minutes
|
|
|
27
27
|
* The exact byte string both sides sign/verify. Binds the signature to the method, the
|
|
28
28
|
* request target, a timestamp (freshness) and a nonce (replay), plus a hash of the body
|
|
29
29
|
* so a captured signature cannot be replayed against different content.
|
|
30
|
+
*
|
|
31
|
+
* `scope` (issue #49) additionally binds it to a REPOSITORY. The path a client signs is
|
|
32
|
+
* the endpoint suffix ("/objects"), because the reference hub sits at the root — so
|
|
33
|
+
* without a scope nothing in the signed material says which repository the write was for,
|
|
34
|
+
* and on a multi-tenant hub a credential captured for one repo is structurally valid for
|
|
35
|
+
* another. Signing the full path instead would couple the signature to the server's mount
|
|
36
|
+
* layout and break under ordinary path-rewriting proxies.
|
|
37
|
+
*
|
|
38
|
+
* Appended rather than inserted, and empty when absent, so an unscoped credential produces
|
|
39
|
+
* byte-identical material to what this function produced before scope existed.
|
|
30
40
|
*/
|
|
31
|
-
export function canonicalRequest(method, path, ts, nonce, body) {
|
|
32
|
-
|
|
41
|
+
export function canonicalRequest(method, path, ts, nonce, body, scope = "") {
|
|
42
|
+
const core = `${method.toUpperCase()}\n${path}\n${ts}\n${nonce}\n${sha256hex(body)}`;
|
|
43
|
+
return scope ? `${core}\n${scope}` : core;
|
|
33
44
|
}
|
|
34
45
|
/** Build an `Authorization: AVCS-Sig …` header value, signing the request with the local
|
|
35
46
|
* actor's private key. `body` is the exact request body the client will send (""for none). */
|
|
36
47
|
export function buildAuthHeader(args) {
|
|
37
48
|
const ts = args.ts ?? new Date().toISOString();
|
|
38
49
|
const nonce = args.nonce ?? randomBytes(12).toString("base64url");
|
|
39
|
-
const
|
|
40
|
-
|
|
50
|
+
const scope = args.scope ?? "";
|
|
51
|
+
const body = args.body ?? "";
|
|
52
|
+
// TWO signatures, deliberately. `sig` covers the original material so a hub running an
|
|
53
|
+
// older avcs — which reconstructs canonicalRequest without any scope — still verifies it
|
|
54
|
+
// and keeps working. `bsig` additionally covers the scope, and is what a hub that
|
|
55
|
+
// REQUIRES binding checks. One signature cannot do both jobs: folding scope into `sig`
|
|
56
|
+
// makes every deployed verifier reject every request, which is exactly what happened the
|
|
57
|
+
// first time this was attempted against a live hub.
|
|
58
|
+
const sig = signMessage(args.privateKey, canonicalRequest(args.method, args.path, ts, nonce, body));
|
|
59
|
+
const head = `${AUTH_SCHEME} keyId="${args.keyId}", ts="${ts}", nonce="${nonce}"`;
|
|
60
|
+
if (!scope)
|
|
61
|
+
return `${head}, sig="${sig}"`;
|
|
62
|
+
const bsig = signMessage(args.privateKey, canonicalRequest(args.method, args.path, ts, nonce, body, scope));
|
|
63
|
+
return `${head}, scope="${scope}", sig="${sig}", bsig="${bsig}"`;
|
|
41
64
|
}
|
|
42
65
|
/** Parse an AVCS-Sig Authorization header. Returns null on any scheme/field mismatch. */
|
|
43
66
|
export function parseAuthHeader(header) {
|
|
@@ -53,10 +76,12 @@ export function parseAuthHeader(header) {
|
|
|
53
76
|
let m;
|
|
54
77
|
while ((m = re.exec(rest)) !== null)
|
|
55
78
|
fields[m[1]] = m[2];
|
|
56
|
-
const { keyId, ts, nonce, sig } = fields;
|
|
79
|
+
const { keyId, ts, nonce, sig, scope, bsig } = fields;
|
|
57
80
|
if (!keyId || !ts || !nonce || !sig)
|
|
58
81
|
return null;
|
|
59
|
-
|
|
82
|
+
// An empty scope is reported as absent: a rootless remote derives "" and must not turn
|
|
83
|
+
// that into an expectation nobody can satisfy.
|
|
84
|
+
return scope && bsig ? { keyId, ts, nonce, sig, scope, bsig } : { keyId, ts, nonce, sig };
|
|
60
85
|
}
|
|
61
86
|
/**
|
|
62
87
|
* A bounded seen-nonce cache for replay protection. Entries expire after `ttlMs` (the
|
|
@@ -116,12 +141,29 @@ export async function verifyAuth(args) {
|
|
|
116
141
|
if (args.nonceCache && !args.nonceCache.check(cred.nonce, args.now)) {
|
|
117
142
|
return { ok: false, reason: "nonce already used (replay)" };
|
|
118
143
|
}
|
|
144
|
+
if (args.expectedScope) {
|
|
145
|
+
if (!cred.scope) {
|
|
146
|
+
return { ok: false, reason: `credential carries no scope; this hub requires scope "${args.expectedScope}"` };
|
|
147
|
+
}
|
|
148
|
+
if (cred.scope !== args.expectedScope) {
|
|
149
|
+
return { ok: false, reason: `credential scope "${cred.scope}" does not match "${args.expectedScope}"` };
|
|
150
|
+
}
|
|
151
|
+
}
|
|
119
152
|
const publicKey = await args.resolvePublicKey(cred.keyId);
|
|
120
153
|
if (!publicKey)
|
|
121
154
|
return { ok: false, reason: `unknown signing key ${cred.keyId}` };
|
|
122
155
|
const msg = canonicalRequest(args.method, args.path, cred.ts, cred.nonce, args.body);
|
|
123
156
|
if (!verifyMessage(publicKey, msg, cred.sig))
|
|
124
157
|
return { ok: false, reason: "request signature does not verify" };
|
|
158
|
+
// When binding is required, the scope must ALSO be signed — otherwise it is decoration a
|
|
159
|
+
// replayer could rewrite. Checked after `sig` so a tampered scope fails as a signature
|
|
160
|
+
// problem rather than a mismatch, and only when this hub asked for binding.
|
|
161
|
+
if (args.expectedScope) {
|
|
162
|
+
const bound = canonicalRequest(args.method, args.path, cred.ts, cred.nonce, args.body, cred.scope);
|
|
163
|
+
if (!cred.bsig || !verifyMessage(publicKey, bound, cred.bsig)) {
|
|
164
|
+
return { ok: false, reason: "scope binding does not verify" };
|
|
165
|
+
}
|
|
166
|
+
}
|
|
125
167
|
return { ok: true, keyId: cred.keyId };
|
|
126
168
|
}
|
|
127
169
|
//# sourceMappingURL=transportAuth.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transportAuth.js","sourceRoot":"","sources":["../../src/hub/transportAuth.ts"],"names":[],"mappings":"AAAA,yFAAyF;AACzF,EAAE;AACF,qFAAqF;AACrF,uFAAuF;AACvF,uFAAuF;AACvF,oEAAoE;AACpE,EAAE;AACF,wFAAwF;AACxF,sFAAsF;AACtF,gFAAgF;AAChF,EAAE;AACF,yFAAyF;AACzF,oFAAoF;AACpF,yFAAyF;AACzF,qFAAqF;AACrF,uFAAuF;AACvF,qEAAqE;AAErE,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEjE,wFAAwF;AACxF,MAAM,CAAC,MAAM,WAAW,GAAG,UAAU,CAAC;AAEtC;4FAC4F;AAC5F,MAAM,CAAC,MAAM,sBAAsB,GAAG,OAAO,CAAC,CAAC,YAAY;
|
|
1
|
+
{"version":3,"file":"transportAuth.js","sourceRoot":"","sources":["../../src/hub/transportAuth.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@izagood/avcs",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.26.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Agentic Version Control System — an AI-native VCS where intent, session, operation, evidence and decision are first-class objects and code is a materialized projection of an operation graph.",
|
|
6
6
|
"license": "Apache-2.0",
|