@nocobase/app-plugin-api-keys 0.0.0-stage → 1.0.0-beta.14

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.
Files changed (79) hide show
  1. package/CHANGELOG.md +468 -0
  2. package/README.md +162 -2
  3. package/dist/client/api-keys-client.d.ts +19 -0
  4. package/dist/client/api-keys-client.d.ts.map +1 -0
  5. package/dist/client/api-keys-client.js +7 -0
  6. package/dist/client/api-keys-client.js.map +1 -0
  7. package/dist/client/expiry.d.ts +23 -0
  8. package/dist/client/expiry.d.ts.map +1 -0
  9. package/dist/client/expiry.js +40 -0
  10. package/dist/client/expiry.js.map +1 -0
  11. package/dist/client/index.d.ts +4 -0
  12. package/dist/client/index.d.ts.map +1 -0
  13. package/dist/client/index.js +6 -0
  14. package/dist/client/index.js.map +1 -0
  15. package/dist/client/plugin.d.ts +8 -0
  16. package/dist/client/plugin.d.ts.map +1 -0
  17. package/dist/client/plugin.js +10 -0
  18. package/dist/client/plugin.js.map +1 -0
  19. package/dist/database/migrations/.manifest.json +9 -0
  20. package/dist/database/migrations/202609150001_create_api_key_table.js +58 -0
  21. package/dist/database/migrations/202609150001_create_api_key_table.js.map +1 -0
  22. package/dist/server/api-docs.d.ts +24 -0
  23. package/dist/server/api-docs.d.ts.map +1 -0
  24. package/dist/server/api-docs.js +73 -0
  25. package/dist/server/api-docs.js.map +1 -0
  26. package/dist/server/api-keys.d.ts +52 -0
  27. package/dist/server/api-keys.d.ts.map +1 -0
  28. package/dist/server/api-keys.js +199 -0
  29. package/dist/server/api-keys.js.map +1 -0
  30. package/dist/server/index.d.ts +23 -0
  31. package/dist/server/index.d.ts.map +1 -0
  32. package/dist/server/index.js +22 -0
  33. package/dist/server/index.js.map +1 -0
  34. package/dist/server/key-sessions.d.ts +35 -0
  35. package/dist/server/key-sessions.d.ts.map +1 -0
  36. package/dist/server/key-sessions.js +50 -0
  37. package/dist/server/key-sessions.js.map +1 -0
  38. package/dist/server/plugin.d.ts +4 -0
  39. package/dist/server/plugin.d.ts.map +1 -0
  40. package/dist/server/plugin.js +15 -0
  41. package/dist/server/plugin.js.map +1 -0
  42. package/dist/server/providers/index.d.ts +19 -0
  43. package/dist/server/providers/index.d.ts.map +1 -0
  44. package/dist/server/providers/index.js +72 -0
  45. package/dist/server/providers/index.js.map +1 -0
  46. package/dist/server/routes/errors.d.ts +8 -0
  47. package/dist/server/routes/errors.d.ts.map +1 -0
  48. package/dist/server/routes/errors.js +48 -0
  49. package/dist/server/routes/errors.js.map +1 -0
  50. package/dist/server/routes/index.d.ts +10 -0
  51. package/dist/server/routes/index.d.ts.map +1 -0
  52. package/dist/server/routes/index.js +177 -0
  53. package/dist/server/routes/index.js.map +1 -0
  54. package/dist/server/routes/schemas.d.ts +25 -0
  55. package/dist/server/routes/schemas.d.ts.map +1 -0
  56. package/dist/server/routes/schemas.js +127 -0
  57. package/dist/server/routes/schemas.js.map +1 -0
  58. package/dist/server/scoped-keys.d.ts +116 -0
  59. package/dist/server/scoped-keys.d.ts.map +1 -0
  60. package/dist/server/scoped-keys.js +451 -0
  61. package/dist/server/scoped-keys.js.map +1 -0
  62. package/dist/server/scopes.d.ts +70 -0
  63. package/dist/server/scopes.d.ts.map +1 -0
  64. package/dist/server/scopes.js +165 -0
  65. package/dist/server/scopes.js.map +1 -0
  66. package/dist/server/service.d.ts +28 -0
  67. package/dist/server/service.d.ts.map +1 -0
  68. package/dist/server/service.js +69 -0
  69. package/dist/server/service.js.map +1 -0
  70. package/dist/server/tokens.d.ts +6 -0
  71. package/dist/server/tokens.d.ts.map +1 -0
  72. package/dist/server/tokens.js +5 -0
  73. package/dist/server/tokens.js.map +1 -0
  74. package/dist/shared/scopes.d.ts +160 -0
  75. package/dist/shared/scopes.d.ts.map +1 -0
  76. package/dist/shared/scopes.js +83 -0
  77. package/dist/shared/scopes.js.map +1 -0
  78. package/package.json +76 -3
  79. package/skills/nocobase-app-plugin-api-keys/SKILL.md +161 -0
