@owlmeans/web-auth 0.1.18-rc.6 → 0.1.18-rc.60
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/agent-meta/manifest.json +2 -2
- package/agent-meta/skills/web-auth/SKILL.md +46 -17
- package/build/append.d.ts +18 -9
- package/build/append.d.ts.map +1 -1
- package/build/append.js +25 -6
- package/build/append.js.map +1 -1
- package/build/auth/plugins/supervisor.d.ts.map +1 -1
- package/build/auth/plugins/supervisor.js +10 -3
- package/build/auth/plugins/supervisor.js.map +1 -1
- package/package.json +12 -10
- package/src/append.ts +42 -9
- package/src/auth/plugins/supervisor.tsx +11 -4
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@ This package ships embedded agent skills under `agent-meta/`. After installing y
|
|
|
6
6
|
your project's skill store (`.agents/skills/`):
|
|
7
7
|
|
|
8
8
|
```sh
|
|
9
|
-
npx @owlmeans/agent-skills
|
|
9
|
+
npx @owlmeans/agent-skills@^0.1.18-rc.47
|
|
10
10
|
```
|
|
11
11
|
|
|
12
12
|
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/web-auth",
|
|
4
|
-
"version": "0.1.18-rc.
|
|
5
|
-
"generatedAt": "2026-
|
|
4
|
+
"version": "0.1.18-rc.60",
|
|
5
|
+
"generatedAt": "2026-10-03T20:05:07.592Z",
|
|
6
6
|
"canonicalRepo": "https://github.com/owlmeans/common",
|
|
7
7
|
"entries": [
|
|
8
8
|
{
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: web-auth
|
|
3
|
-
description: How to use @owlmeans/web-auth — web
|
|
3
|
+
description: How to use @owlmeans/web-auth — web-side authentication-plugin package that registers into the shared @owlmeans/client-auth/manager registry. It ships the development-only PK supervisor login form (appendSupervisorAuth, supervisorClientPlugin, SUPERVISOR_LOGIN_PATH). Auto-invoked when importing @owlmeans/web-auth or wiring the supervisor login into a web client.
|
|
4
4
|
user-invocable: false
|
|
5
5
|
---
|
|
6
6
|
<!-- AUTO-GENERATED — do not edit. Regenerate via sync-agent-meta. -->
|
|
@@ -8,35 +8,64 @@ user-invocable: false
|
|
|
8
8
|
# @owlmeans/web-auth
|
|
9
9
|
|
|
10
10
|
**Layer:** Web
|
|
11
|
-
**Install:** `"@owlmeans/web-auth": "^0.1.18-rc.
|
|
11
|
+
**Install:** `"@owlmeans/web-auth": "^0.1.18-rc.60"` in `dependencies`
|
|
12
12
|
|
|
13
|
-
Web-side auth UI plugins
|
|
14
|
-
(
|
|
13
|
+
Web-side auth UI plugins registering into the shared `@owlmeans/client-auth/manager` plugin registry
|
|
14
|
+
(mirroring `@owlmeans/web-oidc-rp`). It ships the **PK supervisor** login form.
|
|
15
15
|
|
|
16
16
|
## Key Exports
|
|
17
17
|
|
|
18
18
|
| Export | Description |
|
|
19
19
|
|--------|-------------|
|
|
20
|
-
| `appendSupervisorAuth(context, opts?)` |
|
|
21
|
-
| `
|
|
22
|
-
| `
|
|
20
|
+
| `appendSupervisorAuth(context, opts?)` | Register the supervisor login plugin and, unless told otherwise, offer it on the sign-in screen |
|
|
21
|
+
| `WebSupervisorAuthOptions` | `{ enabled?, offer? }` |
|
|
22
|
+
| `SUPERVISOR_LOGIN_PATH` | `/authentication/login/pk-supervisor` — the typed-route path |
|
|
23
|
+
| `supervisorClientPlugin` | The client `AuthenticationPlugin`: a self-contained form that signs the server challenge and hands the packed credential to the standard auth control |
|
|
23
24
|
|
|
24
25
|
## Subpath Exports
|
|
25
|
-
|
|
26
|
-
|
|
26
|
+
|
|
27
|
+
- `./auth/plugins` — a side-effect import that always registers the supervisor plugin
|
|
28
|
+
(`import '@owlmeans/web-auth/auth/plugins'`). Prefer the gated `appendSupervisorAuth`.
|
|
27
29
|
|
|
28
30
|
## Usage
|
|
31
|
+
|
|
29
32
|
```ts
|
|
30
33
|
import { appendSupervisorAuth } from '@owlmeans/web-auth'
|
|
31
|
-
|
|
32
|
-
|
|
34
|
+
|
|
35
|
+
// in the web client's makeContext():
|
|
36
|
+
appendSupervisorAuth(context)
|
|
33
37
|
```
|
|
34
|
-
The form renders at `SUPERVISOR_LOGIN_PATH` via the standard `CAUTHEN_AUTHEN_TYPED` route — no extra
|
|
35
|
-
route registration needed. Test ids: `supervisor-auth-form`, `supervisor-user-id`, `supervisor-pk`,
|
|
36
|
-
`supervisor-submit`, `supervisor-error`.
|
|
37
38
|
|
|
38
|
-
|
|
39
|
+
**It reads `cfg.debug.supervisor`, and deliberately NOT `cfg.debug.all`.** Whole families of
|
|
40
|
+
OwlMeans applications set `debug.all` for reasons that have nothing to do with authentication — a
|
|
41
|
+
Viable-generated target sets it for itself — so gating on it would put an operator login on every
|
|
42
|
+
one of them, in production, reachable by anyone who typed the URL. Pass `{ enabled: true }` to force
|
|
43
|
+
it on regardless of the debug flags.
|
|
44
|
+
|
|
45
|
+
Registering the plugin is not enough to make it OFFERED: `supervisorClientPlugin` carries
|
|
46
|
+
`restricted: true`, so the sign-in screen shows it only where the configuration names it. That is
|
|
47
|
+
what `appendSupervisorAuth` writes into `cfg.security.auth.login.overrides` (and
|
|
48
|
+
`login.secretKey`) when it enables the plugin — pass `{ offer: false }` to register it without
|
|
49
|
+
advertising it.
|
|
50
|
+
|
|
51
|
+
The form renders at `SUPERVISOR_LOGIN_PATH` through the standard `CAUTHEN_AUTHEN_TYPED` route, so
|
|
52
|
+
no extra route registration is needed. It orders itself last (`order: 900`) and renders as a link,
|
|
53
|
+
because it is a tool rather than a way in. Test ids: `supervisor-auth-form`, `supervisor-user-id`,
|
|
54
|
+
`supervisor-pk`, `supervisor-submit`, `supervisor-error`.
|
|
55
|
+
|
|
56
|
+
On submit the form requests a fresh allowance, signs `buildSupervisorPayload(challenge, userId,
|
|
57
|
+
salt)` with the entered private key, packs `{ salt, signature }` as the credential, exchanges the
|
|
58
|
+
resulting token through the client `AuthService`, and navigates via `landAfterLogin` +
|
|
59
|
+
`landingUrl` (`@owlmeans/client-auth/login`) — a pending post-login step, then a screen suspended
|
|
60
|
+
in `@owlmeans/client-flow` (an OAuth consent screen reached signed out, say), else `HOME`. It no
|
|
61
|
+
longer imports `@owlmeans/client-flow` or `@owlmeans/web-client` directly; `landAfterLogin` is the
|
|
62
|
+
whole decision.
|
|
63
|
+
|
|
64
|
+
See the **supervisor-auth** skill for the whole feature — the server append, its options, the
|
|
65
|
+
security boundary and the `@owlmeans/test-ui` helpers.
|
|
39
66
|
|
|
40
67
|
## Depends On
|
|
41
|
-
- `@owlmeans/client-auth
|
|
42
|
-
- `@owlmeans/auth`
|
|
68
|
+
- `@owlmeans/client-auth` (the manager plugin registry), `@owlmeans/web-client`, `@owlmeans/client`
|
|
69
|
+
- `@owlmeans/auth` — `AuthenticationType.Supervisor`, `buildSupervisorPayload`
|
|
70
|
+
- `@owlmeans/auth-common` — the client `AuthService` type
|
|
71
|
+
- `@owlmeans/basic-keys` (signing), `@owlmeans/basic-ids` (the salt), `@owlmeans/config`
|
package/build/append.d.ts
CHANGED
|
@@ -1,19 +1,28 @@
|
|
|
1
|
+
import type { CommonConfig } from '@owlmeans/config';
|
|
1
2
|
export interface WebSupervisorAuthOptions {
|
|
2
|
-
/** Force enable/disable. Default:
|
|
3
|
+
/** Force enable/disable. Default: `cfg.debug.supervisor === true`. */
|
|
3
4
|
enabled?: boolean;
|
|
5
|
+
/**
|
|
6
|
+
* Also offer it on the sign-in screen. Defaults to true — an operator login that is registered
|
|
7
|
+
* but reachable only by typing its URL is a login nobody finds and an exposure nobody sees.
|
|
8
|
+
*/
|
|
9
|
+
offer?: boolean;
|
|
4
10
|
}
|
|
5
|
-
|
|
6
|
-
* Unified, explicit append for the PK-based supervisor login UI. Call it once on
|
|
7
|
-
* the web client context. Development-only by default. It registers the
|
|
8
|
-
* supervisor client plugin so the form is rendered by the standard typed
|
|
9
|
-
* authentication route at {@link SUPERVISOR_LOGIN_PATH}.
|
|
10
|
-
*/
|
|
11
|
-
export declare const appendSupervisorAuth: <T extends {
|
|
11
|
+
interface DebugCarrier {
|
|
12
12
|
cfg: {
|
|
13
13
|
debug?: {
|
|
14
14
|
all?: boolean;
|
|
15
15
|
supervisor?: boolean;
|
|
16
16
|
};
|
|
17
|
+
security?: CommonConfig['security'];
|
|
17
18
|
};
|
|
18
|
-
}
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Unified, explicit append for the PK-based supervisor login UI. Call it once on the web client
|
|
22
|
+
* context. It registers the supervisor client plugin so the form is rendered by the standard typed
|
|
23
|
+
* authentication route at {@link SUPERVISOR_LOGIN_PATH}, and enables it in the sign-in screen's
|
|
24
|
+
* configuration — which is what turns a `restricted` method from registered into offerable.
|
|
25
|
+
*/
|
|
26
|
+
export declare const appendSupervisorAuth: <T extends DebugCarrier>(context: T, opts?: WebSupervisorAuthOptions) => T;
|
|
27
|
+
export {};
|
|
19
28
|
//# sourceMappingURL=append.d.ts.map
|
package/build/append.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"append.d.ts","sourceRoot":"","sources":["../src/append.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"append.d.ts","sourceRoot":"","sources":["../src/append.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAGpD,MAAM,WAAW,wBAAwB;IACvC,sEAAsE;IACtE,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB;;;OAGG;IACH,KAAK,CAAC,EAAE,OAAO,CAAA;CAChB;AAED,UAAU,YAAY;IACpB,GAAG,EAAE;QACH,KAAK,CAAC,EAAE;YAAE,GAAG,CAAC,EAAE,OAAO,CAAC;YAAC,UAAU,CAAC,EAAE,OAAO,CAAA;SAAE,CAAA;QAC/C,QAAQ,CAAC,EAAE,YAAY,CAAC,UAAU,CAAC,CAAA;KACpC,CAAA;CACF;AAcD;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,GAAI,CAAC,SAAS,YAAY,WAChD,CAAC,SAAS,wBAAwB,KAC1C,CAoBF,CAAA"}
|
package/build/append.js
CHANGED
|
@@ -1,19 +1,38 @@
|
|
|
1
1
|
import { AuthenticationType } from '@owlmeans/auth';
|
|
2
2
|
import { plugins as authPlugins } from '@owlmeans/client-auth/manager';
|
|
3
3
|
import { supervisorClientPlugin } from './auth/plugins/supervisor.js';
|
|
4
|
-
const isDevelopment = (context) => context.cfg.debug?.all === true || context.cfg.debug?.supervisor === true;
|
|
5
4
|
/**
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* supervisor
|
|
9
|
-
* authentication
|
|
5
|
+
* Whether this deployment wants the PK supervisor login.
|
|
6
|
+
*
|
|
7
|
+
* Reads `debug.supervisor` and deliberately NOT `debug.all`. `debug.all` is set by whole families
|
|
8
|
+
* of applications for reasons that have nothing to do with authentication — a generated target
|
|
9
|
+
* application sets it for itself — so gating on it hands an operator login to every one of them,
|
|
10
|
+
* in production, reachable by anyone who types the URL. `debug.supervisor` is a deployment saying
|
|
11
|
+
* this specific thing on purpose.
|
|
12
|
+
*/
|
|
13
|
+
const isSupervised = (context) => context.cfg.debug?.supervisor === true;
|
|
14
|
+
/**
|
|
15
|
+
* Unified, explicit append for the PK-based supervisor login UI. Call it once on the web client
|
|
16
|
+
* context. It registers the supervisor client plugin so the form is rendered by the standard typed
|
|
17
|
+
* authentication route at {@link SUPERVISOR_LOGIN_PATH}, and enables it in the sign-in screen's
|
|
18
|
+
* configuration — which is what turns a `restricted` method from registered into offerable.
|
|
10
19
|
*/
|
|
11
20
|
export const appendSupervisorAuth = (context, opts) => {
|
|
12
|
-
const enabled = opts?.enabled ??
|
|
21
|
+
const enabled = opts?.enabled ?? isSupervised(context);
|
|
13
22
|
if (!enabled) {
|
|
14
23
|
return context;
|
|
15
24
|
}
|
|
16
25
|
authPlugins[AuthenticationType.Supervisor] = supervisorClientPlugin;
|
|
26
|
+
if (opts?.offer ?? true) {
|
|
27
|
+
const cfg = context.cfg;
|
|
28
|
+
cfg.security ??= {};
|
|
29
|
+
cfg.security.auth ??= {};
|
|
30
|
+
cfg.security.auth.login ??= {};
|
|
31
|
+
const login = cfg.security.auth.login;
|
|
32
|
+
login.secretKey ??= true;
|
|
33
|
+
login.overrides ??= {};
|
|
34
|
+
login.overrides[AuthenticationType.Supervisor] ??= { enabled: true };
|
|
35
|
+
}
|
|
17
36
|
return context;
|
|
18
37
|
};
|
|
19
38
|
//# sourceMappingURL=append.js.map
|
package/build/append.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"append.js","sourceRoot":"","sources":["../src/append.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAA;AACnD,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,+BAA+B,CAAA;
|
|
1
|
+
{"version":3,"file":"append.js","sourceRoot":"","sources":["../src/append.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAA;AACnD,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,+BAA+B,CAAA;AAEtE,OAAO,EAAE,sBAAsB,EAAE,MAAM,8BAA8B,CAAA;AAmBrE;;;;;;;;GAQG;AACH,MAAM,YAAY,GAAG,CAAC,OAAqB,EAAW,EAAE,CACtD,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAA;AAExC;;;;;GAKG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAClC,OAAU,EAAE,IAA+B,EACxC,EAAE;IACL,MAAM,OAAO,GAAG,IAAI,EAAE,OAAO,IAAI,YAAY,CAAC,OAAO,CAAC,CAAA;IACtD,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,OAAO,CAAA;IAChB,CAAC;IAED,WAAW,CAAC,kBAAkB,CAAC,UAAU,CAAC,GAAG,sBAAsB,CAAA;IAEnE,IAAI,IAAI,EAAE,KAAK,IAAI,IAAI,EAAE,CAAC;QACxB,MAAM,GAAG,GAAG,OAAO,CAAC,GAAmB,CAAA;QACvC,GAAG,CAAC,QAAQ,KAAK,EAAE,CAAA;QACnB,GAAG,CAAC,QAAQ,CAAC,IAAI,KAAK,EAAE,CAAA;QACxB,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,KAAK,EAAE,CAAA;QAC9B,MAAM,KAAK,GAAG,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAA;QACrC,KAAK,CAAC,SAAS,KAAK,IAAI,CAAA;QACxB,KAAK,CAAC,SAAS,KAAK,EAAE,CAAA;QACtB,KAAK,CAAC,SAAS,CAAC,kBAAkB,CAAC,UAAU,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,CAAA;IACtE,CAAC;IAED,OAAO,OAAO,CAAA;AAChB,CAAC,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"supervisor.d.ts","sourceRoot":"","sources":["../../../src/auth/plugins/supervisor.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,uCAAuC,CAAA;
|
|
1
|
+
{"version":3,"file":"supervisor.d.ts","sourceRoot":"","sources":["../../../src/auth/plugins/supervisor.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,uCAAuC,CAAA;AAUjF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,sBAAsB,EAAE,oBA8EpC,CAAA"}
|
|
@@ -3,7 +3,7 @@ import { useState } from 'react';
|
|
|
3
3
|
import { AuthenticationType, buildSupervisorPayload } from '@owlmeans/auth';
|
|
4
4
|
import { DEFAULT_ALIAS as AUTH_SERVICE } from '@owlmeans/client-auth';
|
|
5
5
|
import { useContext } from '@owlmeans/client';
|
|
6
|
-
import {
|
|
6
|
+
import { landAfterLogin, landingUrl } from '@owlmeans/client-auth/login';
|
|
7
7
|
import { makeKeyPairModel } from '@owlmeans/basic-keys';
|
|
8
8
|
import { createIdOfLength } from '@owlmeans/basic-ids';
|
|
9
9
|
/**
|
|
@@ -20,6 +20,10 @@ import { createIdOfLength } from '@owlmeans/basic-ids';
|
|
|
20
20
|
*/
|
|
21
21
|
export const supervisorClientPlugin = {
|
|
22
22
|
type: AuthenticationType.Supervisor,
|
|
23
|
+
// `restricted`, so registering the plugin is not enough to put an operator login on the sign-in
|
|
24
|
+
// screen of a production application — the configuration has to name it. Last in the order and
|
|
25
|
+
// rendered as a link, because it is a tool, not a way in.
|
|
26
|
+
method: { order: 900, icon: 'key', emphasis: 'link', restricted: true },
|
|
23
27
|
Implementation: () => ({ type, control }) => {
|
|
24
28
|
const context = useContext();
|
|
25
29
|
const [userId, setUserId] = useState('');
|
|
@@ -39,8 +43,11 @@ export const supervisorClientPlugin = {
|
|
|
39
43
|
const authService = context.service(AUTH_SERVICE);
|
|
40
44
|
await authService.authenticate(token);
|
|
41
45
|
}
|
|
42
|
-
|
|
43
|
-
|
|
46
|
+
// A registered step (marketing consent, say) or a device/authorization-code consent
|
|
47
|
+
// screen that suspended itself here before sending the browser to sign in both take
|
|
48
|
+
// priority over the app's own home — `landAfterLogin` is the whole decision.
|
|
49
|
+
const landing = await landAfterLogin(context);
|
|
50
|
+
window.location.href = await landingUrl(context, landing);
|
|
44
51
|
}
|
|
45
52
|
catch (e) {
|
|
46
53
|
setError(e instanceof Error ? e.message : String(e));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"supervisor.js","sourceRoot":"","sources":["../../../src/auth/plugins/supervisor.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAGhC,OAAO,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAA;AAE3E,OAAO,EAAE,aAAa,IAAI,YAAY,EAAE,MAAM,uBAAuB,CAAA;AAErE,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAC7C,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"supervisor.js","sourceRoot":"","sources":["../../../src/auth/plugins/supervisor.tsx"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@owlmeans/web-auth",
|
|
3
|
-
"version": "0.1.18-rc.
|
|
3
|
+
"version": "0.1.18-rc.60",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
@@ -29,21 +29,23 @@
|
|
|
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": "^0.1.18-rc.
|
|
37
|
-
"@owlmeans/client-auth": "^0.1.18-rc.
|
|
38
|
-
"@owlmeans/
|
|
39
|
-
"@owlmeans/
|
|
32
|
+
"@owlmeans/auth": "^0.1.18-rc.38",
|
|
33
|
+
"@owlmeans/auth-common": "^0.1.18-rc.45",
|
|
34
|
+
"@owlmeans/basic-ids": "^0.1.18-rc.35",
|
|
35
|
+
"@owlmeans/basic-keys": "^0.1.18-rc.46",
|
|
36
|
+
"@owlmeans/client": "^0.1.18-rc.49",
|
|
37
|
+
"@owlmeans/client-auth": "^0.1.18-rc.56",
|
|
38
|
+
"@owlmeans/client-flow": "^0.1.18-rc.52",
|
|
39
|
+
"@owlmeans/config": "^0.1.18-rc.42",
|
|
40
|
+
"@owlmeans/context": "^0.1.18-rc.32",
|
|
41
|
+
"@owlmeans/web-client": "^0.1.18-rc.59"
|
|
40
42
|
},
|
|
41
43
|
"peerDependencies": {
|
|
42
44
|
"react": "*"
|
|
43
45
|
},
|
|
44
46
|
"devDependencies": {
|
|
45
47
|
"@owlmeans/dep-config": "workspace:*",
|
|
46
|
-
"@types/bun": "^1.
|
|
48
|
+
"@types/bun": "^1.4.0",
|
|
47
49
|
"@types/react": "^19.2.17",
|
|
48
50
|
"nodemon": "^3.1.14",
|
|
49
51
|
"typescript": "^7.0.2"
|
package/src/append.ts
CHANGED
|
@@ -1,30 +1,63 @@
|
|
|
1
1
|
import { AuthenticationType } from '@owlmeans/auth'
|
|
2
2
|
import { plugins as authPlugins } from '@owlmeans/client-auth/manager'
|
|
3
|
+
import type { CommonConfig } from '@owlmeans/config'
|
|
3
4
|
import { supervisorClientPlugin } from './auth/plugins/supervisor.js'
|
|
4
5
|
|
|
5
6
|
export interface WebSupervisorAuthOptions {
|
|
6
|
-
/** Force enable/disable. Default:
|
|
7
|
+
/** Force enable/disable. Default: `cfg.debug.supervisor === true`. */
|
|
7
8
|
enabled?: boolean
|
|
9
|
+
/**
|
|
10
|
+
* Also offer it on the sign-in screen. Defaults to true — an operator login that is registered
|
|
11
|
+
* but reachable only by typing its URL is a login nobody finds and an exposure nobody sees.
|
|
12
|
+
*/
|
|
13
|
+
offer?: boolean
|
|
8
14
|
}
|
|
9
15
|
|
|
10
|
-
|
|
11
|
-
|
|
16
|
+
interface DebugCarrier {
|
|
17
|
+
cfg: {
|
|
18
|
+
debug?: { all?: boolean, supervisor?: boolean }
|
|
19
|
+
security?: CommonConfig['security']
|
|
20
|
+
}
|
|
21
|
+
}
|
|
12
22
|
|
|
13
23
|
/**
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* supervisor
|
|
17
|
-
* authentication
|
|
24
|
+
* Whether this deployment wants the PK supervisor login.
|
|
25
|
+
*
|
|
26
|
+
* Reads `debug.supervisor` and deliberately NOT `debug.all`. `debug.all` is set by whole families
|
|
27
|
+
* of applications for reasons that have nothing to do with authentication — a generated target
|
|
28
|
+
* application sets it for itself — so gating on it hands an operator login to every one of them,
|
|
29
|
+
* in production, reachable by anyone who types the URL. `debug.supervisor` is a deployment saying
|
|
30
|
+
* this specific thing on purpose.
|
|
18
31
|
*/
|
|
19
|
-
|
|
32
|
+
const isSupervised = (context: DebugCarrier): boolean =>
|
|
33
|
+
context.cfg.debug?.supervisor === true
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Unified, explicit append for the PK-based supervisor login UI. Call it once on the web client
|
|
37
|
+
* context. It registers the supervisor client plugin so the form is rendered by the standard typed
|
|
38
|
+
* authentication route at {@link SUPERVISOR_LOGIN_PATH}, and enables it in the sign-in screen's
|
|
39
|
+
* configuration — which is what turns a `restricted` method from registered into offerable.
|
|
40
|
+
*/
|
|
41
|
+
export const appendSupervisorAuth = <T extends DebugCarrier>(
|
|
20
42
|
context: T, opts?: WebSupervisorAuthOptions
|
|
21
43
|
): T => {
|
|
22
|
-
const enabled = opts?.enabled ??
|
|
44
|
+
const enabled = opts?.enabled ?? isSupervised(context)
|
|
23
45
|
if (!enabled) {
|
|
24
46
|
return context
|
|
25
47
|
}
|
|
26
48
|
|
|
27
49
|
authPlugins[AuthenticationType.Supervisor] = supervisorClientPlugin
|
|
28
50
|
|
|
51
|
+
if (opts?.offer ?? true) {
|
|
52
|
+
const cfg = context.cfg as CommonConfig
|
|
53
|
+
cfg.security ??= {}
|
|
54
|
+
cfg.security.auth ??= {}
|
|
55
|
+
cfg.security.auth.login ??= {}
|
|
56
|
+
const login = cfg.security.auth.login
|
|
57
|
+
login.secretKey ??= true
|
|
58
|
+
login.overrides ??= {}
|
|
59
|
+
login.overrides[AuthenticationType.Supervisor] ??= { enabled: true }
|
|
60
|
+
}
|
|
61
|
+
|
|
29
62
|
return context
|
|
30
63
|
}
|
|
@@ -6,8 +6,7 @@ import type { AuthToken } from '@owlmeans/auth'
|
|
|
6
6
|
import { DEFAULT_ALIAS as AUTH_SERVICE } from '@owlmeans/client-auth'
|
|
7
7
|
import type { AuthService } from '@owlmeans/auth-common'
|
|
8
8
|
import { useContext } from '@owlmeans/client'
|
|
9
|
-
import {
|
|
10
|
-
import type { Module } from '@owlmeans/web-client'
|
|
9
|
+
import { landAfterLogin, landingUrl } from '@owlmeans/client-auth/login'
|
|
11
10
|
import { makeKeyPairModel } from '@owlmeans/basic-keys'
|
|
12
11
|
import { createIdOfLength } from '@owlmeans/basic-ids'
|
|
13
12
|
|
|
@@ -26,6 +25,11 @@ import { createIdOfLength } from '@owlmeans/basic-ids'
|
|
|
26
25
|
export const supervisorClientPlugin: AuthenticationPlugin = {
|
|
27
26
|
type: AuthenticationType.Supervisor,
|
|
28
27
|
|
|
28
|
+
// `restricted`, so registering the plugin is not enough to put an operator login on the sign-in
|
|
29
|
+
// screen of a production application — the configuration has to name it. Last in the order and
|
|
30
|
+
// rendered as a link, because it is a tool, not a way in.
|
|
31
|
+
method: { order: 900, icon: 'key', emphasis: 'link', restricted: true },
|
|
32
|
+
|
|
29
33
|
Implementation: () => ({ type, control }) => {
|
|
30
34
|
const context = useContext()
|
|
31
35
|
const [userId, setUserId] = useState('')
|
|
@@ -49,8 +53,11 @@ export const supervisorClientPlugin: AuthenticationPlugin = {
|
|
|
49
53
|
await authService.authenticate(token)
|
|
50
54
|
}
|
|
51
55
|
|
|
52
|
-
|
|
53
|
-
|
|
56
|
+
// A registered step (marketing consent, say) or a device/authorization-code consent
|
|
57
|
+
// screen that suspended itself here before sending the browser to sign in both take
|
|
58
|
+
// priority over the app's own home — `landAfterLogin` is the whole decision.
|
|
59
|
+
const landing = await landAfterLogin(context)
|
|
60
|
+
window.location.href = await landingUrl(context, landing)
|
|
54
61
|
} catch (e) {
|
|
55
62
|
setError(e instanceof Error ? e.message : String(e))
|
|
56
63
|
setBusy(false)
|