@hivemagnus/ardent-studio 0.2.1 → 0.4.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 +7 -0
- package/dist/audit/export.d.ts +22 -0
- package/dist/audit/export.js +115 -0
- package/dist/auth/authenticator.d.ts +72 -0
- package/dist/auth/authenticator.js +88 -0
- package/dist/auth/links.d.ts +1 -0
- package/dist/clients/hivemem.d.ts +4 -4
- package/dist/clients/hivemem.js +57 -35
- package/dist/config.d.ts +2 -0
- package/dist/config.js +7 -1
- package/dist/db/repos/audit.d.ts +4 -0
- package/dist/db/repos/audit.js +16 -0
- package/dist/db/repos/team.d.ts +2 -0
- package/dist/db/repos/team.js +7 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/logger.d.ts +1 -1
- package/dist/logger.js +4 -2
- package/dist/server/app.js +6 -0
- package/dist/server/deps.d.ts +1 -1
- package/dist/server/env.d.ts +1 -1
- package/dist/server/errors.js +5 -0
- package/dist/server/routes/audit.d.ts +3 -0
- package/dist/server/routes/audit.js +6 -0
- package/dist/server/routes/health.js +41 -17
- package/dist/server/routes/projects.js +5 -0
- package/dist/server/routes/stream.js +1 -1
- package/dist/server/routing.d.ts +5 -2
- package/dist/server/routing.js +9 -6
- package/dist/service.d.ts +1 -1
- package/dist/service.js +2 -2
- package/dist/shared/browser.d.ts +87 -1
- package/dist/shared/browser.js +41 -1
- package/docs/openapi-browser.json +215 -2
- package/package.json +5 -3
- package/dist/auth/oathweave.d.ts +0 -46
- package/dist/auth/oathweave.js +0 -123
|
@@ -97,6 +97,15 @@
|
|
|
97
97
|
"false"
|
|
98
98
|
]
|
|
99
99
|
}
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
"in": "query",
|
|
103
|
+
"name": "agentRef",
|
|
104
|
+
"required": false,
|
|
105
|
+
"schema": {
|
|
106
|
+
"type": "string",
|
|
107
|
+
"pattern": "^[A-Za-z0-9._-]{1,128}~[A-Za-z0-9._-]{1,128}$"
|
|
108
|
+
}
|
|
100
109
|
}
|
|
101
110
|
],
|
|
102
111
|
"responses": {
|
|
@@ -130,7 +139,7 @@
|
|
|
130
139
|
"ardentstudio:projects:read"
|
|
131
140
|
],
|
|
132
141
|
"x-idempotent": false,
|
|
133
|
-
"description": "q matches name, brief and tags. needs_review=true keeps projects with review_pending > 0.",
|
|
142
|
+
"description": "q matches name, brief and tags. needs_review=true keeps projects with review_pending > 0. agentRef keeps projects where that agent is bound to a role in the published or the draft team; an agent with no roles gets an empty list. 400 VALIDATION_ERROR for a malformed agentRef.",
|
|
134
143
|
"security": [
|
|
135
144
|
{
|
|
136
145
|
"oathweave": []
|
|
@@ -5247,6 +5256,70 @@
|
|
|
5247
5256
|
]
|
|
5248
5257
|
}
|
|
5249
5258
|
},
|
|
5259
|
+
"/api/ardentstudio/v1/audit/export": {
|
|
5260
|
+
"get": {
|
|
5261
|
+
"operationId": "getAuditExport",
|
|
5262
|
+
"parameters": [
|
|
5263
|
+
{
|
|
5264
|
+
"in": "query",
|
|
5265
|
+
"name": "after",
|
|
5266
|
+
"required": false,
|
|
5267
|
+
"schema": {
|
|
5268
|
+
"type": "string",
|
|
5269
|
+
"maxLength": 512
|
|
5270
|
+
}
|
|
5271
|
+
},
|
|
5272
|
+
{
|
|
5273
|
+
"in": "query",
|
|
5274
|
+
"name": "limit",
|
|
5275
|
+
"required": false,
|
|
5276
|
+
"schema": {
|
|
5277
|
+
"type": "string",
|
|
5278
|
+
"pattern": "^\\d{1,6}$"
|
|
5279
|
+
}
|
|
5280
|
+
}
|
|
5281
|
+
],
|
|
5282
|
+
"responses": {
|
|
5283
|
+
"200": {
|
|
5284
|
+
"description": "Success",
|
|
5285
|
+
"content": {
|
|
5286
|
+
"application/json": {
|
|
5287
|
+
"schema": {
|
|
5288
|
+
"$ref": "#/components/schemas/AuditExportResponse"
|
|
5289
|
+
}
|
|
5290
|
+
}
|
|
5291
|
+
}
|
|
5292
|
+
},
|
|
5293
|
+
"400": {
|
|
5294
|
+
"$ref": "#/components/responses/Error"
|
|
5295
|
+
},
|
|
5296
|
+
"401": {
|
|
5297
|
+
"$ref": "#/components/responses/Error"
|
|
5298
|
+
},
|
|
5299
|
+
"403": {
|
|
5300
|
+
"$ref": "#/components/responses/Error"
|
|
5301
|
+
},
|
|
5302
|
+
"404": {
|
|
5303
|
+
"$ref": "#/components/responses/Error"
|
|
5304
|
+
},
|
|
5305
|
+
"409": {
|
|
5306
|
+
"$ref": "#/components/responses/Error"
|
|
5307
|
+
}
|
|
5308
|
+
},
|
|
5309
|
+
"x-permissions": [
|
|
5310
|
+
"ardentstudio:audit:read"
|
|
5311
|
+
],
|
|
5312
|
+
"x-idempotent": false,
|
|
5313
|
+
"x-or-permission": "ardentstudio:agents:admin",
|
|
5314
|
+
"x-accept": "any",
|
|
5315
|
+
"description": "Every audit record, oldest first, as HiveAuditRecord v1, keyset-paged on the record id. Accepts an Oathweave service token with ardentstudio:audit:read (no account link needed; native-issuer service tokens too when OATHWEAVE_NATIVE_ISSUERS lists the issuer), or a linked person with ardentstudio:audit:read or ardentstudio:agents:admin. 400 for a malformed cursor or limit. nextCursor is the last record's cursor whenever data is not empty, and null only when data is empty (caught up).",
|
|
5316
|
+
"security": [
|
|
5317
|
+
{
|
|
5318
|
+
"oathweave": []
|
|
5319
|
+
}
|
|
5320
|
+
]
|
|
5321
|
+
}
|
|
5322
|
+
},
|
|
5250
5323
|
"/api/ardentstudio/v1/projects/{projectId}/stream": {
|
|
5251
5324
|
"get": {
|
|
5252
5325
|
"operationId": "getProjectsProjectIdStream",
|
|
@@ -5329,7 +5402,7 @@
|
|
|
5329
5402
|
"type": "http",
|
|
5330
5403
|
"scheme": "bearer",
|
|
5331
5404
|
"bearerFormat": "JWT",
|
|
5332
|
-
"description": "Oathweave resource token with audience ardentstudio. Permissions: ardentstudio:projects:read, ardentstudio:projects:write, ardentstudio:templates:read, ardentstudio:templates:write, ardentstudio:review:write, ardentstudio:agents:admin."
|
|
5405
|
+
"description": "Oathweave resource token with audience ardentstudio. Permissions: ardentstudio:projects:read, ardentstudio:projects:write, ardentstudio:templates:read, ardentstudio:templates:write, ardentstudio:review:write, ardentstudio:agents:admin, ardentstudio:audit:read."
|
|
5333
5406
|
}
|
|
5334
5407
|
},
|
|
5335
5408
|
"responses": {
|
|
@@ -6399,6 +6472,27 @@
|
|
|
6399
6472
|
"knowledge"
|
|
6400
6473
|
]
|
|
6401
6474
|
},
|
|
6475
|
+
"AuditExportResponse": {
|
|
6476
|
+
"type": "object",
|
|
6477
|
+
"properties": {
|
|
6478
|
+
"data": {
|
|
6479
|
+
"type": "array",
|
|
6480
|
+
"items": {
|
|
6481
|
+
"$ref": "#/components/schemas/HiveAuditRecord"
|
|
6482
|
+
}
|
|
6483
|
+
},
|
|
6484
|
+
"nextCursor": {
|
|
6485
|
+
"type": [
|
|
6486
|
+
"string",
|
|
6487
|
+
"null"
|
|
6488
|
+
]
|
|
6489
|
+
}
|
|
6490
|
+
},
|
|
6491
|
+
"required": [
|
|
6492
|
+
"data",
|
|
6493
|
+
"nextCursor"
|
|
6494
|
+
]
|
|
6495
|
+
},
|
|
6402
6496
|
"AvatarPreset": {
|
|
6403
6497
|
"type": "object",
|
|
6404
6498
|
"properties": {
|
|
@@ -8100,6 +8194,125 @@
|
|
|
8100
8194
|
"at"
|
|
8101
8195
|
]
|
|
8102
8196
|
},
|
|
8197
|
+
"HiveAuditRecord": {
|
|
8198
|
+
"type": "object",
|
|
8199
|
+
"properties": {
|
|
8200
|
+
"id": {
|
|
8201
|
+
"type": "string",
|
|
8202
|
+
"pattern": "^(hivemem|hiveskills|ardentstudio|embermend):audit:[A-Za-z0-9._:-]{1,200}$"
|
|
8203
|
+
},
|
|
8204
|
+
"product": {
|
|
8205
|
+
"type": "string",
|
|
8206
|
+
"enum": [
|
|
8207
|
+
"hivemem",
|
|
8208
|
+
"hiveskills",
|
|
8209
|
+
"ardentstudio",
|
|
8210
|
+
"embermend"
|
|
8211
|
+
]
|
|
8212
|
+
},
|
|
8213
|
+
"occurredAt": {
|
|
8214
|
+
"type": "string",
|
|
8215
|
+
"format": "date-time",
|
|
8216
|
+
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"
|
|
8217
|
+
},
|
|
8218
|
+
"action": {
|
|
8219
|
+
"type": "string",
|
|
8220
|
+
"maxLength": 128,
|
|
8221
|
+
"pattern": "^[a-z][a-z0-9_]*(\\.[a-z][a-z0-9_]*)+$"
|
|
8222
|
+
},
|
|
8223
|
+
"outcome": {
|
|
8224
|
+
"type": "string",
|
|
8225
|
+
"enum": [
|
|
8226
|
+
"success",
|
|
8227
|
+
"failure"
|
|
8228
|
+
]
|
|
8229
|
+
},
|
|
8230
|
+
"actor": {
|
|
8231
|
+
"type": "object",
|
|
8232
|
+
"properties": {
|
|
8233
|
+
"type": {
|
|
8234
|
+
"type": "string",
|
|
8235
|
+
"enum": [
|
|
8236
|
+
"user",
|
|
8237
|
+
"service",
|
|
8238
|
+
"agent",
|
|
8239
|
+
"system"
|
|
8240
|
+
]
|
|
8241
|
+
},
|
|
8242
|
+
"id": {
|
|
8243
|
+
"type": "string",
|
|
8244
|
+
"minLength": 1,
|
|
8245
|
+
"maxLength": 256
|
|
8246
|
+
},
|
|
8247
|
+
"issuer": {
|
|
8248
|
+
"type": "string",
|
|
8249
|
+
"maxLength": 512
|
|
8250
|
+
},
|
|
8251
|
+
"displayName": {
|
|
8252
|
+
"type": "string",
|
|
8253
|
+
"maxLength": 256
|
|
8254
|
+
}
|
|
8255
|
+
},
|
|
8256
|
+
"required": [
|
|
8257
|
+
"type",
|
|
8258
|
+
"id"
|
|
8259
|
+
]
|
|
8260
|
+
},
|
|
8261
|
+
"target": {
|
|
8262
|
+
"type": "object",
|
|
8263
|
+
"properties": {
|
|
8264
|
+
"type": {
|
|
8265
|
+
"type": "string",
|
|
8266
|
+
"maxLength": 64
|
|
8267
|
+
},
|
|
8268
|
+
"id": {
|
|
8269
|
+
"type": "string",
|
|
8270
|
+
"maxLength": 256
|
|
8271
|
+
}
|
|
8272
|
+
}
|
|
8273
|
+
},
|
|
8274
|
+
"subject": {
|
|
8275
|
+
"type": "object",
|
|
8276
|
+
"properties": {
|
|
8277
|
+
"actorId": {
|
|
8278
|
+
"type": "string",
|
|
8279
|
+
"maxLength": 256
|
|
8280
|
+
},
|
|
8281
|
+
"agentRef": {
|
|
8282
|
+
"type": "string",
|
|
8283
|
+
"maxLength": 257
|
|
8284
|
+
},
|
|
8285
|
+
"nodeId": {
|
|
8286
|
+
"type": "string",
|
|
8287
|
+
"maxLength": 128
|
|
8288
|
+
}
|
|
8289
|
+
}
|
|
8290
|
+
},
|
|
8291
|
+
"details": {
|
|
8292
|
+
"type": "object",
|
|
8293
|
+
"propertyNames": {
|
|
8294
|
+
"type": "string"
|
|
8295
|
+
},
|
|
8296
|
+
"additionalProperties": {
|
|
8297
|
+
"type": [
|
|
8298
|
+
"string",
|
|
8299
|
+
"number",
|
|
8300
|
+
"boolean",
|
|
8301
|
+
"null"
|
|
8302
|
+
]
|
|
8303
|
+
}
|
|
8304
|
+
}
|
|
8305
|
+
},
|
|
8306
|
+
"required": [
|
|
8307
|
+
"id",
|
|
8308
|
+
"product",
|
|
8309
|
+
"occurredAt",
|
|
8310
|
+
"action",
|
|
8311
|
+
"outcome",
|
|
8312
|
+
"actor",
|
|
8313
|
+
"details"
|
|
8314
|
+
]
|
|
8315
|
+
},
|
|
8103
8316
|
"HivememState": {
|
|
8104
8317
|
"type": "string",
|
|
8105
8318
|
"enum": [
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hivemagnus/ardent-studio",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Ardent Project Studio service: projects, team assignment, conversation room and deliverable review for Ardent agents managed by Magnus",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ardent",
|
|
@@ -67,15 +67,17 @@
|
|
|
67
67
|
"verify": "npm run privacy:test && npm run scan:secrets && npm run check:private && npm run typecheck && npm run lint && npm test && npm run build && npm run check:contracts && npm run pack:check"
|
|
68
68
|
},
|
|
69
69
|
"dependencies": {
|
|
70
|
+
"@hivemagnus/hive-common": "^0.4.0",
|
|
71
|
+
"@hivemagnus/hivemem-sdk": "1.1.0",
|
|
70
72
|
"@hivemagnus/magnus-contracts": "2.2.0",
|
|
71
73
|
"@hono/node-server": "^2.1.5",
|
|
74
|
+
"@photostructure/sqlite": "3.3.1",
|
|
72
75
|
"fflate": "^0.8.3",
|
|
73
76
|
"hono": "^4.13.18",
|
|
74
77
|
"jose": "^6.2.15",
|
|
75
78
|
"pdfjs-dist": "^6.5.438",
|
|
76
79
|
"yaml": "2.9.1",
|
|
77
|
-
"zod": "^4.6.7"
|
|
78
|
-
"@photostructure/sqlite": "3.3.1"
|
|
80
|
+
"zod": "^4.6.7"
|
|
79
81
|
},
|
|
80
82
|
"devDependencies": {
|
|
81
83
|
"@apidevtools/swagger-parser": "^13.1.0",
|
package/dist/auth/oathweave.d.ts
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import { type JWTVerifyGetKey } from 'jose';
|
|
2
|
-
import { type ArdentStudioPermission } from '../shared/browser.js';
|
|
3
|
-
import { type IdentityLink } from './links.js';
|
|
4
|
-
export interface OathweaveOptions {
|
|
5
|
-
issuer: string;
|
|
6
|
-
jwksUrl: string;
|
|
7
|
-
userinfoUrl: string;
|
|
8
|
-
audience?: string;
|
|
9
|
-
}
|
|
10
|
-
export interface OathweaveIdentity {
|
|
11
|
-
subject: string;
|
|
12
|
-
issuer: string;
|
|
13
|
-
sessionId: string;
|
|
14
|
-
permissions: string[];
|
|
15
|
-
displayName: string;
|
|
16
|
-
issuedAt: number;
|
|
17
|
-
expiresAt: number;
|
|
18
|
-
}
|
|
19
|
-
export type OathweaveVerifier = (token: string) => Promise<OathweaveIdentity>;
|
|
20
|
-
/** A verified, linked caller. */
|
|
21
|
-
export interface Principal {
|
|
22
|
-
userId: string;
|
|
23
|
-
subject: string;
|
|
24
|
-
issuer: string;
|
|
25
|
-
displayName: string;
|
|
26
|
-
permissions: ArdentStudioPermission[];
|
|
27
|
-
/** Token expiry in epoch seconds. Streams close at this time. */
|
|
28
|
-
expiresAt: number;
|
|
29
|
-
}
|
|
30
|
-
/** The token is valid but its subject has no explicit link, so the person has no Studio access. */
|
|
31
|
-
export declare class AccessDenied extends Error {
|
|
32
|
-
name: string;
|
|
33
|
-
}
|
|
34
|
-
/** How long a userinfo answer is reused, measured from when the request started. */
|
|
35
|
-
export declare const SESSION_CACHE_TTL_MS = 10000;
|
|
36
|
-
/** How often an open stream re-checks its token. */
|
|
37
|
-
export declare const STREAM_RECHECK_MS = 5000;
|
|
38
|
-
export declare function isHttpsEndpoint(value: string): boolean;
|
|
39
|
-
export declare function createOathweaveVerifier(options: OathweaveOptions, overrides?: {
|
|
40
|
-
keys?: JWTVerifyGetKey;
|
|
41
|
-
fetch?: typeof fetch;
|
|
42
|
-
now?: () => number;
|
|
43
|
-
}): OathweaveVerifier;
|
|
44
|
-
export type Authenticator = (token: string) => Promise<Principal>;
|
|
45
|
-
/** Verify a bearer token and map it through its one explicit identity link. */
|
|
46
|
-
export declare function createAuthenticator(verify: OathweaveVerifier, links: readonly IdentityLink[]): Authenticator;
|
package/dist/auth/oathweave.js
DELETED
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
// Oathweave resource-token verification for ArdentStudio, following the suite pattern
|
|
2
|
-
// (Magnus and HiveMem): RS256 only, exact issuer and audience, at most fifteen minutes,
|
|
3
|
-
// USER actor with a session, and an online session check through userinfo. Failure is closed.
|
|
4
|
-
import { createHash } from 'node:crypto';
|
|
5
|
-
import { createRemoteJWKSet, customFetch, jwtVerify } from 'jose';
|
|
6
|
-
import { ARDENT_STUDIO_AUDIENCE } from '../shared/browser.js';
|
|
7
|
-
import { effectivePermissions, linkFor } from './links.js';
|
|
8
|
-
/** The token is valid but its subject has no explicit link, so the person has no Studio access. */
|
|
9
|
-
export class AccessDenied extends Error {
|
|
10
|
-
name = 'AccessDenied';
|
|
11
|
-
}
|
|
12
|
-
/** How long a userinfo answer is reused, measured from when the request started. */
|
|
13
|
-
export const SESSION_CACHE_TTL_MS = 10_000;
|
|
14
|
-
/** How often an open stream re-checks its token. */
|
|
15
|
-
export const STREAM_RECHECK_MS = 5_000;
|
|
16
|
-
const FAILED_CHECK_TTL_MS = 2_000;
|
|
17
|
-
const SESSION_CACHE_MAX = 5_000;
|
|
18
|
-
const REQUEST_TIMEOUT_MS = 3_000;
|
|
19
|
-
export function isHttpsEndpoint(value) {
|
|
20
|
-
try {
|
|
21
|
-
const url = new URL(value);
|
|
22
|
-
return url.protocol === 'https:' && !url.username && !url.password && !url.hash;
|
|
23
|
-
}
|
|
24
|
-
catch {
|
|
25
|
-
return false;
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
export function createOathweaveVerifier(options, overrides = {}) {
|
|
29
|
-
for (const value of [options.issuer, options.jwksUrl, options.userinfoUrl]) {
|
|
30
|
-
if (!isHttpsEndpoint(value))
|
|
31
|
-
throw new Error('Oathweave endpoints require verified HTTPS');
|
|
32
|
-
}
|
|
33
|
-
const audience = options.audience ?? ARDENT_STUDIO_AUDIENCE;
|
|
34
|
-
const request = overrides.fetch ?? ((input, init) => fetch(input, init));
|
|
35
|
-
const now = overrides.now ?? (() => Date.now());
|
|
36
|
-
const keys = overrides.keys ?? createRemoteJWKSet(new URL(options.jwksUrl), {
|
|
37
|
-
[customFetch]: (url, init) => request(url, { ...init, redirect: 'error', signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS) }),
|
|
38
|
-
});
|
|
39
|
-
// Holds only tokens whose signature verified, so garbage can neither fill it nor reach userinfo.
|
|
40
|
-
const sessions = new Map();
|
|
41
|
-
async function fetchDisplayName(token, subject) {
|
|
42
|
-
const result = await request(options.userinfoUrl, {
|
|
43
|
-
headers: { Authorization: `Bearer ${token}` },
|
|
44
|
-
redirect: 'error',
|
|
45
|
-
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
|
|
46
|
-
});
|
|
47
|
-
if (!result.ok)
|
|
48
|
-
throw new Error('Identity session is inactive');
|
|
49
|
-
const user = await result.json();
|
|
50
|
-
if (!user || typeof user !== 'object' || user.sub !== subject)
|
|
51
|
-
throw new Error('Identity subject mismatch');
|
|
52
|
-
return 'name' in user && typeof user.name === 'string' && user.name ? user.name : subject;
|
|
53
|
-
}
|
|
54
|
-
function sessionCheck(token, subject) {
|
|
55
|
-
const key = createHash('sha256').update(token).digest('hex');
|
|
56
|
-
const startedAt = now();
|
|
57
|
-
const current = sessions.get(key);
|
|
58
|
-
if (current && startedAt < current.expiresAt)
|
|
59
|
-
return current.displayName;
|
|
60
|
-
sessions.delete(key);
|
|
61
|
-
if (sessions.size >= SESSION_CACHE_MAX) {
|
|
62
|
-
for (const [entryKey, entry] of sessions)
|
|
63
|
-
if (entry.expiresAt <= startedAt)
|
|
64
|
-
sessions.delete(entryKey);
|
|
65
|
-
if (sessions.size >= SESSION_CACHE_MAX)
|
|
66
|
-
sessions.delete(sessions.keys().next().value);
|
|
67
|
-
}
|
|
68
|
-
const check = { expiresAt: startedAt + SESSION_CACHE_TTL_MS, displayName: fetchDisplayName(token, subject) };
|
|
69
|
-
check.displayName.catch(() => { check.expiresAt = Math.min(check.expiresAt, now() + FAILED_CHECK_TTL_MS); });
|
|
70
|
-
sessions.set(key, check);
|
|
71
|
-
return check.displayName;
|
|
72
|
-
}
|
|
73
|
-
return async (token) => {
|
|
74
|
-
const { payload } = await jwtVerify(token, keys, {
|
|
75
|
-
algorithms: ['RS256'],
|
|
76
|
-
issuer: options.issuer,
|
|
77
|
-
audience,
|
|
78
|
-
requiredClaims: ['sub', 'iat', 'exp', 'jti'],
|
|
79
|
-
maxTokenAge: '15m',
|
|
80
|
-
currentDate: new Date(now()),
|
|
81
|
-
});
|
|
82
|
-
if (payload.aud !== audience || typeof payload.iat !== 'number' || typeof payload.exp !== 'number'
|
|
83
|
-
|| payload.exp <= payload.iat || payload.exp - payload.iat > 900) {
|
|
84
|
-
throw new Error('Invalid resource token audience or lifetime');
|
|
85
|
-
}
|
|
86
|
-
const claims = payload;
|
|
87
|
-
if (claims['actorType'] !== 'USER'
|
|
88
|
-
|| typeof payload.sub !== 'string' || !payload.sub
|
|
89
|
-
|| typeof payload.jti !== 'string' || !payload.jti
|
|
90
|
-
|| typeof claims['sessionId'] !== 'string' || !claims['sessionId']
|
|
91
|
-
|| typeof claims['clientId'] !== 'string'
|
|
92
|
-
|| !Array.isArray(claims['permissions']) || !claims['permissions'].every(value => typeof value === 'string')) {
|
|
93
|
-
throw new Error('Invalid resource identity');
|
|
94
|
-
}
|
|
95
|
-
const displayName = await sessionCheck(token, payload.sub);
|
|
96
|
-
return {
|
|
97
|
-
subject: payload.sub,
|
|
98
|
-
issuer: options.issuer,
|
|
99
|
-
sessionId: claims['sessionId'],
|
|
100
|
-
permissions: claims['permissions'],
|
|
101
|
-
displayName,
|
|
102
|
-
issuedAt: payload.iat,
|
|
103
|
-
expiresAt: payload.exp,
|
|
104
|
-
};
|
|
105
|
-
};
|
|
106
|
-
}
|
|
107
|
-
/** Verify a bearer token and map it through its one explicit identity link. */
|
|
108
|
-
export function createAuthenticator(verify, links) {
|
|
109
|
-
return async (token) => {
|
|
110
|
-
const identity = await verify(token);
|
|
111
|
-
const link = linkFor(links, identity.issuer, identity.subject);
|
|
112
|
-
if (!link)
|
|
113
|
-
throw new AccessDenied('An explicit unique account link is required');
|
|
114
|
-
return {
|
|
115
|
-
userId: link.localUserId,
|
|
116
|
-
subject: identity.subject,
|
|
117
|
-
issuer: identity.issuer,
|
|
118
|
-
displayName: link.displayName ?? identity.displayName,
|
|
119
|
-
permissions: effectivePermissions(link, identity.permissions),
|
|
120
|
-
expiresAt: identity.expiresAt,
|
|
121
|
-
};
|
|
122
|
-
};
|
|
123
|
-
}
|