@tumbaland/backend-core 1.37.0 → 1.39.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/apiKeys/ApiKey.d.ts +23 -3
- package/dist/apiKeys/ApiKey.d.ts.map +1 -1
- package/dist/apiKeys/ApiKey.js +19 -2
- package/dist/apiKeys/ApiKey.js.map +1 -1
- package/dist/apiKeys/index.d.ts +2 -2
- package/dist/apiKeys/index.d.ts.map +1 -1
- package/dist/apiKeys/index.js +5 -1
- package/dist/apiKeys/index.js.map +1 -1
- package/dist/apiKeys/middleware.d.ts +17 -3
- package/dist/apiKeys/middleware.d.ts.map +1 -1
- package/dist/apiKeys/middleware.js +71 -34
- package/dist/apiKeys/middleware.js.map +1 -1
- package/dist/apiKeys/service.d.ts +5 -3
- package/dist/apiKeys/service.d.ts.map +1 -1
- package/dist/apiKeys/service.js +11 -3
- package/dist/apiKeys/service.js.map +1 -1
- package/dist/apiKeys/types.d.ts +43 -8
- package/dist/apiKeys/types.d.ts.map +1 -1
- package/dist/apiKeys/types.js +35 -1
- package/dist/apiKeys/types.js.map +1 -1
- package/dist/audit/AuditEvent.d.ts +51 -0
- package/dist/audit/AuditEvent.d.ts.map +1 -0
- package/dist/audit/AuditEvent.js +69 -0
- package/dist/audit/AuditEvent.js.map +1 -0
- package/dist/audit/actor.d.ts +41 -0
- package/dist/audit/actor.d.ts.map +1 -0
- package/dist/audit/actor.js +39 -0
- package/dist/audit/actor.js.map +1 -0
- package/dist/audit/context.d.ts +40 -0
- package/dist/audit/context.d.ts.map +1 -0
- package/dist/audit/context.js +60 -0
- package/dist/audit/context.js.map +1 -0
- package/dist/audit/index.d.ts +12 -0
- package/dist/audit/index.d.ts.map +1 -0
- package/dist/audit/index.js +22 -0
- package/dist/audit/index.js.map +1 -0
- package/dist/audit/plugin.d.ts +23 -0
- package/dist/audit/plugin.d.ts.map +1 -0
- package/dist/audit/plugin.js +226 -0
- package/dist/audit/plugin.js.map +1 -0
- package/dist/audit/reads.d.ts +47 -0
- package/dist/audit/reads.d.ts.map +1 -0
- package/dist/audit/reads.js +94 -0
- package/dist/audit/reads.js.map +1 -0
- package/dist/audit/service.d.ts +49 -0
- package/dist/audit/service.d.ts.map +1 -0
- package/dist/audit/service.js +65 -0
- package/dist/audit/service.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/oauth/models.d.ts +13 -2
- package/dist/oauth/models.d.ts.map +1 -1
- package/dist/oauth/models.js +19 -0
- package/dist/oauth/models.js.map +1 -1
- package/dist/oauth/service.d.ts +15 -8
- package/dist/oauth/service.d.ts.map +1 -1
- package/dist/oauth/service.js +10 -3
- package/dist/oauth/service.js.map +1 -1
- package/dist/oauth/tokens.d.ts +37 -5
- package/dist/oauth/tokens.d.ts.map +1 -1
- package/dist/oauth/tokens.js +9 -2
- package/dist/oauth/tokens.js.map +1 -1
- package/package.json +1 -1
- package/src/apiKeys/ApiKey.test.ts +25 -1
- package/src/apiKeys/ApiKey.ts +31 -4
- package/src/apiKeys/index.ts +16 -2
- package/src/apiKeys/middleware.test.ts +126 -20
- package/src/apiKeys/middleware.ts +99 -39
- package/src/apiKeys/service.test.ts +58 -9
- package/src/apiKeys/service.ts +25 -6
- package/src/apiKeys/types.ts +63 -8
- package/src/audit/AuditEvent.ts +79 -0
- package/src/audit/actor.test.ts +95 -0
- package/src/audit/actor.ts +68 -0
- package/src/audit/context.test.ts +91 -0
- package/src/audit/context.ts +83 -0
- package/src/audit/index.ts +11 -0
- package/src/audit/plugin.test.ts +258 -0
- package/src/audit/plugin.ts +254 -0
- package/src/audit/reads.test.ts +164 -0
- package/src/audit/reads.ts +88 -0
- package/src/audit/service.test.ts +115 -0
- package/src/audit/service.ts +92 -0
- package/src/index.ts +1 -0
- package/src/middleware/authMiddleware.test.ts +6 -1
- package/src/oauth/models.ts +32 -2
- package/src/oauth/service.test.ts +58 -6
- package/src/oauth/service.ts +25 -7
- package/src/oauth/tokens.test.ts +22 -5
- package/src/oauth/tokens.ts +52 -7
package/dist/oauth/models.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"models.js","sourceRoot":"","sources":["../../src/oauth/models.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,qDAAsD;
|
|
1
|
+
{"version":3,"file":"models.js","sourceRoot":"","sources":["../../src/oauth/models.ts"],"names":[],"mappings":"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"}
|
package/dist/oauth/service.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { IAuthorizationCode } from './models';
|
|
2
|
-
import type
|
|
2
|
+
import { type ApiKeyScope, type ApiKeyTenant, type Tenant } from '../apiKeys/types';
|
|
3
3
|
export interface RegisterClientInput {
|
|
4
4
|
clientName: string;
|
|
5
5
|
redirectUris: string[];
|
|
@@ -54,7 +54,9 @@ export interface IssueCodeInput {
|
|
|
54
54
|
userName: string;
|
|
55
55
|
redirectUri: string;
|
|
56
56
|
scopes: ApiKeyScope[];
|
|
57
|
-
|
|
57
|
+
tenants: Tenant[];
|
|
58
|
+
defaultTenant: Tenant;
|
|
59
|
+
tenantNames: Record<Tenant, string>;
|
|
58
60
|
resource: string;
|
|
59
61
|
codeChallenge: string;
|
|
60
62
|
}
|
|
@@ -87,7 +89,9 @@ export declare const issueRefreshToken: (input: {
|
|
|
87
89
|
clientId: string;
|
|
88
90
|
userId: string;
|
|
89
91
|
scopes: ApiKeyScope[];
|
|
90
|
-
|
|
92
|
+
tenants: Tenant[];
|
|
93
|
+
defaultTenant: Tenant;
|
|
94
|
+
tenantNames: Record<Tenant, string>;
|
|
91
95
|
resource: string;
|
|
92
96
|
}) => Promise<IssuedRefreshToken>;
|
|
93
97
|
export interface RefreshRedemption {
|
|
@@ -96,7 +100,8 @@ export interface RefreshRedemption {
|
|
|
96
100
|
reused?: boolean;
|
|
97
101
|
userId?: string;
|
|
98
102
|
scopes?: ApiKeyScope[];
|
|
99
|
-
|
|
103
|
+
tenants?: ApiKeyTenant;
|
|
104
|
+
tenantNames?: Record<Tenant, string>;
|
|
100
105
|
resource?: string;
|
|
101
106
|
/** the replacement the client must store; the presented one is now dead */
|
|
102
107
|
rotatedToken?: string;
|
|
@@ -120,13 +125,15 @@ export declare const redeemRefreshToken: (token: string, clientId: string) => Pr
|
|
|
120
125
|
/** Cut off an assistant: without a refresh token it can obtain nothing new. */
|
|
121
126
|
export declare const revokeRefreshTokensForUser: (userId: string, clientId?: string) => Promise<number>;
|
|
122
127
|
export declare const listConnections: (userId: string) => Promise<{
|
|
128
|
+
tenantNames: Record<string, string>;
|
|
129
|
+
createdAt: string;
|
|
130
|
+
lastRenewedAt: string | null;
|
|
131
|
+
revokedAt: string | null;
|
|
132
|
+
tenants: string[];
|
|
133
|
+
defaultTenant: string;
|
|
123
134
|
id: string;
|
|
124
135
|
clientId: string;
|
|
125
136
|
clientName: string;
|
|
126
137
|
scopes: string[];
|
|
127
|
-
groupId: string | null;
|
|
128
|
-
createdAt: string;
|
|
129
|
-
lastRenewedAt: string | null;
|
|
130
|
-
revokedAt: string | null;
|
|
131
138
|
}[]>;
|
|
132
139
|
//# sourceMappingURL=service.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/oauth/service.ts"],"names":[],"mappings":"AACA,OAAO,EAAqB,kBAAkB,EAA6B,MAAM,UAAU,CAAC;AAC5F,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/oauth/service.ts"],"names":[],"mappings":"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"}
|
package/dist/oauth/service.js
CHANGED
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.listConnections = exports.revokeRefreshTokensForUser = exports.redeemRefreshToken = exports.issueRefreshToken = exports.redeemAuthorizationCode = exports.issueAuthorizationCode = exports.isRegisteredRedirect = exports.findClient = exports.registerClient = void 0;
|
|
4
4
|
const crypto_1 = require("crypto");
|
|
5
5
|
const models_1 = require("./models");
|
|
6
|
+
const types_1 = require("../apiKeys/types");
|
|
6
7
|
/** How long a user has between approving and the client exchanging the code. */
|
|
7
8
|
const CODE_TTL_MS = 60 * 1000;
|
|
8
9
|
const sha256 = (value) => (0, crypto_1.createHash)('sha256').update(value).digest('hex');
|
|
@@ -143,7 +144,11 @@ const redeemRefreshToken = async (token, clientId) => {
|
|
|
143
144
|
clientId,
|
|
144
145
|
userId: record.userId,
|
|
145
146
|
scopes: record.scopes,
|
|
146
|
-
|
|
147
|
+
// Carried, not reset: rotation reissues the same grant, and re-deriving the
|
|
148
|
+
// tenants would quietly narrow a connection every time it refreshed.
|
|
149
|
+
tenants: record.tenants,
|
|
150
|
+
defaultTenant: record.defaultTenant,
|
|
151
|
+
tenantNames: record.tenantNames,
|
|
147
152
|
resource: record.resource,
|
|
148
153
|
// Carried, not reset: this is still the grant the user approved.
|
|
149
154
|
grantedAt: record.grantedAt ?? record.createdAt
|
|
@@ -152,7 +157,8 @@ const redeemRefreshToken = async (token, clientId) => {
|
|
|
152
157
|
ok: true,
|
|
153
158
|
userId: record.userId,
|
|
154
159
|
scopes: record.scopes,
|
|
155
|
-
|
|
160
|
+
tenants: (0, types_1.readTenants)(record),
|
|
161
|
+
tenantNames: record.tenantNames ?? {},
|
|
156
162
|
resource: record.resource,
|
|
157
163
|
rotatedToken: rotated
|
|
158
164
|
};
|
|
@@ -176,7 +182,8 @@ const listConnections = async (userId) => {
|
|
|
176
182
|
clientId: token.clientId,
|
|
177
183
|
clientName: nameById.get(token.clientId) ?? 'Unknown app',
|
|
178
184
|
scopes: token.scopes,
|
|
179
|
-
|
|
185
|
+
...(({ allowed, default: fallback }) => ({ tenants: allowed, defaultTenant: fallback }))((0, types_1.readTenants)(token)),
|
|
186
|
+
tenantNames: token.tenantNames ?? {},
|
|
180
187
|
createdAt: (token.grantedAt ?? token.createdAt).toISOString(),
|
|
181
188
|
// Set when the refresh token is exchanged, not when a tool runs — access
|
|
182
189
|
// tokens are validated statelessly, so the server never sees ordinary use.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.js","sourceRoot":"","sources":["../../src/oauth/service.ts"],"names":[],"mappings":";;;AAAA,mCAAkE;AAClE,qCAA4F;
|
|
1
|
+
{"version":3,"file":"service.js","sourceRoot":"","sources":["../../src/oauth/service.ts"],"names":[],"mappings":"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"}
|
package/dist/oauth/tokens.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type ApiKeyScope } from '../apiKeys/types';
|
|
1
|
+
import { type ApiKeyScope, type ApiKeyTenant, type Tenant } from '../apiKeys/types';
|
|
2
2
|
/**
|
|
3
3
|
* Access tokens for the OAuth flow that lets an assistant connect to Tumbaland.
|
|
4
4
|
*
|
|
@@ -18,8 +18,33 @@ export interface AccessTokenClaims {
|
|
|
18
18
|
aud: string;
|
|
19
19
|
iss: string;
|
|
20
20
|
scope: string;
|
|
21
|
-
/**
|
|
22
|
-
|
|
21
|
+
/** every tenant this token may act in */
|
|
22
|
+
tenants: Tenant[];
|
|
23
|
+
/** the one it acts in when a call names none */
|
|
24
|
+
defaultTenant: Tenant;
|
|
25
|
+
/**
|
|
26
|
+
* What each tenant is called, for a client that has to offer the choice.
|
|
27
|
+
*
|
|
28
|
+
* Carried on the token because the only place these names are known is the
|
|
29
|
+
* consent screen that rendered them, and the MCP server — which has to name
|
|
30
|
+
* the choice to a model — cannot reach group-service. A snapshot: a group
|
|
31
|
+
* renamed after the connection was made shows its old name until reconnect,
|
|
32
|
+
* which is the same trade the owner's name on an API key already makes.
|
|
33
|
+
*/
|
|
34
|
+
tenantNames: Record<Tenant, string>;
|
|
35
|
+
/** the single tenant an older token was pinned to; read by `readTenants` */
|
|
36
|
+
groupId?: string | null;
|
|
37
|
+
/**
|
|
38
|
+
* Which app this token was issued to.
|
|
39
|
+
*
|
|
40
|
+
* `jti` identifies the token and rotates every hour, so it cannot stand in for
|
|
41
|
+
* the connection — an audit trail built on it would show a different actor
|
|
42
|
+
* each time the assistant refreshed. The client id is stable for the life of
|
|
43
|
+
* the grant, and the name is snapshotted alongside it for the same reason the
|
|
44
|
+
* tenant names are: nothing downstream can look it up.
|
|
45
|
+
*/
|
|
46
|
+
clientId: string;
|
|
47
|
+
clientName: string;
|
|
23
48
|
email: string;
|
|
24
49
|
name: string;
|
|
25
50
|
typ: typeof ACCESS_TOKEN_TYPE;
|
|
@@ -35,7 +60,11 @@ export interface MintAccessTokenInput {
|
|
|
35
60
|
resource: string;
|
|
36
61
|
issuer: string;
|
|
37
62
|
scopes: ApiKeyScope[];
|
|
38
|
-
|
|
63
|
+
tenants: Tenant[];
|
|
64
|
+
defaultTenant: Tenant;
|
|
65
|
+
tenantNames: Record<Tenant, string>;
|
|
66
|
+
clientId: string;
|
|
67
|
+
clientName: string;
|
|
39
68
|
}
|
|
40
69
|
export interface MintedAccessToken {
|
|
41
70
|
accessToken: string;
|
|
@@ -50,7 +79,10 @@ export interface AccessTokenVerification {
|
|
|
50
79
|
email?: string;
|
|
51
80
|
name?: string;
|
|
52
81
|
scopes?: ApiKeyScope[];
|
|
53
|
-
|
|
82
|
+
tenants?: ApiKeyTenant;
|
|
83
|
+
tenantNames?: Record<Tenant, string>;
|
|
84
|
+
clientId?: string;
|
|
85
|
+
clientName?: string;
|
|
54
86
|
}
|
|
55
87
|
/**
|
|
56
88
|
* Check a bearer token presented to the MCP server.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../../src/oauth/tokens.ts"],"names":[],"mappings":"AAGA,OAAO,
|
|
1
|
+
{"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../../src/oauth/tokens.ts"],"names":[],"mappings":"AAGA,OAAO,EAGL,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,MAAM,EACZ,MAAM,kBAAkB,CAAC;AAE1B;;;;;;;;;GASG;AAEH,oFAAoF;AACpF,eAAO,MAAM,iBAAiB,eAAe,CAAC;AAK9C,MAAM,WAAW,iBAAiB;IAChC,2CAA2C;IAC3C,GAAG,EAAE,MAAM,CAAC;IACZ,gFAAgF;IAChF,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,yCAAyC;IACzC,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,gDAAgD;IAChD,aAAa,EAAE,MAAM,CAAC;IACtB;;;;;;;;OAQG;IACH,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,4EAA4E;IAC5E,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB;;;;;;;;OAQG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,OAAO,iBAAiB,CAAC;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,2DAA2D;IAC3D,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,eAAO,MAAM,eAAe,GAAI,OAAO,oBAAoB,KAAG,iBAwB7D,CAAC;AAEF,MAAM,WAAW,uBAAuB;IACtC,EAAE,EAAE,OAAO,CAAC;IACZ,SAAS,CAAC,EAAE,WAAW,GAAG,SAAS,GAAG,gBAAgB,GAAG,YAAY,GAAG,eAAe,CAAC;IACxF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,WAAW,EAAE,CAAC;IACvB,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,iBAAiB,GAC5B,OAAO,MAAM,EACb,kBAAkB,MAAM,KACvB,uBAwBF,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,mBAAmB,GAAI,QAAQ,OAAO,KAAG,MAAM,IAAI,iBAGP,CAAC;AAE1D,qFAAqF;AACrF,eAAO,MAAM,WAAW,GAAI,OAAO,OAAO,KAAG,WAAW,EACmB,CAAC"}
|
package/dist/oauth/tokens.js
CHANGED
|
@@ -29,7 +29,11 @@ const mintAccessToken = (input) => {
|
|
|
29
29
|
aud: input.resource,
|
|
30
30
|
iss: input.issuer,
|
|
31
31
|
scope,
|
|
32
|
-
|
|
32
|
+
tenants: input.tenants,
|
|
33
|
+
defaultTenant: input.defaultTenant,
|
|
34
|
+
tenantNames: input.tenantNames,
|
|
35
|
+
clientId: input.clientId,
|
|
36
|
+
clientName: input.clientName,
|
|
33
37
|
email: input.email,
|
|
34
38
|
name: input.name,
|
|
35
39
|
typ: exports.ACCESS_TOKEN_TYPE,
|
|
@@ -69,7 +73,10 @@ const verifyAccessToken = (token, expectedAudience) => {
|
|
|
69
73
|
email: claims.email ?? '',
|
|
70
74
|
name: claims.name ?? '',
|
|
71
75
|
scopes: (claims.scope ?? '').split(' ').filter(types_1.isApiKeyScope),
|
|
72
|
-
|
|
76
|
+
tenants: (0, types_1.readTenants)(claims),
|
|
77
|
+
tenantNames: claims.tenantNames ?? {},
|
|
78
|
+
clientId: claims.clientId,
|
|
79
|
+
clientName: claims.clientName
|
|
73
80
|
};
|
|
74
81
|
};
|
|
75
82
|
exports.verifyAccessToken = verifyAccessToken;
|
package/dist/oauth/tokens.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tokens.js","sourceRoot":"","sources":["../../src/oauth/tokens.ts"],"names":[],"mappings":";;;;;;AAAA,mCAAoC;AACpC,gEAA+B;AAC/B,uCAA2C;AAC3C,
|
|
1
|
+
{"version":3,"file":"tokens.js","sourceRoot":"","sources":["../../src/oauth/tokens.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ApiKey } from './ApiKey';
|
|
1
|
+
import { ApiKey, API_KEY_SECRET_FIELDS } from './ApiKey';
|
|
2
2
|
|
|
3
3
|
/** The fields the schema insists on, so each test only varies what it is about. */
|
|
4
4
|
const complete = {
|
|
@@ -116,3 +116,27 @@ describe('model registration', () => {
|
|
|
116
116
|
expect(again).toBe(ApiKey);
|
|
117
117
|
});
|
|
118
118
|
});
|
|
119
|
+
|
|
120
|
+
describe('what a key’s audit trail may carry', () => {
|
|
121
|
+
/**
|
|
122
|
+
* The trail is readable by the account owner and kept for a year. A snapshot
|
|
123
|
+
* carrying the hash or the sealed ciphertext would copy credential material
|
|
124
|
+
* into a second collection with a different lifetime — which is exactly what
|
|
125
|
+
* the encryption exists to prevent.
|
|
126
|
+
*/
|
|
127
|
+
it('redacts every field on the schema that holds a secret', () => {
|
|
128
|
+
const secretish = Object.keys(ApiKey.schema.paths).filter((path) =>
|
|
129
|
+
/hash|sealed|secret/i.test(path)
|
|
130
|
+
);
|
|
131
|
+
|
|
132
|
+
// Compared against the schema rather than a hand-written list, so a secret
|
|
133
|
+
// field added later fails here instead of quietly reaching the trail.
|
|
134
|
+
expect(secretish.sort()).toEqual([...API_KEY_SECRET_FIELDS].sort());
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
it('keeps the fields that make a row worth reading', () => {
|
|
138
|
+
for (const field of ['name', 'scopes', 'tenants', 'revokedAt']) {
|
|
139
|
+
expect(API_KEY_SECRET_FIELDS).not.toContain(field);
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
});
|
package/src/apiKeys/ApiKey.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import mongoose, { Document, Schema } from 'mongoose';
|
|
2
|
-
import
|
|
2
|
+
import { auditPlugin } from '../audit/plugin';
|
|
3
|
+
import { PERSONAL_TENANT, type ApiKeyScope, type Tenant } from './types';
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* One API key. Lives in backend-core rather than auth-service because both
|
|
@@ -31,8 +32,17 @@ export interface IApiKey extends Document {
|
|
|
31
32
|
sealedIv: string;
|
|
32
33
|
sealedTag: string;
|
|
33
34
|
scopes: ApiKeyScope[];
|
|
34
|
-
/**
|
|
35
|
-
|
|
35
|
+
/** every tenant this key may act in; see `Tenant` */
|
|
36
|
+
tenants: Tenant[];
|
|
37
|
+
/** the one it acts in when a request names none; always a member of `tenants` */
|
|
38
|
+
defaultTenant: Tenant;
|
|
39
|
+
/**
|
|
40
|
+
* The single tenant this key was pinned to, before tenants were a set.
|
|
41
|
+
*
|
|
42
|
+
* Kept so keys issued under the old model keep working; `readTenants` falls
|
|
43
|
+
* back to it. Nothing writes it any more.
|
|
44
|
+
*/
|
|
45
|
+
groupId?: string | null;
|
|
36
46
|
lastUsedAt?: Date;
|
|
37
47
|
expiresAt?: Date;
|
|
38
48
|
revokedAt?: Date;
|
|
@@ -55,8 +65,11 @@ const ApiKeySchema = new Schema<IApiKey>(
|
|
|
55
65
|
sealedIv: { type: String, required: true },
|
|
56
66
|
sealedTag: { type: String, required: true },
|
|
57
67
|
scopes: { type: [String], default: [] },
|
|
58
|
-
//
|
|
68
|
+
// Defaulted rather than optional: which data a key reaches is a decision the
|
|
59
69
|
// creator made, and it must not be indistinguishable from a field nobody set.
|
|
70
|
+
tenants: { type: [String], default: () => [PERSONAL_TENANT] },
|
|
71
|
+
defaultTenant: { type: String, default: PERSONAL_TENANT },
|
|
72
|
+
// Written by the single-tenant model this replaced; read-only now.
|
|
60
73
|
groupId: { type: String, default: null },
|
|
61
74
|
lastUsedAt: { type: Date },
|
|
62
75
|
expiresAt: { type: Date },
|
|
@@ -70,6 +83,20 @@ const ApiKeySchema = new Schema<IApiKey>(
|
|
|
70
83
|
// Every listing is one user's keys, newest first.
|
|
71
84
|
ApiKeySchema.index({ userId: 1, createdAt: -1 });
|
|
72
85
|
|
|
86
|
+
/**
|
|
87
|
+
* Issuing and revoking a key is worth a record — arguably more than anything a
|
|
88
|
+
* key goes on to do, since a credential nobody remembers creating is the one
|
|
89
|
+
* that matters.
|
|
90
|
+
*
|
|
91
|
+
* Every secret-bearing field is redacted. The trail is readable by the account
|
|
92
|
+
* owner and kept for a year; a snapshot carrying `hash` or the sealed
|
|
93
|
+
* ciphertext would put credential material into a second collection with a
|
|
94
|
+
* different lifetime, which is precisely the thing the encryption is for.
|
|
95
|
+
*/
|
|
96
|
+
export const API_KEY_SECRET_FIELDS = ['hash', 'sealedCiphertext', 'sealedIv', 'sealedTag'];
|
|
97
|
+
|
|
98
|
+
ApiKeySchema.plugin(auditPlugin, { resource: 'api_key', redact: API_KEY_SECRET_FIELDS });
|
|
99
|
+
|
|
73
100
|
export const ApiKey = mongoose.models.ApiKey
|
|
74
101
|
? (mongoose.models.ApiKey as mongoose.Model<IApiKey>)
|
|
75
102
|
: mongoose.model<IApiKey>('ApiKey', ApiKeySchema);
|
package/src/apiKeys/index.ts
CHANGED
|
@@ -11,8 +11,22 @@ export {
|
|
|
11
11
|
export type { CreateApiKeyInput, CreatedApiKey } from './service';
|
|
12
12
|
export { authenticateAgent, requireScope, denyApiKeys } from './middleware';
|
|
13
13
|
export type { ApiKeyContext } from './middleware';
|
|
14
|
-
export {
|
|
15
|
-
|
|
14
|
+
export {
|
|
15
|
+
API_KEY_SCOPES,
|
|
16
|
+
isApiKeyScope,
|
|
17
|
+
PERSONAL_TENANT,
|
|
18
|
+
groupIdOf,
|
|
19
|
+
groupIdsOf,
|
|
20
|
+
readTenants
|
|
21
|
+
} from './types';
|
|
22
|
+
export type {
|
|
23
|
+
ApiKeyScope,
|
|
24
|
+
ApiKeySummary,
|
|
25
|
+
ApiKeyVerification,
|
|
26
|
+
ApiKeyRejection,
|
|
27
|
+
ApiKeyTenant,
|
|
28
|
+
Tenant
|
|
29
|
+
} from './types';
|
|
16
30
|
export {
|
|
17
31
|
looksLikeApiKey,
|
|
18
32
|
displayPrefix,
|