@teikyo/access 0.1.1 → 0.2.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 +1 -1
- package/lib/grants/plugin.d.ts +2 -0
- package/lib/grants/plugin.js +13 -0
- package/lib/revocation/backend.d.ts +3 -2
- package/lib/revocation/backend.js +2 -1
- package/lib/revocation/plugin.d.ts +5 -4
- package/package.json +12 -12
package/README.md
CHANGED
|
@@ -75,5 +75,5 @@ await cache.allows('did:key:z6Mk...', 'app/read')
|
|
|
75
75
|
`accessRevocationPlugin()` (plugin name `access:revocation`) provides a Hozon-backed revocation store and a `verifyToken` hook for Enkaku servers.
|
|
76
76
|
|
|
77
77
|
- Records are scoped by issuer: the store's `get(jti, issuer)` only returns records signed by `issuer`, and the hook looks up the capability's own issuer, so another identity cannot revoke or shadow a jti it does not own.
|
|
78
|
-
- `requireJTI` defaults to `true`, so
|
|
78
|
+
- `requireJTI` defaults to `true`, so tokens created without an explicit `jti` are rejected with `Token without jti rejected`; set it to `false` to accept them (they can never be revoked).
|
|
79
79
|
- Register the store through the plugin, which carries the DID resolution options (`resolver`, `cache`, `methods`) that `add` needs.
|
package/lib/grants/plugin.d.ts
CHANGED
|
@@ -6,6 +6,8 @@ export type AccessGrants = {
|
|
|
6
6
|
store: GrantStore;
|
|
7
7
|
/** Build an Enkaku access predicate admitting issuers, or verified delegates, holding a matching grant. */
|
|
8
8
|
allow(): AllowPredicate;
|
|
9
|
+
/** Whether the subject holds a grant matching the resource, using the same cache as `allow()`. */
|
|
10
|
+
allows(subject: string, resource: string): Promise<boolean>;
|
|
9
11
|
};
|
|
10
12
|
export declare const ACCESS_GRANTS: import("@sozai/http-server").PluginName<"access:grants", AccessGrants>;
|
|
11
13
|
export type AccessGrantsPluginParams = {
|
package/lib/grants/plugin.js
CHANGED
|
@@ -23,6 +23,19 @@ export const ACCESS_GRANTS = pluginName()('access:grants');
|
|
|
23
23
|
ctx.onClose(()=>cache.dispose());
|
|
24
24
|
return {
|
|
25
25
|
store,
|
|
26
|
+
async allows (subject, resource) {
|
|
27
|
+
try {
|
|
28
|
+
return await cache.allows(subject, resource);
|
|
29
|
+
} catch (cause) {
|
|
30
|
+
ctx.logger.error('access check failed for {resource}', {
|
|
31
|
+
resource,
|
|
32
|
+
error: cause
|
|
33
|
+
});
|
|
34
|
+
throw new Error('Access denied', {
|
|
35
|
+
cause
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
},
|
|
26
39
|
allow: ()=>async ({ payload, procedure, verifyDelegation })=>{
|
|
27
40
|
try {
|
|
28
41
|
if (await cache.allows(payload.iss, procedure)) {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { StoreDefinition } from '@hozon/db';
|
|
2
|
-
import { type RevocationBackend, type RevocationOptions
|
|
2
|
+
import { type RevocationBackend, type RevocationOptions } from '@kokuin/capability';
|
|
3
|
+
import { type SignedToken } from '@kokuin/token';
|
|
3
4
|
import type { RevocationTables } from './tables.js';
|
|
4
5
|
/**
|
|
5
6
|
* Revocation backend of the store. `get` is scoped by issuer because the jti namespace belongs to
|
|
@@ -24,4 +25,4 @@ export type RevocationHookParams = {
|
|
|
24
25
|
* a revocation are logged through `onError` and surface as `Access denied`, because Enkaku copies
|
|
25
26
|
* error messages to the client.
|
|
26
27
|
*/
|
|
27
|
-
export declare function createRevocationHook(params: RevocationHookParams):
|
|
28
|
+
export declare function createRevocationHook(params: RevocationHookParams): (token: SignedToken, raw: string) => Promise<void>;
|
|
@@ -66,9 +66,10 @@ function toRecord(row) {
|
|
|
66
66
|
* a revocation are logged through `onError` and surface as `Access denied`, because Enkaku copies
|
|
67
67
|
* error messages to the client.
|
|
68
68
|
*/ export function createRevocationHook(params) {
|
|
69
|
+
// Parameter widened to any signed token so plain invocation tokens can be checked too.
|
|
69
70
|
return async (token, raw)=>{
|
|
70
71
|
if (params.requireJTI && token.payload.jti == null) {
|
|
71
|
-
throw new Error('
|
|
72
|
+
throw new Error('Token without jti rejected');
|
|
72
73
|
}
|
|
73
74
|
try {
|
|
74
75
|
await createRevocationChecker(params.backend, params.options)(token, raw);
|
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
import type { RevocationOptions
|
|
1
|
+
import type { RevocationOptions } from '@kokuin/capability';
|
|
2
|
+
import type { SignedToken } from '@kokuin/token';
|
|
2
3
|
import { type HTTPPlugin } from '@sozai/http-server';
|
|
3
4
|
import { HOZON_DB } from '@teikyo/hozon';
|
|
4
5
|
import { type RevocationStoreAPI } from './backend.js';
|
|
5
6
|
export type AccessRevocation = {
|
|
6
7
|
backend: RevocationStoreAPI;
|
|
7
|
-
/** Enkaku `verifyToken` hook rejecting revoked
|
|
8
|
-
verifyToken:
|
|
8
|
+
/** Enkaku `verifyToken` hook rejecting revoked signed tokens. */
|
|
9
|
+
verifyToken: (token: SignedToken, raw: string) => Promise<void>;
|
|
9
10
|
};
|
|
10
11
|
export declare const ACCESS_REVOCATION: import("@sozai/http-server").PluginName<"access:revocation", AccessRevocation>;
|
|
11
12
|
export type AccessRevocationPluginParams = RevocationOptions & {
|
|
12
|
-
/** Reject
|
|
13
|
+
/** Reject signed tokens without a jti, which cannot be revoked. Defaults to `true`. */
|
|
13
14
|
requireJTI?: boolean;
|
|
14
15
|
};
|
|
15
16
|
/** Provide a persistent revocation backend and the `verifyToken` hook that consults it. */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@teikyo/access",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Access grants and revocation for Enkaku servers",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -19,20 +19,20 @@
|
|
|
19
19
|
"lib/*"
|
|
20
20
|
],
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@enkaku/server": "^0.
|
|
23
|
-
"@hozon/db": "^0.
|
|
24
|
-
"@kokuin/capability": "^0.
|
|
25
|
-
"@kokuin/token": "^0.
|
|
26
|
-
"@sozai/codec": "^0.4.
|
|
27
|
-
"@sozai/http-server": "^0.
|
|
22
|
+
"@enkaku/server": "^0.22.1",
|
|
23
|
+
"@hozon/db": "^0.3.0",
|
|
24
|
+
"@kokuin/capability": "^0.5.1",
|
|
25
|
+
"@kokuin/token": "^0.6.1",
|
|
26
|
+
"@sozai/codec": "^0.4.3",
|
|
27
|
+
"@sozai/http-server": "^0.2.0",
|
|
28
28
|
"@sozai/log": "^0.4.0",
|
|
29
|
-
"@teikyo/hozon": "^0.
|
|
29
|
+
"@teikyo/hozon": "^0.2.0"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
|
-
"@hozon/provider": "^0.1.
|
|
33
|
-
"@types/node": "^26.6.
|
|
34
|
-
"del-cli": "^
|
|
35
|
-
"vitest": "5.0.
|
|
32
|
+
"@hozon/provider": "^0.1.2",
|
|
33
|
+
"@types/node": "^26.6.5",
|
|
34
|
+
"del-cli": "^8.0.1",
|
|
35
|
+
"vitest": "5.0.5"
|
|
36
36
|
},
|
|
37
37
|
"engines": {
|
|
38
38
|
"node": ">=24"
|