@owlmeans/auth-common 0.1.18-rc.46 → 0.1.18-rc.48
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 +2 -2
- package/agent-meta/manifest.json +2 -2
- package/agent-meta/skills/auth-common/SKILL.md +27 -24
- package/build/entity/types.d.ts +52 -0
- package/build/entity/types.d.ts.map +1 -0
- package/build/entity/types.js +2 -0
- package/build/entity/types.js.map +1 -0
- package/build/entity.d.ts +5 -43
- package/build/entity.d.ts.map +1 -1
- package/build/entity.js +43 -76
- package/build/entity.js.map +1 -1
- package/build/entrypoints.d.ts +2 -2
- package/build/guards/basic-ed25519/consts.local.d.ts +3 -0
- package/build/guards/basic-ed25519/consts.local.d.ts.map +1 -0
- package/build/guards/basic-ed25519/consts.local.js +4 -0
- package/build/guards/basic-ed25519/consts.local.js.map +1 -0
- package/build/guards/basic-ed25519/service.d.ts.map +1 -1
- package/build/guards/basic-ed25519/service.js +2 -3
- package/build/guards/basic-ed25519/service.js.map +1 -1
- package/build/index.d.ts +1 -0
- package/build/index.d.ts.map +1 -1
- package/build/index.js.map +1 -1
- package/build/middleware.js +2 -2
- package/build/middleware.js.map +1 -1
- package/build/utils/trusted.js +2 -2
- package/build/utils/trusted.js.map +1 -1
- package/package.json +11 -11
- package/src/entity/types.ts +52 -0
- package/src/entity.ts +49 -77
- package/src/guards/basic-ed25519/consts.local.ts +4 -0
- package/src/guards/basic-ed25519/service.ts +2 -7
- package/src/index.ts +1 -0
- package/src/middleware.ts +2 -2
- package/src/utils/trusted.ts +2 -2
- package/tests/basic-ed25519.spec.ts +2 -2
- package/tests/entity.spec.ts +9 -9
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@ Predefined authentication protocols, guards, and constants shared between server
|
|
|
12
12
|
## Installation
|
|
13
13
|
|
|
14
14
|
```bash
|
|
15
|
-
bun add @owlmeans/auth-common@^0.1.18-rc.
|
|
15
|
+
bun add @owlmeans/auth-common@^0.1.18-rc.48
|
|
16
16
|
```
|
|
17
17
|
|
|
18
18
|
## Usage
|
|
@@ -98,7 +98,7 @@ This package ships embedded agent skills under `agent-meta/`. After installing y
|
|
|
98
98
|
your project's skill store (`.agents/skills/`):
|
|
99
99
|
|
|
100
100
|
```sh
|
|
101
|
-
npx @owlmeans/agent-skills@^0.1.18-rc.
|
|
101
|
+
npx @owlmeans/agent-skills@^0.1.18-rc.51
|
|
102
102
|
```
|
|
103
103
|
|
|
104
104
|
The embedded files are version-matched to this package release. Do not edit them
|
package/agent-meta/manifest.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 2,
|
|
3
3
|
"package": "@owlmeans/auth-common",
|
|
4
|
-
"version": "0.1.18-rc.
|
|
5
|
-
"generatedAt": "2026-10-
|
|
4
|
+
"version": "0.1.18-rc.48",
|
|
5
|
+
"generatedAt": "2026-10-06T11:45:57.659Z",
|
|
6
6
|
"canonicalRepo": "https://github.com/owlmeans/common",
|
|
7
7
|
"entries": [
|
|
8
8
|
{
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: auth-common
|
|
3
|
-
description: How to use @owlmeans/auth-common — the auth vocabulary both sides of the wire share, covering guard aliases (DEFAULT_GUARD, GUARD_ED25519), the shared auth protocol trees, the Ed25519 signature guard, the TRUSTED-record trust() helper, and the organization-entity resolver contract (ENTITY_RESOLVER,
|
|
3
|
+
description: How to use @owlmeans/auth-common — the auth vocabulary both sides of the wire share, covering guard aliases (DEFAULT_GUARD, GUARD_ED25519), the shared auth protocol trees, the Ed25519 signature guard, the TRUSTED-record trust() helper, and the organization-entity resolver contract (ENTITY_RESOLVER, makeEntityScope). Auto-invoked when importing guard constants, shared auth protocols, or entity-resolution helpers.
|
|
4
4
|
user-invocable: false
|
|
5
5
|
---
|
|
6
6
|
<!-- AUTO-GENERATED — do not edit. Regenerate via sync-agent-meta. -->
|
|
@@ -8,7 +8,7 @@ user-invocable: false
|
|
|
8
8
|
# @owlmeans/auth-common
|
|
9
9
|
|
|
10
10
|
**Layer:** Core
|
|
11
|
-
**Install:** `"@owlmeans/auth-common": "^0.1.18-rc.
|
|
11
|
+
**Install:** `"@owlmeans/auth-common": "^0.1.18-rc.48"` in `dependencies`
|
|
12
12
|
|
|
13
13
|
Everything a server and a browser must agree on to talk authentication: aliases, the shared
|
|
14
14
|
protocol declarations, the signature guard, and the contract for resolving the organization
|
|
@@ -78,32 +78,35 @@ a deployment backed by an external IAM registers none, and every consumer must t
|
|
|
78
78
|
entity as ordinary rather than exceptional.
|
|
79
79
|
|
|
80
80
|
```typescript
|
|
81
|
-
import {
|
|
81
|
+
import { makeEntityScope } from '@owlmeans/auth-common'
|
|
82
|
+
|
|
83
|
+
const scope = makeEntityScope(request) // once at the top of a handler, never stored
|
|
82
84
|
```
|
|
83
85
|
|
|
84
86
|
| Helper | What it answers |
|
|
85
87
|
|--------|-----------------|
|
|
86
|
-
| `attachEntity(context
|
|
87
|
-
| `entityKeyOf(
|
|
88
|
-
| `requireEntityKey(
|
|
89
|
-
| `requireEntity(
|
|
90
|
-
|
|
91
|
-
`attachEntity` must be called wherever authentication is **established** — the HTTP
|
|
92
|
-
any socket that authenticates after its connection is already open. A path that
|
|
93
|
-
without it leaves `request.entity` empty and its handlers silently compare a slug
|
|
94
|
-
ids.
|
|
95
|
-
|
|
96
|
-
A guard may attach the entity itself when its authority names the organization — the OIDC guard
|
|
97
|
-
|
|
98
|
-
resolve from. `attachEntity` trusts that attachment only while its `slug` is the token's
|
|
99
|
-
`entitySlugOf(request.auth)`; on any mismatch it removes it and resolves as if nothing
|
|
100
|
-
attached, so a stale or foreign entity can never reach a handler. That attached entity is
|
|
101
|
-
the organization's frozen IAM key (`{ id: entityKey, slug, iamKey: entityKey }`) — the
|
|
102
|
-
record id never leaves the provider — so on such a relying party
|
|
103
|
-
`entityKey`, which survives a rename exactly as a record id
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
88
|
+
| `scope.attachEntity(context)` | Resolve the slug on `request.auth` and set `request.entity`, canonicalizing a retired slug to the current one. Keeps an entity the guard already attached when its `slug` equals the token's exactly, and drops one that does not. Otherwise a no-op when no resolver is registered; throws `AuthenFailed('entity')` when the token names an organization that will not resolve |
|
|
89
|
+
| `scope.entityKeyOf()` | The value to store and query organization-scoped records by — `req.entity?.id`, falling back to the token's slug where no resolver exists |
|
|
90
|
+
| `scope.requireEntityKey()` | Same, throwing `AuthorizationError` when the request carries no organization |
|
|
91
|
+
| `scope.requireEntity()` | The full `ResolvedEntity` (`id`, `slug`, `iamKey`), throwing `AuthorizationError` when nothing resolved |
|
|
92
|
+
|
|
93
|
+
`scope.attachEntity(context)` must be called wherever authentication is **established** — the HTTP
|
|
94
|
+
boundary, and any socket that authenticates after its connection is already open. A path that
|
|
95
|
+
authenticates without it leaves `request.entity` empty and its handlers silently compare a slug
|
|
96
|
+
against stored ids.
|
|
97
|
+
|
|
98
|
+
A guard may attach the entity itself when its authority names the organization — the OIDC guard does
|
|
99
|
+
for a session of a tenanted client (`@owlmeans/oidc`), whose relying party has no registry to
|
|
100
|
+
resolve from. `scope.attachEntity` trusts that attachment only while its `slug` is the token's
|
|
101
|
+
`authHelper.entitySlugOf(request.auth)`; on any mismatch it removes it and resolves as if nothing
|
|
102
|
+
had been attached, so a stale or foreign entity can never reach a handler. That attached entity is
|
|
103
|
+
keyed by the organization's frozen IAM key (`{ id: entityKey, slug, iamKey: entityKey }`) — the
|
|
104
|
+
registry's record id never leaves the provider — so on such a relying party
|
|
105
|
+
`scope.requireEntityKey()` answers the `entityKey`, which survives a rename exactly as a record id
|
|
106
|
+
would.
|
|
107
|
+
|
|
108
|
+
Never build a user-facing name (a hostname, a display label) from `scope.entityKeyOf()`. Those want
|
|
109
|
+
the current slug, `req.entity?.slug`.
|
|
107
110
|
|
|
108
111
|
## Usage
|
|
109
112
|
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { BasicContext } from '@owlmeans/context';
|
|
2
|
+
import type { ResolvedEntity } from '@owlmeans/entrypoint';
|
|
3
|
+
/** The organization entity one request acts for — built once at the top of a handler, never stored. */
|
|
4
|
+
export interface EntityScope {
|
|
5
|
+
/**
|
|
6
|
+
* The value a handler should store and query organization-scoped records by.
|
|
7
|
+
*
|
|
8
|
+
* Prefers the entity's stable id, which is the whole point of resolving one: records keyed by it
|
|
9
|
+
* survive a rename untouched. Falls back to the slug on the token for deployments that register no
|
|
10
|
+
* resolver — there the slug IS the only identifier the system has, and refusing to serve them
|
|
11
|
+
* would break every installation backed by an external IAM.
|
|
12
|
+
*
|
|
13
|
+
* Never use this to compose a user-facing name (a hostname, a display label). Those want the
|
|
14
|
+
* current slug, `req.entity?.slug`, precisely because it can change.
|
|
15
|
+
*/
|
|
16
|
+
entityKeyOf: () => string | undefined;
|
|
17
|
+
/**
|
|
18
|
+
* `entityKeyOf` for handlers that cannot proceed without an organization.
|
|
19
|
+
*
|
|
20
|
+
* @throws {AuthorizationError} when the request carries no organization at all.
|
|
21
|
+
*/
|
|
22
|
+
requireEntityKey: () => string;
|
|
23
|
+
/**
|
|
24
|
+
* The full resolved entity, for handlers that need the slug or the frozen key as well as the id.
|
|
25
|
+
*
|
|
26
|
+
* @throws {AuthorizationError} when no resolver is registered or the entity did not resolve.
|
|
27
|
+
*/
|
|
28
|
+
requireEntity: () => ResolvedEntity;
|
|
29
|
+
/**
|
|
30
|
+
* Resolve the organization a just-authenticated request acts for, and attach it.
|
|
31
|
+
*
|
|
32
|
+
* Called wherever authentication is ESTABLISHED — the HTTP boundary, and any socket that
|
|
33
|
+
* authenticates on its own once the connection is already open. Both need it for the same reason:
|
|
34
|
+
* the token names the organization by a slug that can move, while everything downstream keys on
|
|
35
|
+
* the record. A path that authenticates without calling this leaves `request.entity` empty, and
|
|
36
|
+
* its handlers quietly fall back to comparing a slug against stored ids — which surfaces as "this
|
|
37
|
+
* project does not exist" rather than as a missing resolution, and costs an afternoon to find.
|
|
38
|
+
*
|
|
39
|
+
* An entity the guard already attached is kept while its slug is exactly the token's: a guard
|
|
40
|
+
* whose authority names the organization itself (an OIDC session of a tenanted client) is the only
|
|
41
|
+
* source such a deployment has, because the registry that owns the organization is not its own.
|
|
42
|
+
* One whose slug differs is never trusted — it is dropped, and resolution proceeds as if it had
|
|
43
|
+
* not been there.
|
|
44
|
+
*
|
|
45
|
+
* Otherwise a no-op when no resolver is registered: such a deployment has no organization store,
|
|
46
|
+
* and the slug is the only identifier it has.
|
|
47
|
+
*
|
|
48
|
+
* @throws {AuthenFailed} when the token names an organization that cannot be resolved.
|
|
49
|
+
*/
|
|
50
|
+
attachEntity: (context: BasicContext<any>) => Promise<ResolvedEntity | undefined>;
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/entity/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AACrD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAE1D,uGAAuG;AACvG,MAAM,WAAW,WAAW;IAC1B;;;;;;;;;;OAUG;IACH,WAAW,EAAE,MAAM,MAAM,GAAG,SAAS,CAAA;IACrC;;;;OAIG;IACH,gBAAgB,EAAE,MAAM,MAAM,CAAA;IAC9B;;;;OAIG;IACH,aAAa,EAAE,MAAM,cAAc,CAAA;IACnC;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,YAAY,EAAE,CAAC,OAAO,EAAE,YAAY,CAAC,GAAG,CAAC,KAAK,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC,CAAA;CAClF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/entity/types.ts"],"names":[],"mappings":""}
|
package/build/entity.d.ts
CHANGED
|
@@ -1,49 +1,11 @@
|
|
|
1
1
|
import type { AbstractRequest, ResolvedEntity } from '@owlmeans/entrypoint';
|
|
2
2
|
import type { BasicContext } from '@owlmeans/context';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
* Prefers the entity's stable id, which is the whole point of resolving one: records keyed by it
|
|
7
|
-
* survive a rename untouched. Falls back to the slug on the token for deployments that register no
|
|
8
|
-
* resolver — there the slug IS the only identifier the system has, and refusing to serve them
|
|
9
|
-
* would break every installation backed by an external IAM.
|
|
10
|
-
*
|
|
11
|
-
* Never use this to compose a user-facing name (a hostname, a display label). Those want the
|
|
12
|
-
* current slug, `req.entity?.slug`, precisely because it can change.
|
|
13
|
-
*/
|
|
3
|
+
import type { EntityScope } from './entity/types.js';
|
|
4
|
+
export declare const makeEntityScope: (req: AbstractRequest) => EntityScope;
|
|
5
|
+
/** @deprecated compat:factory-refactor — use `makeEntityScope(req).entityKeyOf()` */
|
|
14
6
|
export declare const entityKeyOf: (req: AbstractRequest) => string | undefined;
|
|
15
|
-
/**
|
|
16
|
-
* `entityKeyOf` for handlers that cannot proceed without an organization.
|
|
17
|
-
*
|
|
18
|
-
* @throws {AuthorizationError} when the request carries no organization at all.
|
|
19
|
-
*/
|
|
7
|
+
/** @deprecated compat:factory-refactor — use `makeEntityScope(req).requireEntityKey()` */
|
|
20
8
|
export declare const requireEntityKey: (req: AbstractRequest) => string;
|
|
21
|
-
/**
|
|
22
|
-
* The full resolved entity, for handlers that need the slug or the frozen key as well as the id.
|
|
23
|
-
*
|
|
24
|
-
* @throws {AuthorizationError} when no resolver is registered or the entity did not resolve.
|
|
25
|
-
*/
|
|
26
|
-
export declare const requireEntity: (req: AbstractRequest) => ResolvedEntity;
|
|
27
|
-
/**
|
|
28
|
-
* Resolve the organization a just-authenticated request acts for, and attach it.
|
|
29
|
-
*
|
|
30
|
-
* Called wherever authentication is ESTABLISHED — the HTTP boundary, and any socket that
|
|
31
|
-
* authenticates on its own once the connection is already open. Both need it for the same reason:
|
|
32
|
-
* the token names the organization by a slug that can move, while everything downstream keys on
|
|
33
|
-
* the record. A path that authenticates without calling this leaves `request.entity` empty, and
|
|
34
|
-
* its handlers quietly fall back to comparing a slug against stored ids — which surfaces as "this
|
|
35
|
-
* project does not exist" rather than as a missing resolution, and costs an afternoon to find.
|
|
36
|
-
*
|
|
37
|
-
* An entity the guard already attached is kept while its slug is exactly the token's: a guard
|
|
38
|
-
* whose authority names the organization itself (an OIDC session of a tenanted client) is the only
|
|
39
|
-
* source such a deployment has, because the registry that owns the organization is not its own.
|
|
40
|
-
* One whose slug differs is never trusted — it is dropped, and resolution proceeds as if it had
|
|
41
|
-
* not been there.
|
|
42
|
-
*
|
|
43
|
-
* Otherwise a no-op when no resolver is registered: such a deployment has no organization store,
|
|
44
|
-
* and the slug is the only identifier it has.
|
|
45
|
-
*
|
|
46
|
-
* @throws {AuthenFailed} when the token names an organization that cannot be resolved.
|
|
47
|
-
*/
|
|
9
|
+
/** @deprecated compat:factory-refactor — use `makeEntityScope(request).attachEntity(context)` */
|
|
48
10
|
export declare const attachEntity: (context: BasicContext<any>, request: AbstractRequest) => Promise<ResolvedEntity | undefined>;
|
|
49
11
|
//# sourceMappingURL=entity.d.ts.map
|
package/build/entity.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entity.d.ts","sourceRoot":"","sources":["../src/entity.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAC3E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;
|
|
1
|
+
{"version":3,"file":"entity.d.ts","sourceRoot":"","sources":["../src/entity.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAC3E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAIrD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAEpD,eAAO,MAAM,eAAe,QAAS,eAAe,KAAG,WAgDtD,CAAA;AAED,qFAAqF;AACrF,eAAO,MAAM,WAAW,QAAS,eAAe,KAAG,MAAM,GAAG,SAA+C,CAAA;AAE3G,0FAA0F;AAC1F,eAAO,MAAM,gBAAgB,QAAS,eAAe,KAAG,MAAiD,CAAA;AAEzG,iGAAiG;AACjG,eAAO,MAAM,YAAY,YACd,YAAY,CAAC,GAAG,CAAC,WAAW,eAAe,KACnD,OAAO,CAAC,cAAc,GAAG,SAAS,CAAyD,CAAA"}
|
package/build/entity.js
CHANGED
|
@@ -1,80 +1,47 @@
|
|
|
1
|
-
import { AuthenFailed, AuthorizationError,
|
|
1
|
+
import { AuthenFailed, AuthorizationError, authHelper } from '@owlmeans/auth';
|
|
2
2
|
import { ENTITY_RESOLVER } from './consts.js';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
export const requireEntity = (req) => {
|
|
33
|
-
if (req.entity == null) {
|
|
34
|
-
throw new AuthorizationError();
|
|
35
|
-
}
|
|
36
|
-
return req.entity;
|
|
37
|
-
};
|
|
38
|
-
/**
|
|
39
|
-
* Resolve the organization a just-authenticated request acts for, and attach it.
|
|
40
|
-
*
|
|
41
|
-
* Called wherever authentication is ESTABLISHED — the HTTP boundary, and any socket that
|
|
42
|
-
* authenticates on its own once the connection is already open. Both need it for the same reason:
|
|
43
|
-
* the token names the organization by a slug that can move, while everything downstream keys on
|
|
44
|
-
* the record. A path that authenticates without calling this leaves `request.entity` empty, and
|
|
45
|
-
* its handlers quietly fall back to comparing a slug against stored ids — which surfaces as "this
|
|
46
|
-
* project does not exist" rather than as a missing resolution, and costs an afternoon to find.
|
|
47
|
-
*
|
|
48
|
-
* An entity the guard already attached is kept while its slug is exactly the token's: a guard
|
|
49
|
-
* whose authority names the organization itself (an OIDC session of a tenanted client) is the only
|
|
50
|
-
* source such a deployment has, because the registry that owns the organization is not its own.
|
|
51
|
-
* One whose slug differs is never trusted — it is dropped, and resolution proceeds as if it had
|
|
52
|
-
* not been there.
|
|
53
|
-
*
|
|
54
|
-
* Otherwise a no-op when no resolver is registered: such a deployment has no organization store,
|
|
55
|
-
* and the slug is the only identifier it has.
|
|
56
|
-
*
|
|
57
|
-
* @throws {AuthenFailed} when the token names an organization that cannot be resolved.
|
|
58
|
-
*/
|
|
59
|
-
export const attachEntity = async (context, request) => {
|
|
60
|
-
const slug = entitySlugOf(request.auth);
|
|
61
|
-
if (request.entity != null) {
|
|
62
|
-
if (slug != null && request.entity.slug === slug) {
|
|
63
|
-
return request.entity;
|
|
3
|
+
export const makeEntityScope = (req) => {
|
|
4
|
+
const entityKeyOf = () => req.entity?.id ?? authHelper.entitySlugOf(req.auth);
|
|
5
|
+
const requireEntityKey = () => {
|
|
6
|
+
const key = entityKeyOf();
|
|
7
|
+
if (key == null || key === '') {
|
|
8
|
+
throw new AuthorizationError();
|
|
9
|
+
}
|
|
10
|
+
return key;
|
|
11
|
+
};
|
|
12
|
+
const requireEntity = () => {
|
|
13
|
+
if (req.entity == null) {
|
|
14
|
+
throw new AuthorizationError();
|
|
15
|
+
}
|
|
16
|
+
return req.entity;
|
|
17
|
+
};
|
|
18
|
+
const attachEntity = async (context) => {
|
|
19
|
+
const slug = authHelper.entitySlugOf(req.auth);
|
|
20
|
+
if (req.entity != null) {
|
|
21
|
+
if (slug != null && req.entity.slug === slug) {
|
|
22
|
+
return req.entity;
|
|
23
|
+
}
|
|
24
|
+
req.entity = undefined;
|
|
25
|
+
}
|
|
26
|
+
if (slug == null || !context.hasService(ENTITY_RESOLVER)) {
|
|
27
|
+
return undefined;
|
|
28
|
+
}
|
|
29
|
+
const entity = await context.service(ENTITY_RESOLVER).resolve(slug);
|
|
30
|
+
if (entity == null) {
|
|
31
|
+
throw new AuthenFailed('entity');
|
|
64
32
|
}
|
|
65
|
-
request
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
throw new AuthenFailed('entity');
|
|
73
|
-
}
|
|
74
|
-
// Canonicalize: a request that arrived under a retired slug continues under the current one, so
|
|
75
|
-
// nothing echoing the value back can re-publish a name the organization has dropped.
|
|
76
|
-
request.auth.entitySlug = entity.slug;
|
|
77
|
-
request.entity = entity;
|
|
78
|
-
return entity;
|
|
33
|
+
// Canonicalize: a request that arrived under a retired slug continues under the current one, so
|
|
34
|
+
// nothing echoing the value back can re-publish a name the organization has dropped.
|
|
35
|
+
req.auth.entitySlug = entity.slug;
|
|
36
|
+
req.entity = entity;
|
|
37
|
+
return entity;
|
|
38
|
+
};
|
|
39
|
+
return { entityKeyOf, requireEntityKey, requireEntity, attachEntity };
|
|
79
40
|
};
|
|
41
|
+
/** @deprecated compat:factory-refactor — use `makeEntityScope(req).entityKeyOf()` */
|
|
42
|
+
export const entityKeyOf = (req) => makeEntityScope(req).entityKeyOf();
|
|
43
|
+
/** @deprecated compat:factory-refactor — use `makeEntityScope(req).requireEntityKey()` */
|
|
44
|
+
export const requireEntityKey = (req) => makeEntityScope(req).requireEntityKey();
|
|
45
|
+
/** @deprecated compat:factory-refactor — use `makeEntityScope(request).attachEntity(context)` */
|
|
46
|
+
export const attachEntity = async (context, request) => await makeEntityScope(request).attachEntity(context);
|
|
80
47
|
//# sourceMappingURL=entity.js.map
|
package/build/entity.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entity.js","sourceRoot":"","sources":["../src/entity.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,
|
|
1
|
+
{"version":3,"file":"entity.js","sourceRoot":"","sources":["../src/entity.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAE7E,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAG7C,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,GAAoB,EAAe,EAAE;IACnE,MAAM,WAAW,GAAG,GAAuB,EAAE,CAC3C,GAAG,CAAC,MAAM,EAAE,EAAE,IAAI,UAAU,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;IAErD,MAAM,gBAAgB,GAAG,GAAW,EAAE;QACpC,MAAM,GAAG,GAAG,WAAW,EAAE,CAAA;QACzB,IAAI,GAAG,IAAI,IAAI,IAAI,GAAG,KAAK,EAAE,EAAE,CAAC;YAC9B,MAAM,IAAI,kBAAkB,EAAE,CAAA;QAChC,CAAC;QAED,OAAO,GAAG,CAAA;IACZ,CAAC,CAAA;IAED,MAAM,aAAa,GAAG,GAAmB,EAAE;QACzC,IAAI,GAAG,CAAC,MAAM,IAAI,IAAI,EAAE,CAAC;YACvB,MAAM,IAAI,kBAAkB,EAAE,CAAA;QAChC,CAAC;QAED,OAAO,GAAG,CAAC,MAAM,CAAA;IACnB,CAAC,CAAA;IAED,MAAM,YAAY,GAAG,KAAK,EAAE,OAA0B,EAAuC,EAAE;QAC7F,MAAM,IAAI,GAAG,UAAU,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;QAC9C,IAAI,GAAG,CAAC,MAAM,IAAI,IAAI,EAAE,CAAC;YACvB,IAAI,IAAI,IAAI,IAAI,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;gBAC7C,OAAO,GAAG,CAAC,MAAM,CAAA;YACnB,CAAC;YACD,GAAG,CAAC,MAAM,GAAG,SAAS,CAAA;QACxB,CAAC;QAED,IAAI,IAAI,IAAI,IAAI,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,eAAe,CAAC,EAAE,CAAC;YACzD,OAAO,SAAS,CAAA;QAClB,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,OAAO,CAAwB,eAAe,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;QAC1F,IAAI,MAAM,IAAI,IAAI,EAAE,CAAC;YACnB,MAAM,IAAI,YAAY,CAAC,QAAQ,CAAC,CAAA;QAClC,CAAC;QAED,gGAAgG;QAChG,qFAAqF;QACrF,GAAG,CAAC,IAAK,CAAC,UAAU,GAAG,MAAM,CAAC,IAAI,CAAA;QAClC,GAAG,CAAC,MAAM,GAAG,MAAM,CAAA;QAEnB,OAAO,MAAM,CAAA;IACf,CAAC,CAAA;IAED,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,aAAa,EAAE,YAAY,EAAE,CAAA;AACvE,CAAC,CAAA;AAED,qFAAqF;AACrF,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,GAAoB,EAAsB,EAAE,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,CAAA;AAE3G,0FAA0F;AAC1F,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,GAAoB,EAAU,EAAE,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,gBAAgB,EAAE,CAAA;AAEzG,iGAAiG;AACjG,MAAM,CAAC,MAAM,YAAY,GAAG,KAAK,EAC/B,OAA0B,EAAE,OAAwB,EACf,EAAE,CAAC,MAAM,eAAe,CAAC,OAAO,CAAC,CAAC,YAAY,CAAC,OAAO,CAAC,CAAA"}
|
package/build/entrypoints.d.ts
CHANGED
|
@@ -19,10 +19,10 @@ export declare const authProtocols: {
|
|
|
19
19
|
flowEnter: import("@owlmeans/entrypoint").EntrypointProtocol<import("@owlmeans/entrypoint").OpenRequest, import("@owlmeans/entrypoint").OpenValue>;
|
|
20
20
|
dispatcher: import("@owlmeans/entrypoint").EntrypointProtocol<{
|
|
21
21
|
query: AuthToken;
|
|
22
|
-
},
|
|
22
|
+
}, unknown>;
|
|
23
23
|
surrogate: import("@owlmeans/entrypoint").EntrypointProtocol<{
|
|
24
24
|
query: SurrogateQuery;
|
|
25
|
-
},
|
|
25
|
+
}, unknown>;
|
|
26
26
|
dispatcherAuthenticate: import("@owlmeans/entrypoint").EntrypointProtocol<{
|
|
27
27
|
body: AuthToken;
|
|
28
28
|
}, AuthToken>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consts.local.d.ts","sourceRoot":"","sources":["../../../src/guards/basic-ed25519/consts.local.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,OAAO,QAAyC,CAAA;AAC7D,eAAO,MAAM,QAAQ,QAA0C,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consts.local.js","sourceRoot":"","sources":["../../../src/guards/basic-ed25519/consts.local.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AAErE,MAAM,CAAC,MAAM,OAAO,GAAG,kBAAkB,CAAC,iBAAiB,EAAE,CAAA;AAC7D,MAAM,CAAC,MAAM,QAAQ,GAAG,mBAAmB,CAAC,iBAAiB,EAAE,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../src/guards/basic-ed25519/service.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../src/guards/basic-ed25519/service.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,iBAAiB,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAA;AAU7E,eAAO,MAAM,qBAAqB,aAAc,MAAM,SAAS,wBAAwB,KAAG,iBA+IzF,CAAA"}
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import { createService } from '@owlmeans/context';
|
|
2
2
|
import { assertContext } from '@owlmeans/context';
|
|
3
|
-
import {
|
|
3
|
+
import { BED255_CASHE_RESOURCE, GUARD_ED25519, BED255_SIG_TTL } from './consts.js';
|
|
4
|
+
import { nonceKey, timeKey } from './consts.local.js';
|
|
4
5
|
import { trust } from '../../utils/trusted.js';
|
|
5
6
|
import { AuthenPayloadError, AuthroizationType, AuthRole } from '@owlmeans/auth';
|
|
6
7
|
import { createIdOfLength } from '@owlmeans/basic-ids';
|
|
7
8
|
import { extractAuthToken } from '@owlmeans/auth-common/utils';
|
|
8
9
|
import { makeMemorySignedRequestReplayStore, makeResourceSignedRequestReplayStore } from './replay.js';
|
|
9
|
-
const timeKey = BED255_TIME_HEADER.toLocaleLowerCase();
|
|
10
|
-
const nonceKey = BED255_NONCE_HEADER.toLocaleLowerCase();
|
|
11
10
|
export const makeBasicEd25519Guard = (resource, opts) => {
|
|
12
11
|
const memoryReplay = makeMemorySignedRequestReplayStore();
|
|
13
12
|
const replay = (context) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.js","sourceRoot":"","sources":["../../../src/guards/basic-ed25519/service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AAEjD,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AACjD,OAAO,
|
|
1
|
+
{"version":3,"file":"service.js","sourceRoot":"","sources":["../../../src/guards/basic-ed25519/service.ts"],"names":[],"mappings":"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"}
|
package/build/index.d.ts
CHANGED
package/build/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,mBAAmB,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,mBAAmB,YAAY,CAAA;AAC/B,mBAAmB,mBAAmB,CAAA;AAEtC,cAAc,cAAc,CAAA;AAC5B,cAAc,kBAAkB,CAAA;AAChC,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA;AAC3B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,mBAAmB,CAAA"}
|
package/build/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,cAAc,cAAc,CAAA;AAC5B,cAAc,kBAAkB,CAAA;AAChC,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA;AAC3B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,mBAAmB,CAAA"}
|
package/build/middleware.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { MiddlewareType, MiddlewareStage, AppType } from '@owlmeans/context';
|
|
2
|
-
import { provideRequest } from '@owlmeans/client-entrypoint';
|
|
3
2
|
import { AUTH_HEADER } from '@owlmeans/auth';
|
|
3
|
+
import { clientRequestHelper } from '@owlmeans/client-entrypoint';
|
|
4
4
|
export const authMiddleware = {
|
|
5
5
|
type: MiddlewareType.Context,
|
|
6
6
|
stage: MiddlewareStage.Loading,
|
|
@@ -22,7 +22,7 @@ export const authMiddleware = {
|
|
|
22
22
|
// middleware wrapped this entrypoint.
|
|
23
23
|
const [token] = (await Promise.all(module.getGuards().map(guard => context.service(guard).authenticated(req)))).filter(token => token != null).reverse();
|
|
24
24
|
if (token != null) {
|
|
25
|
-
const _req = req ?? provideRequest(module.alias, module.path());
|
|
25
|
+
const _req = req ?? clientRequestHelper.provideRequest(module.alias, module.path());
|
|
26
26
|
const headers = (_req.headers ?? {});
|
|
27
27
|
if (headers[AUTH_HEADER] == null) {
|
|
28
28
|
headers[AUTH_HEADER] = token;
|
package/build/middleware.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"middleware.js","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,cAAc,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAA;AAC7F,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"middleware.js","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,cAAc,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAA;AAC7F,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAG5C,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAA;AAEjE,MAAM,CAAC,MAAM,cAAc,GAAe;IACxC,IAAI,EAAE,cAAc,CAAC,OAAO;IAC5B,KAAK,EAAE,eAAe,CAAC,OAAO;IAC9B,KAAK,EAAE,KAAK,EAAC,OAAO,EAAC,EAAE;QACrB,OAAO,CAAC,WAAW,EAAU,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE;YAC7C,IAAI,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,KAAK,OAAO,CAAC,OAAO,IAAI,MAAM,CAAC,MAAM,IAAI,IAAI,EAAE,CAAC;gBACzE,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBAClC,IAAI,MAAM,CAAC,+BAA+B,KAAK,IAAI,EAAE,CAAC;wBACpD,OAAM;oBACR,CAAC;oBACD,MAAM,CAAC,+BAA+B,GAAG,IAAI,CAAA;oBAC7C,uFAAuF;oBACvF,iEAAiE;oBACjE,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAA;oBAC5B,MAAM,CAAC,MAAM,GAAG,CAAC,KAAK,EAAC,GAAG,EAAC,EAAE;wBAC3B,+EAA+E;wBAC/E,sCAAsC;wBACtC,8EAA8E;wBAC9E,sCAAsC;wBACtC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,GAAG,CACvD,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,OAAO,CAAe,KAAK,CAAC,CAAC,aAAa,CAAC,GAAG,CAAC,CACjE,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC,OAAO,EAAE,CAAA;wBAC5C,IAAI,KAAK,IAAI,IAAI,EAAE,CAAC;4BAClB,MAAM,IAAI,GAA6B,GAAG,IAAI,mBAAmB,CAAC,cAAc,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC,CAAA;4BAC7G,MAAM,OAAO,GAAG,CAAC,IAAI,CAAC,OAAO,IAAI,EAAE,CAAuC,CAAA;4BAC1E,IAAI,OAAO,CAAC,WAAW,CAAC,IAAI,IAAI,EAAE,CAAC;gCACjC,OAAO,CAAC,WAAW,CAAC,GAAG,KAAK,CAAA;gCAC5B,IAAI,CAAC,OAAO,GAAG,OAAO,CAAA;gCACtB,GAAG,GAAG,IAAkB,CAAA;4BAC1B,CAAC;wBACH,CAAC;wBAED,OAAO,MAAM,CAAC,GAAG,CAAC,CAAA;oBACpB,CAAC,CAAyB,CAAA;gBAE5B,CAAC;YACH,CAAC;QACH,CAAC,CAAC,CAAA;IACJ,CAAC;CACF,CAAA"}
|
package/build/utils/trusted.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { keyHelper, makeKeyPairModel } from '@owlmeans/basic-keys';
|
|
2
2
|
export const trust = async (context, resource, userName, field = 'name') => {
|
|
3
3
|
const where = { [field]: userName };
|
|
4
4
|
const trustedUser = await context.resource(resource).load(where);
|
|
@@ -6,7 +6,7 @@ export const trust = async (context, resource, userName, field = 'name') => {
|
|
|
6
6
|
throw new SyntaxError(`Auth service trusted entity is not provided: ${userName}`);
|
|
7
7
|
}
|
|
8
8
|
// @TODO credential can really be undefined - we need to process it properly
|
|
9
|
-
const keyPair = trustedUser.secret != null ? makeKeyPairModel(trustedUser.secret) : fromPubKey(trustedUser.credential);
|
|
9
|
+
const keyPair = trustedUser.secret != null ? makeKeyPairModel(trustedUser.secret) : keyHelper.fromPubKey(trustedUser.credential);
|
|
10
10
|
return { user: trustedUser, key: keyPair };
|
|
11
11
|
};
|
|
12
12
|
//# sourceMappingURL=trusted.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"trusted.js","sourceRoot":"","sources":["../../src/utils/trusted.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"trusted.js","sourceRoot":"","sources":["../../src/utils/trusted.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AAElE,MAAM,CAAC,MAAM,KAAK,GAAG,KAAK,EAA0C,OAAU,EAAE,QAAgB,EAAE,QAAgB,EAAE,KAAK,GAAW,MAAM,EAAE,EAAE;IAC5I,MAAM,KAAK,GAA4B,EAAE,CAAC,KAAK,CAAC,EAAE,QAAQ,EAAE,CAAA;IAC5D,MAAM,WAAW,GAAG,MAAM,OAAO,CAAC,QAAQ,CAA0B,QAAQ,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IACzF,IAAI,WAAW,IAAI,IAAI,EAAE,CAAC;QACxB,MAAM,IAAI,WAAW,CAAC,gDAAgD,QAAQ,EAAE,CAAC,CAAA;IACnF,CAAC;IAED,4EAA4E;IAC5E,MAAM,OAAO,GAAG,WAAW,CAAC,MAAM,IAAI,IAAI,CAAC,CAAC,CAAC,gBAAgB,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,WAAW,CAAC,UAAW,CAAC,CAAA;IAEjI,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,GAAG,EAAE,OAAO,EAAE,CAAA;AAC5C,CAAC,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@owlmeans/auth-common",
|
|
3
|
-
"version": "0.1.18-rc.
|
|
3
|
+
"version": "0.1.18-rc.48",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
@@ -29,19 +29,19 @@
|
|
|
29
29
|
}
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@owlmeans/auth": "^0.1.18-rc.
|
|
33
|
-
"@owlmeans/auth-common": "^0.1.18-rc.
|
|
34
|
-
"@owlmeans/basic-ids": "^0.1.18-rc.
|
|
35
|
-
"@owlmeans/basic-keys": "^0.1.18-rc.
|
|
36
|
-
"@owlmeans/client-entrypoint": "^0.1.18-rc.
|
|
37
|
-
"@owlmeans/context": "^0.1.18-rc.
|
|
38
|
-
"@owlmeans/entrypoint": "^0.1.18-rc.
|
|
39
|
-
"@owlmeans/resource": "^0.1.18-rc.
|
|
40
|
-
"@owlmeans/route": "^0.1.18-rc.
|
|
32
|
+
"@owlmeans/auth": "^0.1.18-rc.40",
|
|
33
|
+
"@owlmeans/auth-common": "^0.1.18-rc.48",
|
|
34
|
+
"@owlmeans/basic-ids": "^0.1.18-rc.38",
|
|
35
|
+
"@owlmeans/basic-keys": "^0.1.18-rc.49",
|
|
36
|
+
"@owlmeans/client-entrypoint": "^0.1.18-rc.48",
|
|
37
|
+
"@owlmeans/context": "^0.1.18-rc.34",
|
|
38
|
+
"@owlmeans/entrypoint": "^0.1.18-rc.41",
|
|
39
|
+
"@owlmeans/resource": "^0.1.18-rc.40",
|
|
40
|
+
"@owlmeans/route": "^0.1.18-rc.35"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"@owlmeans/dep-config": "workspace:*",
|
|
44
|
-
"@owlmeans/test-auth": "^0.1.18-rc.
|
|
44
|
+
"@owlmeans/test-auth": "^0.1.18-rc.47",
|
|
45
45
|
"@types/bun": "^1.4.2",
|
|
46
46
|
"nodemon": "^3.1.14",
|
|
47
47
|
"typescript": "^7.0.2"
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { BasicContext } from '@owlmeans/context'
|
|
2
|
+
import type { ResolvedEntity } from '@owlmeans/entrypoint'
|
|
3
|
+
|
|
4
|
+
/** The organization entity one request acts for — built once at the top of a handler, never stored. */
|
|
5
|
+
export interface EntityScope {
|
|
6
|
+
/**
|
|
7
|
+
* The value a handler should store and query organization-scoped records by.
|
|
8
|
+
*
|
|
9
|
+
* Prefers the entity's stable id, which is the whole point of resolving one: records keyed by it
|
|
10
|
+
* survive a rename untouched. Falls back to the slug on the token for deployments that register no
|
|
11
|
+
* resolver — there the slug IS the only identifier the system has, and refusing to serve them
|
|
12
|
+
* would break every installation backed by an external IAM.
|
|
13
|
+
*
|
|
14
|
+
* Never use this to compose a user-facing name (a hostname, a display label). Those want the
|
|
15
|
+
* current slug, `req.entity?.slug`, precisely because it can change.
|
|
16
|
+
*/
|
|
17
|
+
entityKeyOf: () => string | undefined
|
|
18
|
+
/**
|
|
19
|
+
* `entityKeyOf` for handlers that cannot proceed without an organization.
|
|
20
|
+
*
|
|
21
|
+
* @throws {AuthorizationError} when the request carries no organization at all.
|
|
22
|
+
*/
|
|
23
|
+
requireEntityKey: () => string
|
|
24
|
+
/**
|
|
25
|
+
* The full resolved entity, for handlers that need the slug or the frozen key as well as the id.
|
|
26
|
+
*
|
|
27
|
+
* @throws {AuthorizationError} when no resolver is registered or the entity did not resolve.
|
|
28
|
+
*/
|
|
29
|
+
requireEntity: () => ResolvedEntity
|
|
30
|
+
/**
|
|
31
|
+
* Resolve the organization a just-authenticated request acts for, and attach it.
|
|
32
|
+
*
|
|
33
|
+
* Called wherever authentication is ESTABLISHED — the HTTP boundary, and any socket that
|
|
34
|
+
* authenticates on its own once the connection is already open. Both need it for the same reason:
|
|
35
|
+
* the token names the organization by a slug that can move, while everything downstream keys on
|
|
36
|
+
* the record. A path that authenticates without calling this leaves `request.entity` empty, and
|
|
37
|
+
* its handlers quietly fall back to comparing a slug against stored ids — which surfaces as "this
|
|
38
|
+
* project does not exist" rather than as a missing resolution, and costs an afternoon to find.
|
|
39
|
+
*
|
|
40
|
+
* An entity the guard already attached is kept while its slug is exactly the token's: a guard
|
|
41
|
+
* whose authority names the organization itself (an OIDC session of a tenanted client) is the only
|
|
42
|
+
* source such a deployment has, because the registry that owns the organization is not its own.
|
|
43
|
+
* One whose slug differs is never trusted — it is dropped, and resolution proceeds as if it had
|
|
44
|
+
* not been there.
|
|
45
|
+
*
|
|
46
|
+
* Otherwise a no-op when no resolver is registered: such a deployment has no organization store,
|
|
47
|
+
* and the slug is the only identifier it has.
|
|
48
|
+
*
|
|
49
|
+
* @throws {AuthenFailed} when the token names an organization that cannot be resolved.
|
|
50
|
+
*/
|
|
51
|
+
attachEntity: (context: BasicContext<any>) => Promise<ResolvedEntity | undefined>
|
|
52
|
+
}
|
package/src/entity.ts
CHANGED
|
@@ -1,95 +1,67 @@
|
|
|
1
1
|
import type { AbstractRequest, ResolvedEntity } from '@owlmeans/entrypoint'
|
|
2
2
|
import type { BasicContext } from '@owlmeans/context'
|
|
3
|
-
import { AuthenFailed, AuthorizationError,
|
|
3
|
+
import { AuthenFailed, AuthorizationError, authHelper } from '@owlmeans/auth'
|
|
4
4
|
import type { EntityResolverService } from './types.js'
|
|
5
5
|
import { ENTITY_RESOLVER } from './consts.js'
|
|
6
|
+
import type { EntityScope } from './entity/types.js'
|
|
6
7
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
* Prefers the entity's stable id, which is the whole point of resolving one: records keyed by it
|
|
11
|
-
* survive a rename untouched. Falls back to the slug on the token for deployments that register no
|
|
12
|
-
* resolver — there the slug IS the only identifier the system has, and refusing to serve them
|
|
13
|
-
* would break every installation backed by an external IAM.
|
|
14
|
-
*
|
|
15
|
-
* Never use this to compose a user-facing name (a hostname, a display label). Those want the
|
|
16
|
-
* current slug, `req.entity?.slug`, precisely because it can change.
|
|
17
|
-
*/
|
|
18
|
-
export const entityKeyOf = (req: AbstractRequest): string | undefined =>
|
|
19
|
-
req.entity?.id ?? entitySlugOf(req.auth)
|
|
8
|
+
export const makeEntityScope = (req: AbstractRequest): EntityScope => {
|
|
9
|
+
const entityKeyOf = (): string | undefined =>
|
|
10
|
+
req.entity?.id ?? authHelper.entitySlugOf(req.auth)
|
|
20
11
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
if (key == null || key === '') {
|
|
29
|
-
throw new AuthorizationError()
|
|
12
|
+
const requireEntityKey = (): string => {
|
|
13
|
+
const key = entityKeyOf()
|
|
14
|
+
if (key == null || key === '') {
|
|
15
|
+
throw new AuthorizationError()
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return key
|
|
30
19
|
}
|
|
31
20
|
|
|
32
|
-
|
|
33
|
-
|
|
21
|
+
const requireEntity = (): ResolvedEntity => {
|
|
22
|
+
if (req.entity == null) {
|
|
23
|
+
throw new AuthorizationError()
|
|
24
|
+
}
|
|
34
25
|
|
|
35
|
-
|
|
36
|
-
* The full resolved entity, for handlers that need the slug or the frozen key as well as the id.
|
|
37
|
-
*
|
|
38
|
-
* @throws {AuthorizationError} when no resolver is registered or the entity did not resolve.
|
|
39
|
-
*/
|
|
40
|
-
export const requireEntity = (req: AbstractRequest): ResolvedEntity => {
|
|
41
|
-
if (req.entity == null) {
|
|
42
|
-
throw new AuthorizationError()
|
|
26
|
+
return req.entity
|
|
43
27
|
}
|
|
44
28
|
|
|
45
|
-
|
|
46
|
-
|
|
29
|
+
const attachEntity = async (context: BasicContext<any>): Promise<ResolvedEntity | undefined> => {
|
|
30
|
+
const slug = authHelper.entitySlugOf(req.auth)
|
|
31
|
+
if (req.entity != null) {
|
|
32
|
+
if (slug != null && req.entity.slug === slug) {
|
|
33
|
+
return req.entity
|
|
34
|
+
}
|
|
35
|
+
req.entity = undefined
|
|
36
|
+
}
|
|
47
37
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
*
|
|
51
|
-
* Called wherever authentication is ESTABLISHED — the HTTP boundary, and any socket that
|
|
52
|
-
* authenticates on its own once the connection is already open. Both need it for the same reason:
|
|
53
|
-
* the token names the organization by a slug that can move, while everything downstream keys on
|
|
54
|
-
* the record. A path that authenticates without calling this leaves `request.entity` empty, and
|
|
55
|
-
* its handlers quietly fall back to comparing a slug against stored ids — which surfaces as "this
|
|
56
|
-
* project does not exist" rather than as a missing resolution, and costs an afternoon to find.
|
|
57
|
-
*
|
|
58
|
-
* An entity the guard already attached is kept while its slug is exactly the token's: a guard
|
|
59
|
-
* whose authority names the organization itself (an OIDC session of a tenanted client) is the only
|
|
60
|
-
* source such a deployment has, because the registry that owns the organization is not its own.
|
|
61
|
-
* One whose slug differs is never trusted — it is dropped, and resolution proceeds as if it had
|
|
62
|
-
* not been there.
|
|
63
|
-
*
|
|
64
|
-
* Otherwise a no-op when no resolver is registered: such a deployment has no organization store,
|
|
65
|
-
* and the slug is the only identifier it has.
|
|
66
|
-
*
|
|
67
|
-
* @throws {AuthenFailed} when the token names an organization that cannot be resolved.
|
|
68
|
-
*/
|
|
69
|
-
export const attachEntity = async (
|
|
70
|
-
context: BasicContext<any>, request: AbstractRequest
|
|
71
|
-
): Promise<ResolvedEntity | undefined> => {
|
|
72
|
-
const slug = entitySlugOf(request.auth)
|
|
73
|
-
if (request.entity != null) {
|
|
74
|
-
if (slug != null && request.entity.slug === slug) {
|
|
75
|
-
return request.entity
|
|
38
|
+
if (slug == null || !context.hasService(ENTITY_RESOLVER)) {
|
|
39
|
+
return undefined
|
|
76
40
|
}
|
|
77
|
-
request.entity = undefined
|
|
78
|
-
}
|
|
79
41
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
42
|
+
const entity = await context.service<EntityResolverService>(ENTITY_RESOLVER).resolve(slug)
|
|
43
|
+
if (entity == null) {
|
|
44
|
+
throw new AuthenFailed('entity')
|
|
45
|
+
}
|
|
83
46
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
47
|
+
// Canonicalize: a request that arrived under a retired slug continues under the current one, so
|
|
48
|
+
// nothing echoing the value back can re-publish a name the organization has dropped.
|
|
49
|
+
req.auth!.entitySlug = entity.slug
|
|
50
|
+
req.entity = entity
|
|
88
51
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
request.auth!.entitySlug = entity.slug
|
|
92
|
-
request.entity = entity
|
|
52
|
+
return entity
|
|
53
|
+
}
|
|
93
54
|
|
|
94
|
-
return
|
|
55
|
+
return { entityKeyOf, requireEntityKey, requireEntity, attachEntity }
|
|
95
56
|
}
|
|
57
|
+
|
|
58
|
+
/** @deprecated compat:factory-refactor — use `makeEntityScope(req).entityKeyOf()` */
|
|
59
|
+
export const entityKeyOf = (req: AbstractRequest): string | undefined => makeEntityScope(req).entityKeyOf()
|
|
60
|
+
|
|
61
|
+
/** @deprecated compat:factory-refactor — use `makeEntityScope(req).requireEntityKey()` */
|
|
62
|
+
export const requireEntityKey = (req: AbstractRequest): string => makeEntityScope(req).requireEntityKey()
|
|
63
|
+
|
|
64
|
+
/** @deprecated compat:factory-refactor — use `makeEntityScope(request).attachEntity(context)` */
|
|
65
|
+
export const attachEntity = async (
|
|
66
|
+
context: BasicContext<any>, request: AbstractRequest
|
|
67
|
+
): Promise<ResolvedEntity | undefined> => await makeEntityScope(request).attachEntity(context)
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import { createService } from '@owlmeans/context'
|
|
2
2
|
import type { AbstractRequest, AbstractResponse } from '@owlmeans/entrypoint'
|
|
3
3
|
import { assertContext } from '@owlmeans/context'
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
BED255_SIG_TTL
|
|
7
|
-
} from './consts.js'
|
|
4
|
+
import { BED255_CASHE_RESOURCE, GUARD_ED25519, BED255_SIG_TTL } from './consts.js'
|
|
5
|
+
import { nonceKey, timeKey } from './consts.local.js'
|
|
8
6
|
import { trust } from '../../utils/trusted.js'
|
|
9
7
|
import type { Config, Context } from '../../utils/types.js'
|
|
10
8
|
import type { BasicEd25519Guard, BasicEd25519GuardOptions } from './types.js'
|
|
@@ -17,9 +15,6 @@ import {
|
|
|
17
15
|
} from './replay.js'
|
|
18
16
|
import type { SignedRequestReplayResource, SignedRequestReplayStore } from './types.js'
|
|
19
17
|
|
|
20
|
-
const timeKey = BED255_TIME_HEADER.toLocaleLowerCase()
|
|
21
|
-
const nonceKey = BED255_NONCE_HEADER.toLocaleLowerCase()
|
|
22
|
-
|
|
23
18
|
export const makeBasicEd25519Guard = (resource: string, opts?: BasicEd25519GuardOptions): BasicEd25519Guard => {
|
|
24
19
|
const memoryReplay = makeMemorySignedRequestReplayStore()
|
|
25
20
|
|
package/src/index.ts
CHANGED
package/src/middleware.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { type Middleware, MiddlewareType, MiddlewareStage, AppType } from '@owlmeans/context'
|
|
2
|
-
import { provideRequest } from '@owlmeans/client-entrypoint'
|
|
3
2
|
import { AUTH_HEADER } from '@owlmeans/auth'
|
|
4
3
|
import type { AbstractRequest, GuardService } from '@owlmeans/entrypoint'
|
|
5
4
|
import type { Perked } from './types.local.js'
|
|
5
|
+
import { clientRequestHelper } from '@owlmeans/client-entrypoint'
|
|
6
6
|
|
|
7
7
|
export const authMiddleware: Middleware = {
|
|
8
8
|
type: MiddlewareType.Context,
|
|
@@ -27,7 +27,7 @@ export const authMiddleware: Middleware = {
|
|
|
27
27
|
guard => context.service<GuardService>(guard).authenticated(req)
|
|
28
28
|
))).filter(token => token != null).reverse()
|
|
29
29
|
if (token != null) {
|
|
30
|
-
const _req: Partial<AbstractRequest> = req ?? provideRequest(module.alias, module.path())
|
|
30
|
+
const _req: Partial<AbstractRequest> = req ?? clientRequestHelper.provideRequest(module.alias, module.path())
|
|
31
31
|
const headers = (_req.headers ?? {}) as Record<string, string | undefined>
|
|
32
32
|
if (headers[AUTH_HEADER] == null) {
|
|
33
33
|
headers[AUTH_HEADER] = token
|
package/src/utils/trusted.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import type { Context, Config } from './types.js'
|
|
3
3
|
import type { TrustedRecord } from '../types.js'
|
|
4
4
|
import type { Criteria, Resource } from '@owlmeans/resource'
|
|
5
|
-
import {
|
|
5
|
+
import { keyHelper, makeKeyPairModel } from '@owlmeans/basic-keys'
|
|
6
6
|
|
|
7
7
|
export const trust = async <C extends Config, T extends Context<C>>(context: T, resource: string, userName: string, field: string = 'name') => {
|
|
8
8
|
const where: Criteria<TrustedRecord> = { [field]: userName }
|
|
@@ -12,7 +12,7 @@ export const trust = async <C extends Config, T extends Context<C>>(context: T,
|
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
// @TODO credential can really be undefined - we need to process it properly
|
|
15
|
-
const keyPair = trustedUser.secret != null ? makeKeyPairModel(trustedUser.secret) : fromPubKey(trustedUser.credential!)
|
|
15
|
+
const keyPair = trustedUser.secret != null ? makeKeyPairModel(trustedUser.secret) : keyHelper.fromPubKey(trustedUser.credential!)
|
|
16
16
|
|
|
17
17
|
return { user: trustedUser, key: keyPair }
|
|
18
18
|
}
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
BED255_NONCE_HEADER, BED255_SIG_TTL, BED255_TIME_HEADER, makeBasicEd25519Guard,
|
|
5
5
|
makeResourceSignedRequestReplayStore
|
|
6
6
|
} from '@owlmeans/auth-common'
|
|
7
|
-
import type { SignedRequestReplayResource } from '@owlmeans/auth-common'
|
|
7
|
+
import type { BasicEd25519Guard, SignedRequestReplayResource } from '@owlmeans/auth-common'
|
|
8
8
|
import type { AbstractRequest, AbstractResponse } from '@owlmeans/entrypoint'
|
|
9
9
|
import type { Auth } from '@owlmeans/auth'
|
|
10
10
|
import { RecordExists } from '@owlmeans/resource'
|
|
@@ -35,7 +35,7 @@ const request = async (timestamp: string, nonce: string) => {
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
const handle = async (
|
|
38
|
-
guard:
|
|
38
|
+
guard: BasicEd25519Guard, req: AbstractRequest
|
|
39
39
|
): Promise<Auth | undefined> => {
|
|
40
40
|
let value: Auth | undefined
|
|
41
41
|
const response: AbstractResponse<Auth> = {
|
package/tests/entity.spec.ts
CHANGED
|
@@ -4,7 +4,7 @@ import type { BasicConfig, BasicContext } from '@owlmeans/context'
|
|
|
4
4
|
import { AuthenFailed, AuthRole } from '@owlmeans/auth'
|
|
5
5
|
import type { Auth } from '@owlmeans/auth'
|
|
6
6
|
import type { AbstractRequest, ResolvedEntity } from '@owlmeans/entrypoint'
|
|
7
|
-
import {
|
|
7
|
+
import { makeEntityScope } from '../src/entity.js'
|
|
8
8
|
import { ENTITY_RESOLVER } from '../src/consts.js'
|
|
9
9
|
import type { EntityResolverService, OrgEntityRef } from '../src/types.js'
|
|
10
10
|
|
|
@@ -47,7 +47,7 @@ describe('attachEntity — an entity the guard attached', () => {
|
|
|
47
47
|
const { ctx } = await contextWith()
|
|
48
48
|
const request = requestFor('tenant', attached)
|
|
49
49
|
|
|
50
|
-
expect(await attachEntity(ctx
|
|
50
|
+
expect(await makeEntityScope(request).attachEntity(ctx)).toEqual(attached)
|
|
51
51
|
expect(request.entity).toEqual(attached)
|
|
52
52
|
})
|
|
53
53
|
|
|
@@ -55,7 +55,7 @@ describe('attachEntity — an entity the guard attached', () => {
|
|
|
55
55
|
const { ctx, calls } = await contextWith([ACME])
|
|
56
56
|
const request = requestFor('tenant', attached)
|
|
57
57
|
|
|
58
|
-
expect(await attachEntity(ctx
|
|
58
|
+
expect(await makeEntityScope(request).attachEntity(ctx)).toEqual(attached)
|
|
59
59
|
expect(calls).toEqual([])
|
|
60
60
|
})
|
|
61
61
|
|
|
@@ -63,7 +63,7 @@ describe('attachEntity — an entity the guard attached', () => {
|
|
|
63
63
|
const { ctx, calls } = await contextWith([ACME])
|
|
64
64
|
const request = requestFor('acme', attached)
|
|
65
65
|
|
|
66
|
-
expect(await attachEntity(ctx
|
|
66
|
+
expect(await makeEntityScope(request).attachEntity(ctx)).toEqual(ACME)
|
|
67
67
|
expect(request.entity).toEqual(ACME)
|
|
68
68
|
expect(calls).toEqual(['acme'])
|
|
69
69
|
})
|
|
@@ -72,7 +72,7 @@ describe('attachEntity — an entity the guard attached', () => {
|
|
|
72
72
|
const { ctx } = await contextWith()
|
|
73
73
|
const request = requestFor('acme', attached)
|
|
74
74
|
|
|
75
|
-
expect(await attachEntity(ctx
|
|
75
|
+
expect(await makeEntityScope(request).attachEntity(ctx)).toBeUndefined()
|
|
76
76
|
expect(request.entity).toBeUndefined()
|
|
77
77
|
})
|
|
78
78
|
|
|
@@ -80,7 +80,7 @@ describe('attachEntity — an entity the guard attached', () => {
|
|
|
80
80
|
const { ctx } = await contextWith()
|
|
81
81
|
const request = requestFor(undefined, attached)
|
|
82
82
|
|
|
83
|
-
expect(await attachEntity(ctx
|
|
83
|
+
expect(await makeEntityScope(request).attachEntity(ctx)).toBeUndefined()
|
|
84
84
|
expect(request.entity).toBeUndefined()
|
|
85
85
|
})
|
|
86
86
|
})
|
|
@@ -90,7 +90,7 @@ describe('attachEntity — the resolver path', () => {
|
|
|
90
90
|
const { ctx } = await contextWith([ACME])
|
|
91
91
|
const request = requestFor('acme-old')
|
|
92
92
|
|
|
93
|
-
expect(await attachEntity(ctx
|
|
93
|
+
expect(await makeEntityScope(request).attachEntity(ctx)).toEqual(ACME)
|
|
94
94
|
expect(request.entity).toEqual(ACME)
|
|
95
95
|
expect(request.auth?.entitySlug).toBe('acme')
|
|
96
96
|
})
|
|
@@ -98,14 +98,14 @@ describe('attachEntity — the resolver path', () => {
|
|
|
98
98
|
test('refuses a token naming an organization the registry does not know', async () => {
|
|
99
99
|
const { ctx } = await contextWith([ACME])
|
|
100
100
|
|
|
101
|
-
await expect(
|
|
101
|
+
await expect(makeEntityScope(requestFor('nobody')).attachEntity(ctx)).rejects.toBeInstanceOf(AuthenFailed)
|
|
102
102
|
})
|
|
103
103
|
|
|
104
104
|
test('is a no-op with no resolver and nothing attached', async () => {
|
|
105
105
|
const { ctx } = await contextWith()
|
|
106
106
|
const request = requestFor('acme')
|
|
107
107
|
|
|
108
|
-
expect(await attachEntity(ctx
|
|
108
|
+
expect(await makeEntityScope(request).attachEntity(ctx)).toBeUndefined()
|
|
109
109
|
expect(request.entity).toBeUndefined()
|
|
110
110
|
expect(request.auth?.entitySlug).toBe('acme')
|
|
111
111
|
})
|