@@ -0,0 +1,177 @@
1
+ import { authenticationToken } from '@nocobase/app-plugin-authentication/server';
2
+ import { authorizationToken, } from '@nocobase/app-plugin-authorization';
3
+ import { apiErrorHandler, apiErrorResponse, apiErrorResponses, apiValidator, cliRoute, dataResponse, defineApiRoutes, describeRoute, emptyResponse, listResponse, } from '@nocobase/app-server/router';
4
+ import { Hono } from 'hono';
5
+ import { requireSignInSession } from '../key-sessions.js';
6
+ import { scopedApiKeysToken } from '../tokens.js';
7
+ import { toApiKeysApiError } from './errors.js';
8
+ import { ApiKeyParams, ApiKeysListMeta, ApiKeyViewSchema, CreateApiKeyInput, CreatedApiKeySchema, KeyScopeObjectSchema, KeyScopeOptionsSchema, ScopeGroupParams, ScopeObjectsQuery, } from './schemas.js';
9
+ const tags = ['ApiKeys'];
10
+ /** Every route refuses a request made with an API key: keys are managed from a sign-in. */
11
+ const signInOnly = 'Takes a signed-in session: a request made with any API key is refused (`403`).';
12
+ const keyNotFound = apiErrorResponse(404, 'The caller has no key with this id (`KEY_NOT_FOUND`).');
13
+ const creationForbidden = apiErrorResponse(403, 'The caller may not use API keys or may not create keys of their own (`API_KEY_CREATION_FORBIDDEN`).');
14
+ /**
15
+ * `/api/apiKeys`: a person's own keys, with or without a scope. Self-service: every endpoint acts on the caller's
16
+ * keys only, and only from a sign-in: a request made with any API key is refused (`requireSignInSession`).
17
+ */
18
+ export const apiRoutes = defineApiRoutes(({ container }) => {
19
+ const router = new Hono();
20
+ if (!container.has(authenticationToken))
21
+ return router;
22
+ const keys = container.resolve(scopedApiKeysToken);
23
+ const routes = new Hono();
24
+ routes.onError((error, context) => apiErrorHandler(toApiKeysApiError(error), context));
25
+ routes.use('*', container.resolve(authenticationToken).required());
26
+ // Managing keys takes a sign-in: no key, scoped or not, creates, rotates or revokes keys.
27
+ routes.use('*', requireSignInSession());
28
+ if (container.has(authorizationToken))
29
+ routes.use('*', container.resolve(authorizationToken).middleware());
30
+ const userId = (context) => context.get('auth').user.id;
31
+ const identity = async (context) => context.get('authz')?.identity ??
32
+ (await keys.identityOf(userId(context)));
33
+ // Creating and rotating are refused before the input is read when the person may not create keys.
34
+ const mayCreate = async (context, next) => {
35
+ await keys.requireOwnCreation(userId(context));
36
+ await next();
37
+ };
38
+ routes.get('/scopeOptions', describeRoute({
39
+ tags,
40
+ summary: 'List what a scoped key may be limited to',
41
+ operationId: 'apiKeysListScopeOptions',
42
+ ...cliRoute({ command: 'api-key scope-options' }),
43
+ description: signInOnly,
44
+ responses: {
45
+ 200: dataResponse(KeyScopeOptionsSchema),
46
+ ...apiErrorResponses,
47
+ },
48
+ }), async (context) => context.json({
49
+ data: {
50
+ ...(await keys.scopeOptions(userId(context))),
51
+ mayCreate: await keys.mayCreateOwn(userId(context)),
52
+ },
53
+ }));
54
+ // The records a person may pick for a group: bounded by what they see, and narrowed by `q` or `id`.
55
+ routes.get('/scopeObjects/:group', describeRoute({
56
+ tags,
57
+ summary: 'List the records a scope group may be limited to',
58
+ operationId: 'apiKeysListScopeObjects',
59
+ ...cliRoute({
60
+ command: 'api-key scope-objects',
61
+ columns: ['id', 'title', 'description'],
62
+ examples: ['api-key scope-objects pm.projects --q checkout'],
63
+ }),
64
+ description: `${signInOnly} Bounded by what the caller can see and narrowed by \`q\` or repeated \`id\`; not paged.`,
65
+ responses: {
66
+ 200: listResponse(KeyScopeObjectSchema, ApiKeysListMeta),
67
+ ...apiErrorResponses,
68
+ 404: apiErrorResponse(404, 'The scope group does not exist (`UNKNOWN_SCOPE_GROUP`).'),
69
+ },
70
+ }), apiValidator('param', ScopeGroupParams), apiValidator('query', ScopeObjectsQuery), async (context) => {
71
+ const { group } = context.req.valid('param');
72
+ const { q, id } = context.req.valid('query');
73
+ const data = await keys.scopeObjects(group, await identity(context), {
74
+ ...(q ? { search: q } : {}),
75
+ ...(id ? { ids: id } : {}),
76
+ });
77
+ return context.json({ data, meta: { total: data.length } });
78
+ });
79
+ // A person's own keys: a bounded list, not paged.
80
+ routes.get('/', describeRoute({
81
+ tags,
82
+ summary: 'List my API keys',
83
+ operationId: 'apiKeysListKeys',
84
+ ...cliRoute({
85
+ command: 'api-key list',
86
+ columns: [
87
+ 'id',
88
+ 'name',
89
+ 'start',
90
+ 'enabled',
91
+ 'expiresAt',
92
+ 'lastUsedAt',
93
+ ],
94
+ }),
95
+ description: `${signInOnly} Never returns a key's secret.`,
96
+ responses: {
97
+ 200: listResponse(ApiKeyViewSchema, ApiKeysListMeta),
98
+ ...apiErrorResponses,
99
+ },
100
+ }), async (context) => {
101
+ const data = await keys.list(userId(context));
102
+ return context.json({ data, meta: { total: data.length } });
103
+ });
104
+ routes.post('/', mayCreate, describeRoute({
105
+ tags,
106
+ summary: 'Create an API key',
107
+ operationId: 'apiKeysCreateKey',
108
+ ...cliRoute({
109
+ command: 'api-key create',
110
+ examples: [
111
+ 'api-key create --name ci --expires-in-days 90',
112
+ 'api-key create --file key.json',
113
+ ],
114
+ bodyFile: 'file',
115
+ }),
116
+ description: `${signInOnly} The secret is in this response only. \`scope: null\` makes a key that acts as the caller in full.`,
117
+ responses: {
118
+ 201: dataResponse(CreatedApiKeySchema, 'The created key.'),
119
+ ...apiErrorResponses,
120
+ 403: creationForbidden,
121
+ 400: apiErrorResponse(400, 'The expiry or the scope is not allowed (`EXPIRY_REQUIRED`, `INVALID_EXPIRY`, `INVALID_SCOPE`, `EMPTY_SCOPE`, `UNKNOWN_SCOPE_GROUP`, `SCOPE_LEVEL_NOT_OFFERED`, `SCOPE_OBJECTS_NOT_OFFERED`, `UNKNOWN_SCOPE_OBJECT`).'),
122
+ },
123
+ }), apiValidator('json', CreateApiKeyInput), async (context) => {
124
+ context.header('Cache-Control', 'no-store');
125
+ return context.json({
126
+ data: await keys.create(userId(context), context.req.valid('json'), await identity(context)),
127
+ }, 201);
128
+ });
129
+ routes.post('/:keyId/rotate', mayCreate, describeRoute({
130
+ tags,
131
+ summary: 'Rotate an API key',
132
+ operationId: 'apiKeysRotateKey',
133
+ ...cliRoute({
134
+ command: 'api-key rotate',
135
+ flags: { keyId: { name: 'key' } },
136
+ confirm: 'Rotate this key? The old secret stops working.',
137
+ }),
138
+ description: `${signInOnly} Replaces the key with a new secret, keeping its name, scope and lifetime; the old secret stops working.`,
139
+ responses: {
140
+ 200: dataResponse(CreatedApiKeySchema),
141
+ ...apiErrorResponses,
142
+ 403: creationForbidden,
143
+ 404: keyNotFound,
144
+ },
145
+ }), apiValidator('param', ApiKeyParams), async (context) => {
146
+ context.header('Cache-Control', 'no-store');
147
+ return context.json({
148
+ data: await keys.rotate(userId(context), context.req.valid('param').keyId),
149
+ });
150
+ });
151
+ routes.delete('/:keyId', describeRoute({
152
+ tags,
153
+ summary: 'Revoke an API key',
154
+ operationId: 'apiKeysRevokeKey',
155
+ ...cliRoute({
156
+ command: 'api-key delete',
157
+ flags: { keyId: { name: 'key' } },
158
+ confirm: 'Revoke this key? Whatever uses it stops working.',
159
+ }),
160
+ description: signInOnly,
161
+ responses: {
162
+ 204: emptyResponse('The key was revoked.'),
163
+ ...apiErrorResponses,
164
+ 404: keyNotFound,
165
+ },
166
+ }), apiValidator('param', ApiKeyParams), async (context) => {
167
+ await keys.revoke(userId(context), context.req.valid('param').keyId);
168
+ return context.body(null, 204);
169
+ });
170
+ router.route('/apiKeys', routes);
171
+ return router;
172
+ });
173
+ const routes = [
174
+ apiRoutes,
175
+ ];
176
+ export default routes;
177
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../server/routes/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ import { z } from 'zod';
2
+ import { type ApiKeyView, type CreateApiKeyRequest, type CreatedApiKey, type KeyScopeObject, type KeyScopeOptions, type KeyScopeInput } from '../../shared/scopes.js';
3
+ /** A key's scope; which groups exist and what they offer is checked by `ApiKeyScopes.validate`. */
4
+ export declare const KeyScopeInputSchema: z.ZodType<KeyScopeInput>;
5
+ /** The body of `POST /apiKeys`. */
6
+ export declare const CreateApiKeyInput: z.ZodType<CreateApiKeyRequest>;
7
+ export declare const ApiKeyParams: z.ZodObject<{
8
+ keyId: z.ZodString;
9
+ }>;
10
+ export declare const ScopeGroupParams: z.ZodObject<{
11
+ group: z.ZodString;
12
+ }>;
13
+ /** The query of `GET /apiKeys/scopeObjects/:group`: a search, or the records to look up by id (`id` repeated). */
14
+ export declare const ScopeObjectsQuery: z.ZodType<{
15
+ q?: string | undefined;
16
+ id?: string[] | undefined;
17
+ }>;
18
+ export declare const KeyScopeOptionsSchema: z.ZodType<KeyScopeOptions>;
19
+ export declare const KeyScopeObjectSchema: z.ZodType<KeyScopeObject>;
20
+ export declare const ApiKeyViewSchema: z.ZodType<ApiKeyView>;
21
+ export declare const CreatedApiKeySchema: z.ZodType<CreatedApiKey>;
22
+ export declare const ApiKeysListMeta: z.ZodType<{
23
+ total: number;
24
+ }>;
25
+ //# sourceMappingURL=schemas.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../../../server/routes/schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAGL,KAAK,UAAU,EACf,KAAK,mBAAmB,EACxB,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,eAAe,EAGpB,KAAK,aAAa,EAEnB,MAAM,wBAAwB,CAAC;AAahC,mGAAmG;AACnG,eAAO,MAAM,mBAAmB,EAAE,CAAC,CAAC,OAAO,CAAC,aAAa,CAEvD,CAAC;AAEH,mCAAmC;AACnC,eAAO,MAAM,iBAAiB,EAAE,CAAC,CAAC,OAAO,CAAC,mBAAmB,CAO5D,CAAC;AAEF,eAAO,MAAM,YAAY,EAAE,CAAC,CAAC,SAAS,CAAC;IAAE,KAAK,EAAE,CAAC,CAAC,SAAS,CAAA;CAAE,CAE3D,CAAC;AAEH,eAAO,MAAM,gBAAgB,EAAE,CAAC,CAAC,SAAS,CAAC;IAAE,KAAK,EAAE,CAAC,CAAC,SAAS,CAAA;CAAE,CAE/D,CAAC;AAIH,kHAAkH;AAClH,eAAO,MAAM,iBAAiB,EAAE,CAAC,CAAC,OAAO,CAAC;IACxC,CAAC,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACvB,EAAE,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;CAC3B,CAQC,CAAC;AAgCH,eAAO,MAAM,qBAAqB,EAAE,CAAC,CAAC,OAAO,CAAC,eAAe,CA2C3D,CAAC;AAEH,eAAO,MAAM,oBAAoB,EAAE,CAAC,CAAC,OAAO,CAAC,cAAc,CAIzD,CAAC;AAEH,eAAO,MAAM,gBAAgB,EAAE,CAAC,CAAC,OAAO,CAAC,UAAU,CAgBrB,CAAC;AAE/B,eAAO,MAAM,mBAAmB,EAAE,CAAC,CAAC,OAAO,CAAC,aAAa,CAOpB,CAAC;AAEtC,eAAO,MAAM,eAAe,EAAE,CAAC,CAAC,OAAO,CAAC;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAEvD,CAAC"}
@@ -0,0 +1,127 @@
1
+ import { z } from 'zod';
2
+ import { KEY_SCOPE_LEVELS, } from '../../shared/scopes.js';
3
+ const KeyScopeLevelSchema = z.enum(KEY_SCOPE_LEVELS);
4
+ const KeyScopeGroupGrantSchema = z.strictObject({
5
+ level: KeyScopeLevelSchema,
6
+ objects: z
7
+ .union([z.literal('all'), z.array(z.string().min(1)).min(1)])
8
+ .optional(),
9
+ });
10
+ /** A key's scope; which groups exist and what they offer is checked by `ApiKeyScopes.validate`. */
11
+ export const KeyScopeInputSchema = z.strictObject({
12
+ groups: z.record(z.string().min(1), KeyScopeGroupGrantSchema),
13
+ });
14
+ /** The body of `POST /apiKeys`. */
15
+ export const CreateApiKeyInput = z.strictObject({
16
+ name: z.string(),
17
+ description: z.string().nullable().optional(),
18
+ expiresInDays: z.number().int().nullable(),
19
+ scope: KeyScopeInputSchema.nullable(),
20
+ });
21
+ export const ApiKeyParams = z.object({
22
+ keyId: z.string().min(1),
23
+ });
24
+ export const ScopeGroupParams = z.object({
25
+ group: z.string().min(1),
26
+ });
27
+ const MAX_PICKED_IDS = 100;
28
+ /** The query of `GET /apiKeys/scopeObjects/:group`: a search, or the records to look up by id (`id` repeated). */
29
+ export const ScopeObjectsQuery = z.object({
30
+ q: z.string().max(200).optional(),
31
+ id: z
32
+ .union([z.string().min(1), z.array(z.string().min(1)).max(MAX_PICKED_IDS)])
33
+ .optional()
34
+ .transform((value) => value === undefined ? undefined : Array.isArray(value) ? value : [value]),
35
+ });
36
+ // Response schemas: they document what the routes send; nothing validates a response against them.
37
+ const dateTime = () => z.string().meta({ format: 'date-time' });
38
+ const LocalizedTextSchema = z
39
+ .union([z.string(), z.object({ key: z.string(), ns: z.string() })])
40
+ .meta({
41
+ ref: 'ApiKeysLocalizedText',
42
+ description: 'Plain text, or an i18n key in a namespace.',
43
+ });
44
+ const AccessRefSchema = z.discriminatedUnion('kind', [
45
+ z.object({ kind: z.literal('page'), id: z.string() }),
46
+ z.object({ kind: z.literal('settings'), id: z.string(), action: z.string() }),
47
+ z.object({ kind: z.literal('business'), id: z.string(), action: z.string() }),
48
+ ]);
49
+ const GrantResponseSchema = z.object({
50
+ level: KeyScopeLevelSchema,
51
+ objects: z.union([z.literal('all'), z.array(z.string())]).optional(),
52
+ });
53
+ const KeyScopeResponseSchema = z
54
+ .object({ groups: z.record(z.string(), GrantResponseSchema) })
55
+ .meta({
56
+ ref: 'ApiKeysKeyScope',
57
+ description: 'What the key may do, group by group; a group left out grants nothing.',
58
+ });
59
+ export const KeyScopeOptionsSchema = z.object({
60
+ groups: z
61
+ .array(z.object({
62
+ id: z.string(),
63
+ category: z.enum(['business', 'administration', 'account']),
64
+ title: LocalizedTextSchema,
65
+ description: LocalizedTextSchema.nullable(),
66
+ levels: z.array(KeyScopeLevelSchema),
67
+ access: z.partialRecord(KeyScopeLevelSchema, z.array(AccessRefSchema)),
68
+ held: z.partialRecord(KeyScopeLevelSchema, z.boolean()).meta({
69
+ description: 'Whether the caller holds everything up to each level; false shows it greyed out.',
70
+ }),
71
+ objects: z
72
+ .object({ business: z.string(), title: LocalizedTextSchema })
73
+ .nullable(),
74
+ }))
75
+ .meta({ description: 'Empty when scoped keys are not offered.' }),
76
+ presets: z.array(z.object({
77
+ id: z.string(),
78
+ title: LocalizedTextSchema,
79
+ description: LocalizedTextSchema.nullable(),
80
+ groups: z.record(z.string(), z.object({
81
+ level: KeyScopeLevelSchema,
82
+ objects: z.enum(['all', 'pick']).optional(),
83
+ })),
84
+ expiresInDays: z.number().int().nullable(),
85
+ })),
86
+ maxScopedKeyDays: z.number().int().nullable().meta({
87
+ description: 'The longest a scoped key may live, in days; null when "never expires" is allowed.',
88
+ }),
89
+ defaultExpiresInDays: z.number().int(),
90
+ mayCreate: z.boolean().optional().meta({
91
+ description: 'Whether the caller may create keys of their own.',
92
+ }),
93
+ });
94
+ export const KeyScopeObjectSchema = z.object({
95
+ id: z.string(),
96
+ title: z.string(),
97
+ description: z.string().optional(),
98
+ });
99
+ export const ApiKeyViewSchema = z
100
+ .object({
101
+ id: z.string(),
102
+ name: z.string().nullable(),
103
+ description: z.string().nullable(),
104
+ start: z.string().nullable().meta({
105
+ description: 'The first characters of the key, to recognize it.',
106
+ }),
107
+ enabled: z.boolean(),
108
+ createdAt: dateTime(),
109
+ expiresAt: dateTime().nullable(),
110
+ lastUsedAt: dateTime().nullable(),
111
+ scope: KeyScopeResponseSchema.nullable().meta({
112
+ description: 'Null for a key that acts as its owner in full.',
113
+ }),
114
+ })
115
+ .meta({ ref: 'ApiKeysKey' });
116
+ export const CreatedApiKeySchema = z
117
+ .object({
118
+ key: ApiKeyViewSchema,
119
+ secret: z.string().meta({
120
+ description: 'The key itself, shown only in this response.',
121
+ }),
122
+ })
123
+ .meta({ ref: 'ApiKeysCreatedKey' });
124
+ export const ApiKeysListMeta = z.object({
125
+ total: z.number().int(),
126
+ });
127
+ //# sourceMappingURL=schemas.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schemas.js","sourceRoot":"","sources":["../../../server/routes/schemas.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,116 @@
1
+ /**
2
+ * Keys with scopes: creating, listing, rotating and revoking a user's keys, and recognizing the key behind a request.
3
+ * The caller authorizes who may manage whose keys; this service only ever acts on the user it is told.
4
+ */
5
+ import { type Auth, type AuthSession } from '@nocobase/app-plugin-authentication/server';
6
+ import type { Authorization, AuthorizationIdentity, KeyScope } from '@nocobase/authorization/core';
7
+ import type { DatabaseConnection } from '@nocobase/db';
8
+ import { type ApiKeyView, type CreatedApiKey, type KeyScopeInput, type KeyScopeObject, type KeyScopeOptions } from '../shared/scopes.js';
9
+ import { type ApiKeyScopes } from './scopes.js';
10
+ /** The expiry the editor proposes for a scoped key. */
11
+ export declare const DEFAULT_SCOPED_KEY_DAYS = 90;
12
+ /** `apiKeys` in the application's configuration. */
13
+ export interface ApiKeysConfig {
14
+ /** The longest a scoped key may live, in days. Unset allows "never expires". */
15
+ readonly maxScopedKeyDays?: number | null;
16
+ }
17
+ /** A refused key operation: a status and a stable code. */
18
+ export declare class ApiKeyRequestError extends Error {
19
+ readonly status: 400 | 403 | 404;
20
+ readonly code: string;
21
+ constructor(status: 400 | 403 | 404, code: string, message: string);
22
+ }
23
+ export interface ScopedApiKeysOptions {
24
+ readonly auth: Pick<Auth, 'pluginApi'>;
25
+ readonly connection: () => DatabaseConnection;
26
+ readonly scopes: ApiKeyScopes;
27
+ /** The application's authorization, to say what a user holds and to build their identity; optional. */
28
+ readonly authorization?: () => Authorization | undefined;
29
+ readonly config?: () => ApiKeysConfig | undefined;
30
+ }
31
+ /**
32
+ * Whether a user may create (and rotate) keys of their own, as an application decides it. Without one, everyone may.
33
+ * Listing and revoking one's keys stay open, so a person who loses the permission can still clean up.
34
+ */
35
+ export type OwnKeyPolicy = (userId: string) => Promise<boolean>;
36
+ /** A key's fields as `create` would issue it, checked but not yet issued (`ScopedApiKeys.check`). */
37
+ export interface CheckedApiKey {
38
+ readonly name: string;
39
+ readonly description: string | null;
40
+ readonly scope: KeyScopeInput | null;
41
+ readonly expiresInDays: number | null;
42
+ }
43
+ /**
44
+ * Lets the hook on Better Auth's own `/api-key/create` ask `keys` whether a person may create a key of their own, as
45
+ * `/api/apiKeys` does. The plugin's provider calls it at boot; returns what disconnects it.
46
+ */
47
+ export declare function connectOwnKeyPolicy(auth: Pick<Auth, 'administrationContext'>, keys: Pick<ScopedApiKeys, 'mayCreateOwn'>): Promise<() => void>;
48
+ export declare class ScopedApiKeys {
49
+ private readonly options;
50
+ private readonly resolved;
51
+ private ownKeyPolicy;
52
+ constructor(options: ScopedApiKeysOptions);
53
+ /**
54
+ * Sets who may create keys of their own (`/api/apiKeys` and Better Auth's `/api-key/create`). Returns what removes
55
+ * it again.
56
+ */
57
+ setOwnKeyPolicy(policy: OwnKeyPolicy): () => void;
58
+ /** Whether `userId` may create keys of their own; true unless the application set a policy that says otherwise. */
59
+ mayCreateOwn(userId: string): Promise<boolean>;
60
+ /** Refuses with 403 `API_KEY_CREATION_FORBIDDEN` unless `userId` may create keys of their own. */
61
+ requireOwnCreation(userId: string): Promise<void>;
62
+ private get maxScopedKeyDays();
63
+ /** The identity a request of `userId` would carry, as the authorization plugin's middleware builds it. */
64
+ identityOf(userId: string): Promise<AuthorizationIdentity>;
65
+ /** What the editor offers for keys of `userId`, with what that user holds today. */
66
+ scopeOptions(userId: string): Promise<KeyScopeOptions>;
67
+ /** The records a group may be limited to, as `identity` may see them. */
68
+ scopeObjects(groupId: string, identity: AuthorizationIdentity, query?: {
69
+ readonly search?: string;
70
+ readonly ids?: readonly string[];
71
+ }): Promise<readonly KeyScopeObject[]>;
72
+ /** `userId`'s keys of the default configuration, newest first. */
73
+ list(userId: string): Promise<ApiKeyView[]>;
74
+ /**
75
+ * Creates a key for `userId`. `identity` is whoever chooses the records of a group limited to some: each must be
76
+ * one they may see.
77
+ */
78
+ create(userId: string, input: unknown, identity: AuthorizationIdentity): Promise<CreatedApiKey>;
79
+ /**
80
+ * Checks what `create` would issue — name, description, scope, the records it picks (`identity` must see each) and
81
+ * expiry — without issuing anything, so a caller can refuse before creating whatever the key belongs to.
82
+ */
83
+ check(input: unknown, identity: AuthorizationIdentity): Promise<CheckedApiKey>;
84
+ /** Issues a key `check` accepted. */
85
+ issueChecked(userId: string, input: CheckedApiKey): Promise<CreatedApiKey>;
86
+ /** One of `userId`'s keys. */
87
+ get(userId: string, keyId: string): Promise<ApiKeyView>;
88
+ /**
89
+ * Gives a key a new secret in place: the same key — id, name, description, scope and owner — with a new value, and
90
+ * an expiry renewed for the lifetime it had. The old value stops at once.
91
+ */
92
+ rotate(userId: string, keyId: string): Promise<CreatedApiKey>;
93
+ /**
94
+ * Replaces a key's scope. `identity` is whoever chooses it: each record a group is limited to must be one they may
95
+ * see. The caller decides who may change a key and whether the new scope is one they may give. A key without a scope
96
+ * cannot be given one this way, nor the reverse.
97
+ */
98
+ setScope(userId: string, keyId: string, input: unknown, identity: AuthorizationIdentity): Promise<ApiKeyView>;
99
+ /** Renames a key or changes its description; a field left out stays. */
100
+ update(userId: string, keyId: string, input: unknown): Promise<ApiKeyView>;
101
+ revoke(userId: string, keyId: string): Promise<void>;
102
+ /** Every key of `userId`, as when the account is deleted. */
103
+ revokeAll(userId: string): Promise<void>;
104
+ /**
105
+ * The scope of the key a request authenticated with: compiled from its stored scope, unbounded for a service
106
+ * account's unscoped key, and null for a session or a person's unscoped key. Read once per request.
107
+ */
108
+ resolve(session: NonNullable<AuthSession>, request: Request): Promise<KeyScope | null>;
109
+ private lookup;
110
+ private issue;
111
+ private remove;
112
+ private requireRow;
113
+ private checkObjects;
114
+ private expiryOf;
115
+ }
116
+ //# sourceMappingURL=scoped-keys.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scoped-keys.d.ts","sourceRoot":"","sources":["../../server/scoped-keys.ts"],"names":[],"mappings":"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"}