@ainize/core 0.1.3 → 0.1.5
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/teach-auth.d.ts +56 -0
- package/dist/teach-auth.d.ts.map +1 -1
- package/dist/teach-auth.js +71 -0
- package/dist/teach-auth.js.map +1 -1
- package/package.json +1 -1
package/dist/teach-auth.d.ts
CHANGED
|
@@ -16,4 +16,60 @@ export declare function teachAuthHeaderFor(key: {
|
|
|
16
16
|
privateKey: string;
|
|
17
17
|
address: string;
|
|
18
18
|
}, t: TeachAuthTarget, ts?: number): string;
|
|
19
|
+
/** Header that carries the delegation, beside the ordinary `x-ainize-auth`. */
|
|
20
|
+
export declare const DELEGATE_HEADER = "x-ainize-delegate";
|
|
21
|
+
/** The longest a node will honour one delegation, however long the owner wrote. */
|
|
22
|
+
export declare const DELEGATION_MAX_MS: number;
|
|
23
|
+
/**
|
|
24
|
+
* Why delegation exists at all.
|
|
25
|
+
*
|
|
26
|
+
* A teaching key signs EVERY request. That is right for a key the browser holds and wrong for a key a wallet
|
|
27
|
+
* extension holds: `window.ainetwork.signMessage` is a user-facing prompt, so signing per request would put a
|
|
28
|
+
* confirmation dialog in front of every live test, every dataset page and every poll of a running lesson. The
|
|
29
|
+
* alternative people reach for — asking the extension for the private key — does not exist and should not.
|
|
30
|
+
*
|
|
31
|
+
* So the wallet signs ONCE, and what it signs is permission for a freshly generated browser key to act as that
|
|
32
|
+
* address. The browser key signs the requests, exactly as before; the delegation rides alongside and says whose
|
|
33
|
+
* they are.
|
|
34
|
+
*
|
|
35
|
+
* WHAT KEEPS IT HONEST, and each of these is checked in `verifyDelegation`:
|
|
36
|
+
*
|
|
37
|
+
* it names THIS node — a delegation shown to one node cannot be replayed at another.
|
|
38
|
+
* it names THAT key — a stolen delegation is inert without the browser key it authorises, and that key
|
|
39
|
+
* never leaves the browser.
|
|
40
|
+
* it expires — and the node caps the window at `DELEGATION_MAX_MS` no matter what the owner
|
|
41
|
+
* wrote, so one careless prompt cannot authorise a key for ever.
|
|
42
|
+
* the per-request proof is unchanged — the v2 signature still comes from the delegate key, so the replay
|
|
43
|
+
* cache, the route binding and the body binding all still apply.
|
|
44
|
+
*
|
|
45
|
+
* What it is NOT: a login. The node keeps no session, issues nothing, and forgets the delegation the moment the
|
|
46
|
+
* request ends. Two tabs, a CLI and a script can hold different delegate keys for the same owner at once — which
|
|
47
|
+
* is what makes several lessons under one identity possible, rather than a thing to be worked around.
|
|
48
|
+
*/
|
|
49
|
+
export declare function delegateMessage(t: {
|
|
50
|
+
node: string;
|
|
51
|
+
delegate: string;
|
|
52
|
+
expires: number;
|
|
53
|
+
}): string;
|
|
54
|
+
export interface Delegation {
|
|
55
|
+
owner: string;
|
|
56
|
+
expires: number;
|
|
57
|
+
signature: string;
|
|
58
|
+
}
|
|
59
|
+
/** Parse `x-ainize-delegate: <owner>:<expires>:<sig>`. Returns null on anything malformed. */
|
|
60
|
+
export declare function parseDelegation(header: string | undefined | null): Delegation | null;
|
|
61
|
+
/** The header an owner's wallet produces once, and every delegated request then carries unchanged. */
|
|
62
|
+
export declare function delegateHeader(d: Delegation): string;
|
|
63
|
+
/**
|
|
64
|
+
* The address a delegated request acts as, or null.
|
|
65
|
+
*
|
|
66
|
+
* `verify` is passed in rather than imported so this stays usable from the browser bundle, which verifies with
|
|
67
|
+
* `@noble/secp256k1` and must not pull `@ainblockchain/ain-util` in.
|
|
68
|
+
*/
|
|
69
|
+
export declare function verifyDelegation(header: string | undefined | null, ctx: {
|
|
70
|
+
node: string;
|
|
71
|
+
delegate: string;
|
|
72
|
+
now?: number;
|
|
73
|
+
maxMs?: number;
|
|
74
|
+
}, verify: (message: string, signature: string, address: string) => boolean): string | null;
|
|
19
75
|
//# sourceMappingURL=teach-auth.d.ts.map
|
package/dist/teach-auth.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"teach-auth.d.ts","sourceRoot":"","sources":["../src/teach-auth.ts"],"names":[],"mappings":"AAmBA,eAAO,MAAM,kBAAkB,QAAa,CAAC;AAC7C,eAAO,MAAM,aAAa,OAAO,CAAC;AAElC,MAAM,WAAW,eAAe;IAAG,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE;AAIpI,6IAA6I;AAC7I,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,eAAe,GAAG;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAI5E;AAED,0FAA0F;AAC1F,wBAAgB,kBAAkB,CAAC,GAAG,EAAE;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,EAAE,CAAC,EAAE,eAAe,EAAE,EAAE,SAAa,GAAG,MAAM,CAE5H"}
|
|
1
|
+
{"version":3,"file":"teach-auth.d.ts","sourceRoot":"","sources":["../src/teach-auth.ts"],"names":[],"mappings":"AAmBA,eAAO,MAAM,kBAAkB,QAAa,CAAC;AAC7C,eAAO,MAAM,aAAa,OAAO,CAAC;AAElC,MAAM,WAAW,eAAe;IAAG,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE;AAIpI,6IAA6I;AAC7I,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,eAAe,GAAG;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAI5E;AAED,0FAA0F;AAC1F,wBAAgB,kBAAkB,CAAC,GAAG,EAAE;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,EAAE,CAAC,EAAE,eAAe,EAAE,EAAE,SAAa,GAAG,MAAM,CAE5H;AAID,+EAA+E;AAC/E,eAAO,MAAM,eAAe,sBAAsB,CAAC;AACnD,mFAAmF;AACnF,eAAO,MAAM,iBAAiB,QAAmB,CAAC;AAElD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAE9F;AAED,MAAM,WAAW,UAAU;IAAG,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE;AAEjF,8FAA8F;AAC9F,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,UAAU,GAAG,IAAI,CAQpF;AAED,sGAAsG;AACtG,wBAAgB,cAAc,CAAC,CAAC,EAAE,UAAU,GAAG,MAAM,CAEpD;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,EACjC,GAAG,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,EACrE,MAAM,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,OAAO,GACvE,MAAM,GAAG,IAAI,CASf"}
|
package/dist/teach-auth.js
CHANGED
|
@@ -30,4 +30,75 @@ export function teachAuthMessage(t) {
|
|
|
30
30
|
export function teachAuthHeaderFor(key, t, ts = Date.now()) {
|
|
31
31
|
return `${key.address}:${ts}:${signMessage(teachAuthMessage({ ...t, ts }), key.privateKey)}:${TEACH_AUTH_V2}`;
|
|
32
32
|
}
|
|
33
|
+
// ------------------------------------------------------------------ delegation (AIN Wallet sign-in)
|
|
34
|
+
/** Header that carries the delegation, beside the ordinary `x-ainize-auth`. */
|
|
35
|
+
export const DELEGATE_HEADER = 'x-ainize-delegate';
|
|
36
|
+
/** The longest a node will honour one delegation, however long the owner wrote. */
|
|
37
|
+
export const DELEGATION_MAX_MS = 24 * 60 * 60_000;
|
|
38
|
+
/**
|
|
39
|
+
* Why delegation exists at all.
|
|
40
|
+
*
|
|
41
|
+
* A teaching key signs EVERY request. That is right for a key the browser holds and wrong for a key a wallet
|
|
42
|
+
* extension holds: `window.ainetwork.signMessage` is a user-facing prompt, so signing per request would put a
|
|
43
|
+
* confirmation dialog in front of every live test, every dataset page and every poll of a running lesson. The
|
|
44
|
+
* alternative people reach for — asking the extension for the private key — does not exist and should not.
|
|
45
|
+
*
|
|
46
|
+
* So the wallet signs ONCE, and what it signs is permission for a freshly generated browser key to act as that
|
|
47
|
+
* address. The browser key signs the requests, exactly as before; the delegation rides alongside and says whose
|
|
48
|
+
* they are.
|
|
49
|
+
*
|
|
50
|
+
* WHAT KEEPS IT HONEST, and each of these is checked in `verifyDelegation`:
|
|
51
|
+
*
|
|
52
|
+
* it names THIS node — a delegation shown to one node cannot be replayed at another.
|
|
53
|
+
* it names THAT key — a stolen delegation is inert without the browser key it authorises, and that key
|
|
54
|
+
* never leaves the browser.
|
|
55
|
+
* it expires — and the node caps the window at `DELEGATION_MAX_MS` no matter what the owner
|
|
56
|
+
* wrote, so one careless prompt cannot authorise a key for ever.
|
|
57
|
+
* the per-request proof is unchanged — the v2 signature still comes from the delegate key, so the replay
|
|
58
|
+
* cache, the route binding and the body binding all still apply.
|
|
59
|
+
*
|
|
60
|
+
* What it is NOT: a login. The node keeps no session, issues nothing, and forgets the delegation the moment the
|
|
61
|
+
* request ends. Two tabs, a CLI and a script can hold different delegate keys for the same owner at once — which
|
|
62
|
+
* is what makes several lessons under one identity possible, rather than a thing to be worked around.
|
|
63
|
+
*/
|
|
64
|
+
export function delegateMessage(t) {
|
|
65
|
+
return ['delegate', t.node, t.delegate.toLowerCase(), String(t.expires)].join(':');
|
|
66
|
+
}
|
|
67
|
+
/** Parse `x-ainize-delegate: <owner>:<expires>:<sig>`. Returns null on anything malformed. */
|
|
68
|
+
export function parseDelegation(header) {
|
|
69
|
+
if (!header)
|
|
70
|
+
return null;
|
|
71
|
+
const parts = header.split(':');
|
|
72
|
+
if (parts.length !== 3)
|
|
73
|
+
return null;
|
|
74
|
+
const [owner, expStr, signature] = parts;
|
|
75
|
+
const expires = Number(expStr);
|
|
76
|
+
if (!/^0x[0-9a-fA-F]{40}$/.test(owner ?? '') || !Number.isFinite(expires) || !signature)
|
|
77
|
+
return null;
|
|
78
|
+
return { owner, expires, signature };
|
|
79
|
+
}
|
|
80
|
+
/** The header an owner's wallet produces once, and every delegated request then carries unchanged. */
|
|
81
|
+
export function delegateHeader(d) {
|
|
82
|
+
return `${d.owner}:${d.expires}:${d.signature}`;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* The address a delegated request acts as, or null.
|
|
86
|
+
*
|
|
87
|
+
* `verify` is passed in rather than imported so this stays usable from the browser bundle, which verifies with
|
|
88
|
+
* `@noble/secp256k1` and must not pull `@ainblockchain/ain-util` in.
|
|
89
|
+
*/
|
|
90
|
+
export function verifyDelegation(header, ctx, verify) {
|
|
91
|
+
const d = parseDelegation(header);
|
|
92
|
+
if (!d)
|
|
93
|
+
return null;
|
|
94
|
+
const now = ctx.now ?? Date.now();
|
|
95
|
+
if (d.expires <= now)
|
|
96
|
+
return null;
|
|
97
|
+
if (d.expires - now > (ctx.maxMs ?? DELEGATION_MAX_MS))
|
|
98
|
+
return null;
|
|
99
|
+
if (d.owner.toLowerCase() === ctx.delegate.toLowerCase())
|
|
100
|
+
return null; // a key delegating to itself proves nothing
|
|
101
|
+
const message = delegateMessage({ node: ctx.node, delegate: ctx.delegate, expires: d.expires });
|
|
102
|
+
return verify(message, d.signature, d.owner) ? d.owner : null;
|
|
103
|
+
}
|
|
33
104
|
//# sourceMappingURL=teach-auth.js.map
|
package/dist/teach-auth.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"teach-auth.js","sourceRoot":"","sources":["../src/teach-auth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE5C,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,GAAG,MAAM,CAAC;AAC7C,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,CAAC;AAIlC,MAAM,MAAM,GAAG,CAAC,CAAsB,EAAE,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAExF,6IAA6I;AAC7I,MAAM,UAAU,gBAAgB,CAAC,CAAmC;IAClE,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,OAAO,IAAI,OAAO,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC3F,IAAI,CAAC,CAAC,IAAI,KAAK,SAAS,IAAI,CAAC,CAAC,IAAI,KAAK,IAAI,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC;QAAE,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IAC7F,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACzB,CAAC;AAED,0FAA0F;AAC1F,MAAM,UAAU,kBAAkB,CAAC,GAA4C,EAAE,CAAkB,EAAE,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE;IAClH,OAAO,GAAG,GAAG,CAAC,OAAO,IAAI,EAAE,IAAI,WAAW,CAAC,gBAAgB,CAAC,EAAE,GAAG,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,GAAG,CAAC,UAAU,CAAC,IAAI,aAAa,EAAE,CAAC;AAChH,CAAC"}
|
|
1
|
+
{"version":3,"file":"teach-auth.js","sourceRoot":"","sources":["../src/teach-auth.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED