@owlmeans/client-auth 0.1.18-rc.14 → 0.1.18-rc.16
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/agent-meta/manifest.json +2 -2
- package/agent-meta/skills/client-auth/SKILL.md +1 -1
- package/build/login/flow.d.ts +20 -0
- package/build/login/flow.d.ts.map +1 -0
- package/build/login/flow.js +39 -0
- package/build/login/flow.js.map +1 -0
- package/build/login/i18n/be.json +1 -1
- package/build/login/i18n/de.json +1 -1
- package/build/login/i18n/en.json +1 -1
- package/build/login/i18n/es.json +1 -1
- package/build/login/i18n/pl.json +1 -1
- package/build/login/i18n/ru.json +1 -1
- package/build/login/i18n/uk.json +1 -1
- package/build/login/index.d.ts +1 -0
- package/build/login/index.d.ts.map +1 -1
- package/build/login/index.js +1 -0
- package/build/login/index.js.map +1 -1
- package/build/login/resume.d.ts +10 -0
- package/build/login/resume.d.ts.map +1 -1
- package/build/login/resume.js +22 -0
- package/build/login/resume.js.map +1 -1
- package/build/manager/modules.d.ts +1 -1
- package/build/manager/modules.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/login/flow.ts +44 -0
- package/src/login/i18n/be.json +1 -1
- package/src/login/i18n/de.json +1 -1
- package/src/login/i18n/en.json +1 -1
- package/src/login/i18n/es.json +1 -1
- package/src/login/i18n/pl.json +1 -1
- package/src/login/i18n/ru.json +1 -1
- package/src/login/i18n/uk.json +1 -1
- package/src/login/index.ts +1 -0
- package/src/login/resume.ts +23 -0
- package/tests/login.spec.ts +19 -1
package/agent-meta/manifest.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 2,
|
|
3
3
|
"package": "@owlmeans/client-auth",
|
|
4
|
-
"version": "0.1.18-rc.
|
|
5
|
-
"generatedAt": "2026-09-01T12:
|
|
4
|
+
"version": "0.1.18-rc.16",
|
|
5
|
+
"generatedAt": "2026-09-01T12:34:07.505Z",
|
|
6
6
|
"canonicalRepo": "https://github.com/owlmeans/common",
|
|
7
7
|
"entries": [
|
|
8
8
|
{
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { FlowModel } from '@owlmeans/flow';
|
|
2
|
+
/**
|
|
3
|
+
* Bring a freshly booted standard OIDC flow to the step an authorization request can be made from.
|
|
4
|
+
*
|
|
5
|
+
* `stdOidcFlow` starts at `Dispatch`, but `OidcAuthService.authenticate` refuses any state that is
|
|
6
|
+
* not `Ephemeral` and returns null — so an application whose flow was only booted can ask for an
|
|
7
|
+
* authorization URL all day and be told nothing, forever. The dispatcher in this package has always
|
|
8
|
+
* done this transition inline; a relying party that replaces that dispatcher (`web-oidc-rp`,
|
|
9
|
+
* `mui-oidc-rp`) inherited the requirement without the code, which is what left a sign-in button
|
|
10
|
+
* that reported no error and did nothing at all.
|
|
11
|
+
*
|
|
12
|
+
* `Ephemeral` is the branch for an application that is its OWN authority — its flow configuration
|
|
13
|
+
* maps the auth service to a placeholder, which is exactly the generated-application case. An app
|
|
14
|
+
* federated with a real auth service keeps its target and is left alone.
|
|
15
|
+
*
|
|
16
|
+
* Idempotent, and safe to call on every attempt: a flow already past `Dispatch`, or one that is
|
|
17
|
+
* not the standard OIDC flow at all, is returned untouched.
|
|
18
|
+
*/
|
|
19
|
+
export declare const enterOidcAuthorization: (model: FlowModel) => FlowModel;
|
|
20
|
+
//# sourceMappingURL=flow.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flow.d.ts","sourceRoot":"","sources":["../../src/login/flow.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAG/C;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,sBAAsB,UAAW,SAAS,KAAG,SAsBzD,CAAA"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { FLOW_PLACEHOLDER, OidcAuthStep, STD_OIDC_FLOW } from '@owlmeans/flow';
|
|
2
|
+
import { DEFAULT_ENTITY } from '../consts.js';
|
|
3
|
+
/**
|
|
4
|
+
* Bring a freshly booted standard OIDC flow to the step an authorization request can be made from.
|
|
5
|
+
*
|
|
6
|
+
* `stdOidcFlow` starts at `Dispatch`, but `OidcAuthService.authenticate` refuses any state that is
|
|
7
|
+
* not `Ephemeral` and returns null — so an application whose flow was only booted can ask for an
|
|
8
|
+
* authorization URL all day and be told nothing, forever. The dispatcher in this package has always
|
|
9
|
+
* done this transition inline; a relying party that replaces that dispatcher (`web-oidc-rp`,
|
|
10
|
+
* `mui-oidc-rp`) inherited the requirement without the code, which is what left a sign-in button
|
|
11
|
+
* that reported no error and did nothing at all.
|
|
12
|
+
*
|
|
13
|
+
* `Ephemeral` is the branch for an application that is its OWN authority — its flow configuration
|
|
14
|
+
* maps the auth service to a placeholder, which is exactly the generated-application case. An app
|
|
15
|
+
* federated with a real auth service keeps its target and is left alone.
|
|
16
|
+
*
|
|
17
|
+
* Idempotent, and safe to call on every attempt: a flow already past `Dispatch`, or one that is
|
|
18
|
+
* not the standard OIDC flow at all, is returned untouched.
|
|
19
|
+
*/
|
|
20
|
+
export const enterOidcAuthorization = (model) => {
|
|
21
|
+
const state = model.state();
|
|
22
|
+
if (state.flow !== STD_OIDC_FLOW || state.step !== OidcAuthStep.Dispatch) {
|
|
23
|
+
return model;
|
|
24
|
+
}
|
|
25
|
+
const target = model.step().service;
|
|
26
|
+
if (state.service == null || state.service === '') {
|
|
27
|
+
model.target(target);
|
|
28
|
+
}
|
|
29
|
+
// The entity travels to this app's own backend, which resolves its default provider by `def`
|
|
30
|
+
// alone. It still has to BE there: the init endpoint rejects a body without one.
|
|
31
|
+
if (state.entityId == null) {
|
|
32
|
+
model.entity(DEFAULT_ENTITY);
|
|
33
|
+
}
|
|
34
|
+
if (target === FLOW_PLACEHOLDER) {
|
|
35
|
+
model.transit(OidcAuthStep.Ephemeral, true);
|
|
36
|
+
}
|
|
37
|
+
return model;
|
|
38
|
+
};
|
|
39
|
+
//# sourceMappingURL=flow.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flow.js","sourceRoot":"","sources":["../../src/login/flow.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAE9E,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAE7C;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,KAAgB,EAAa,EAAE;IACpE,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,EAAE,CAAA;IAC3B,IAAI,KAAK,CAAC,IAAI,KAAK,aAAa,IAAI,KAAK,CAAC,IAAI,KAAK,YAAY,CAAC,QAAQ,EAAE,CAAC;QACzE,OAAO,KAAK,CAAA;IACd,CAAC;IAED,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,OAAO,CAAA;IACnC,IAAI,KAAK,CAAC,OAAO,IAAI,IAAI,IAAI,KAAK,CAAC,OAAO,KAAK,EAAE,EAAE,CAAC;QAClD,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;IACtB,CAAC;IAED,6FAA6F;IAC7F,iFAAiF;IACjF,IAAI,KAAK,CAAC,QAAQ,IAAI,IAAI,EAAE,CAAC;QAC3B,KAAK,CAAC,MAAM,CAAC,cAAc,CAAC,CAAA;IAC9B,CAAC;IAED,IAAI,MAAM,KAAK,gBAAgB,EAAE,CAAC;QAChC,KAAK,CAAC,OAAO,CAAC,YAAY,CAAC,SAAS,EAAE,IAAI,CAAC,CAAA;IAC7C,CAAC;IAED,OAAO,KAAK,CAAA;AACd,CAAC,CAAA"}
|
package/build/login/i18n/be.json
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"method": {
|
|
8
8
|
"google": "Працягнуць з Google",
|
|
9
9
|
"oidc": "Працягнуць з {{provider}}",
|
|
10
|
-
"oidc-default": "Увайсці",
|
|
10
|
+
"oidc-default": "Увайсці / Зарэгістравацца",
|
|
11
11
|
"oidc-client": "Працягнуць з {{provider}}",
|
|
12
12
|
"basic-ed25519": "Увайсці з ключом",
|
|
13
13
|
"pk-supervisor": "Сакрэтны ключ (аператар)",
|
package/build/login/i18n/de.json
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"method": {
|
|
8
8
|
"google": "Mit Google fortfahren",
|
|
9
9
|
"oidc": "Mit {{provider}} fortfahren",
|
|
10
|
-
"oidc-default": "Anmelden",
|
|
10
|
+
"oidc-default": "Anmelden / Registrieren",
|
|
11
11
|
"oidc-client": "Mit {{provider}} fortfahren",
|
|
12
12
|
"basic-ed25519": "Mit einem Schlüssel anmelden",
|
|
13
13
|
"pk-supervisor": "Geheimer Schlüssel (Betreiber)",
|
package/build/login/i18n/en.json
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"method": {
|
|
8
8
|
"google": "Continue with Google",
|
|
9
9
|
"oidc": "Continue with {{provider}}",
|
|
10
|
-
"oidc-default": "Sign in",
|
|
10
|
+
"oidc-default": "Sign in / Sign up",
|
|
11
11
|
"oidc-client": "Continue with {{provider}}",
|
|
12
12
|
"basic-ed25519": "Sign in with a key",
|
|
13
13
|
"pk-supervisor": "Secret key (operator)",
|
package/build/login/i18n/es.json
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"method": {
|
|
8
8
|
"google": "Continuar con Google",
|
|
9
9
|
"oidc": "Continuar con {{provider}}",
|
|
10
|
-
"oidc-default": "Iniciar sesión",
|
|
10
|
+
"oidc-default": "Iniciar sesión / Registrarse",
|
|
11
11
|
"oidc-client": "Continuar con {{provider}}",
|
|
12
12
|
"basic-ed25519": "Iniciar sesión con una clave",
|
|
13
13
|
"pk-supervisor": "Clave secreta (operador)",
|
package/build/login/i18n/pl.json
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"method": {
|
|
8
8
|
"google": "Kontynuuj z Google",
|
|
9
9
|
"oidc": "Kontynuuj z {{provider}}",
|
|
10
|
-
"oidc-default": "Zaloguj się",
|
|
10
|
+
"oidc-default": "Zaloguj się / Zarejestruj się",
|
|
11
11
|
"oidc-client": "Kontynuuj z {{provider}}",
|
|
12
12
|
"basic-ed25519": "Zaloguj się kluczem",
|
|
13
13
|
"pk-supervisor": "Klucz tajny (operator)",
|
package/build/login/i18n/ru.json
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"method": {
|
|
8
8
|
"google": "Продолжить с Google",
|
|
9
9
|
"oidc": "Продолжить с {{provider}}",
|
|
10
|
-
"oidc-default": "Войти",
|
|
10
|
+
"oidc-default": "Войти / Зарегистрироваться",
|
|
11
11
|
"oidc-client": "Продолжить с {{provider}}",
|
|
12
12
|
"basic-ed25519": "Войти с ключом",
|
|
13
13
|
"pk-supervisor": "Секретный ключ (оператор)",
|
package/build/login/i18n/uk.json
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"method": {
|
|
8
8
|
"google": "Продовжити з Google",
|
|
9
9
|
"oidc": "Продовжити з {{provider}}",
|
|
10
|
-
"oidc-default": "Увійти",
|
|
10
|
+
"oidc-default": "Увійти / Зареєструватися",
|
|
11
11
|
"oidc-client": "Продовжити з {{provider}}",
|
|
12
12
|
"basic-ed25519": "Увійти з ключем",
|
|
13
13
|
"pk-supervisor": "Секретний ключ (оператор)",
|
package/build/login/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/login/index.ts"],"names":[],"mappings":"AAAA,OAAO,WAAW,CAAA;AAElB,cAAc,aAAa,CAAA;AAC3B,cAAc,YAAY,CAAA;AAC1B,cAAc,UAAU,CAAA;AACxB,cAAc,YAAY,CAAA;AAC1B,cAAc,cAAc,CAAA;AAC5B,cAAc,aAAa,CAAA;AAC3B,cAAc,YAAY,CAAA;AAC1B,cAAc,aAAa,CAAA;AAC3B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,aAAa,CAAA;AAC3B,cAAc,cAAc,CAAA;AAC5B,cAAc,WAAW,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/login/index.ts"],"names":[],"mappings":"AAAA,OAAO,WAAW,CAAA;AAElB,cAAc,aAAa,CAAA;AAC3B,cAAc,YAAY,CAAA;AAC1B,cAAc,UAAU,CAAA;AACxB,cAAc,YAAY,CAAA;AAC1B,cAAc,cAAc,CAAA;AAC5B,cAAc,WAAW,CAAA;AACzB,cAAc,aAAa,CAAA;AAC3B,cAAc,YAAY,CAAA;AAC1B,cAAc,aAAa,CAAA;AAC3B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,aAAa,CAAA;AAC3B,cAAc,cAAc,CAAA;AAC5B,cAAc,WAAW,CAAA"}
|
package/build/login/index.js
CHANGED
package/build/login/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/login/index.ts"],"names":[],"mappings":"AAAA,OAAO,WAAW,CAAA;AAElB,cAAc,aAAa,CAAA;AAC3B,cAAc,YAAY,CAAA;AAC1B,cAAc,UAAU,CAAA;AACxB,cAAc,YAAY,CAAA;AAC1B,cAAc,cAAc,CAAA;AAC5B,cAAc,aAAa,CAAA;AAC3B,cAAc,YAAY,CAAA;AAC1B,cAAc,aAAa,CAAA;AAC3B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,aAAa,CAAA;AAC3B,cAAc,cAAc,CAAA;AAC5B,cAAc,WAAW,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/login/index.ts"],"names":[],"mappings":"AAAA,OAAO,WAAW,CAAA;AAElB,cAAc,aAAa,CAAA;AAC3B,cAAc,YAAY,CAAA;AAC1B,cAAc,UAAU,CAAA;AACxB,cAAc,YAAY,CAAA;AAC1B,cAAc,cAAc,CAAA;AAC5B,cAAc,WAAW,CAAA;AACzB,cAAc,aAAa,CAAA;AAC3B,cAAc,YAAY,CAAA;AAC1B,cAAc,aAAa,CAAA;AAC3B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,aAAa,CAAA;AAC3B,cAAc,cAAc,CAAA;AAC5B,cAAc,WAAW,CAAA"}
|
package/build/login/resume.d.ts
CHANGED
|
@@ -1,4 +1,14 @@
|
|
|
1
1
|
import { LoginOutcome } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* The message key a FINISHED sign-in attempt should show, or null when it actually went somewhere.
|
|
4
|
+
*
|
|
5
|
+
* A dispatcher may treat `Passed` as "carry on with the ordinary continuation", because it has one.
|
|
6
|
+
* A screen does not: the user clicked, the document did not move, and nothing rendered — which is
|
|
7
|
+
* indistinguishable from a broken button, and is exactly how a null authorization URL used to
|
|
8
|
+
* present itself. Every outcome that leaves the user looking at the same screen therefore has to
|
|
9
|
+
* say something.
|
|
10
|
+
*/
|
|
11
|
+
export declare const loginAttemptError: (outcome: LoginOutcome | null) => string | null;
|
|
2
12
|
/** What a dispatcher does once `login().resume(...)` has answered. */
|
|
3
13
|
export declare enum ResumeAction {
|
|
4
14
|
/** The plugin took it over — the browser is leaving, or the window is closing. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resume.d.ts","sourceRoot":"","sources":["../../src/login/resume.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAEzC,sEAAsE;AACtE,oBAAY,YAAY;IACtB,kFAAkF;IAClF,IAAI,SAAS;IACb,oFAAoF;IACpF,MAAM,WAAW;IACjB,sEAAsE;IACtE,QAAQ,aAAa;CACtB;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,YAAY,YAAa,YAAY,KAAG,YAYpD,CAAA"}
|
|
1
|
+
{"version":3,"file":"resume.d.ts","sourceRoot":"","sources":["../../src/login/resume.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAEzC;;;;;;;;GAQG;AACH,eAAO,MAAM,iBAAiB,YAAa,YAAY,GAAG,IAAI,KAAG,MAAM,GAAG,IAYzE,CAAA;AAED,sEAAsE;AACtE,oBAAY,YAAY;IACtB,kFAAkF;IAClF,IAAI,SAAS;IACb,oFAAoF;IACpF,MAAM,WAAW;IACjB,sEAAsE;IACtE,QAAQ,aAAa;CACtB;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,YAAY,YAAa,YAAY,KAAG,YAYpD,CAAA"}
|
package/build/login/resume.js
CHANGED
|
@@ -1,4 +1,26 @@
|
|
|
1
1
|
import { LoginOutcome } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* The message key a FINISHED sign-in attempt should show, or null when it actually went somewhere.
|
|
4
|
+
*
|
|
5
|
+
* A dispatcher may treat `Passed` as "carry on with the ordinary continuation", because it has one.
|
|
6
|
+
* A screen does not: the user clicked, the document did not move, and nothing rendered — which is
|
|
7
|
+
* indistinguishable from a broken button, and is exactly how a null authorization URL used to
|
|
8
|
+
* present itself. Every outcome that leaves the user looking at the same screen therefore has to
|
|
9
|
+
* say something.
|
|
10
|
+
*/
|
|
11
|
+
export const loginAttemptError = (outcome) => {
|
|
12
|
+
switch (outcome) {
|
|
13
|
+
case LoginOutcome.Gesture:
|
|
14
|
+
// The window never opened. That is the popup blocker, and it has its own copy.
|
|
15
|
+
return 'login.error.blocked';
|
|
16
|
+
case LoginOutcome.Failed:
|
|
17
|
+
case LoginOutcome.Passed:
|
|
18
|
+
return 'login.error.failed';
|
|
19
|
+
default:
|
|
20
|
+
// Handled, Redirected and Orphaned all did something; Orphaned reports itself elsewhere.
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
};
|
|
2
24
|
/** What a dispatcher does once `login().resume(...)` has answered. */
|
|
3
25
|
export var ResumeAction;
|
|
4
26
|
(function (ResumeAction) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resume.js","sourceRoot":"","sources":["../../src/login/resume.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAEzC,sEAAsE;AACtE,MAAM,CAAN,IAAY,YAOX;AAPD,WAAY,YAAY;IACtB,kFAAkF;IAClF,6BAAa,CAAA;IACb,oFAAoF;IACpF,iCAAiB,CAAA;IACjB,sEAAsE;IACtE,qCAAqB,CAAA;AACvB,CAAC,EAPW,YAAY,KAAZ,YAAY,QAOvB;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,OAAqB,EAAgB,EAAE;IAClE,QAAQ,OAAO,EAAE,CAAC;QAChB,KAAK,YAAY,CAAC,OAAO,CAAC;QAC1B,KAAK,YAAY,CAAC,UAAU;YAC1B,OAAO,YAAY,CAAC,IAAI,CAAA;QAC1B,KAAK,YAAY,CAAC,QAAQ,CAAC;QAC3B,KAAK,YAAY,CAAC,MAAM,CAAC;QACzB,KAAK,YAAY,CAAC,OAAO;YACvB,OAAO,YAAY,CAAC,MAAM,CAAA;QAC5B;YACE,OAAO,YAAY,CAAC,QAAQ,CAAA;IAChC,CAAC;AACH,CAAC,CAAA"}
|
|
1
|
+
{"version":3,"file":"resume.js","sourceRoot":"","sources":["../../src/login/resume.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAEzC;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,OAA4B,EAAiB,EAAE;IAC/E,QAAQ,OAAO,EAAE,CAAC;QAChB,KAAK,YAAY,CAAC,OAAO;YACvB,+EAA+E;YAC/E,OAAO,qBAAqB,CAAA;QAC9B,KAAK,YAAY,CAAC,MAAM,CAAC;QACzB,KAAK,YAAY,CAAC,MAAM;YACtB,OAAO,oBAAoB,CAAA;QAC7B;YACE,yFAAyF;YACzF,OAAO,IAAI,CAAA;IACf,CAAC;AACH,CAAC,CAAA;AAED,sEAAsE;AACtE,MAAM,CAAN,IAAY,YAOX;AAPD,WAAY,YAAY;IACtB,kFAAkF;IAClF,6BAAa,CAAA;IACb,oFAAoF;IACpF,iCAAiB,CAAA;IACjB,sEAAsE;IACtE,qCAAqB,CAAA;AACvB,CAAC,EAPW,YAAY,KAAZ,YAAY,QAOvB;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,OAAqB,EAAgB,EAAE;IAClE,QAAQ,OAAO,EAAE,CAAC;QAChB,KAAK,YAAY,CAAC,OAAO,CAAC;QAC1B,KAAK,YAAY,CAAC,UAAU;YAC1B,OAAO,YAAY,CAAC,IAAI,CAAA;QAC1B,KAAK,YAAY,CAAC,QAAQ,CAAC;QAC3B,KAAK,YAAY,CAAC,MAAM,CAAC;QACzB,KAAK,YAAY,CAAC,OAAO;YACvB,OAAO,YAAY,CAAC,MAAM,CAAA;QAC5B;YACE,OAAO,YAAY,CAAC,QAAQ,CAAA;IAChC,CAAC;AACH,CAAC,CAAA"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const modules:
|
|
1
|
+
export declare const modules: import("@owlmeans/entrypoint").CommonEntrypoint[];
|
|
2
2
|
//# sourceMappingURL=modules.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"modules.d.ts","sourceRoot":"","sources":["../../src/manager/modules.ts"],"names":[],"mappings":"AAiBA,eAAO,MAAM,OAAO,
|
|
1
|
+
{"version":3,"file":"modules.d.ts","sourceRoot":"","sources":["../../src/manager/modules.ts"],"names":[],"mappings":"AAiBA,eAAO,MAAM,OAAO,mDAAO,CAAA"}
|
package/package.json
CHANGED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { FLOW_PLACEHOLDER, OidcAuthStep, STD_OIDC_FLOW } from '@owlmeans/flow'
|
|
2
|
+
import type { FlowModel } from '@owlmeans/flow'
|
|
3
|
+
import { DEFAULT_ENTITY } from '../consts.js'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Bring a freshly booted standard OIDC flow to the step an authorization request can be made from.
|
|
7
|
+
*
|
|
8
|
+
* `stdOidcFlow` starts at `Dispatch`, but `OidcAuthService.authenticate` refuses any state that is
|
|
9
|
+
* not `Ephemeral` and returns null — so an application whose flow was only booted can ask for an
|
|
10
|
+
* authorization URL all day and be told nothing, forever. The dispatcher in this package has always
|
|
11
|
+
* done this transition inline; a relying party that replaces that dispatcher (`web-oidc-rp`,
|
|
12
|
+
* `mui-oidc-rp`) inherited the requirement without the code, which is what left a sign-in button
|
|
13
|
+
* that reported no error and did nothing at all.
|
|
14
|
+
*
|
|
15
|
+
* `Ephemeral` is the branch for an application that is its OWN authority — its flow configuration
|
|
16
|
+
* maps the auth service to a placeholder, which is exactly the generated-application case. An app
|
|
17
|
+
* federated with a real auth service keeps its target and is left alone.
|
|
18
|
+
*
|
|
19
|
+
* Idempotent, and safe to call on every attempt: a flow already past `Dispatch`, or one that is
|
|
20
|
+
* not the standard OIDC flow at all, is returned untouched.
|
|
21
|
+
*/
|
|
22
|
+
export const enterOidcAuthorization = (model: FlowModel): FlowModel => {
|
|
23
|
+
const state = model.state()
|
|
24
|
+
if (state.flow !== STD_OIDC_FLOW || state.step !== OidcAuthStep.Dispatch) {
|
|
25
|
+
return model
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const target = model.step().service
|
|
29
|
+
if (state.service == null || state.service === '') {
|
|
30
|
+
model.target(target)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// The entity travels to this app's own backend, which resolves its default provider by `def`
|
|
34
|
+
// alone. It still has to BE there: the init endpoint rejects a body without one.
|
|
35
|
+
if (state.entityId == null) {
|
|
36
|
+
model.entity(DEFAULT_ENTITY)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (target === FLOW_PLACEHOLDER) {
|
|
40
|
+
model.transit(OidcAuthStep.Ephemeral, true)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return model
|
|
44
|
+
}
|
package/src/login/i18n/be.json
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"method": {
|
|
8
8
|
"google": "Працягнуць з Google",
|
|
9
9
|
"oidc": "Працягнуць з {{provider}}",
|
|
10
|
-
"oidc-default": "Увайсці",
|
|
10
|
+
"oidc-default": "Увайсці / Зарэгістравацца",
|
|
11
11
|
"oidc-client": "Працягнуць з {{provider}}",
|
|
12
12
|
"basic-ed25519": "Увайсці з ключом",
|
|
13
13
|
"pk-supervisor": "Сакрэтны ключ (аператар)",
|
package/src/login/i18n/de.json
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"method": {
|
|
8
8
|
"google": "Mit Google fortfahren",
|
|
9
9
|
"oidc": "Mit {{provider}} fortfahren",
|
|
10
|
-
"oidc-default": "Anmelden",
|
|
10
|
+
"oidc-default": "Anmelden / Registrieren",
|
|
11
11
|
"oidc-client": "Mit {{provider}} fortfahren",
|
|
12
12
|
"basic-ed25519": "Mit einem Schlüssel anmelden",
|
|
13
13
|
"pk-supervisor": "Geheimer Schlüssel (Betreiber)",
|
package/src/login/i18n/en.json
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"method": {
|
|
8
8
|
"google": "Continue with Google",
|
|
9
9
|
"oidc": "Continue with {{provider}}",
|
|
10
|
-
"oidc-default": "Sign in",
|
|
10
|
+
"oidc-default": "Sign in / Sign up",
|
|
11
11
|
"oidc-client": "Continue with {{provider}}",
|
|
12
12
|
"basic-ed25519": "Sign in with a key",
|
|
13
13
|
"pk-supervisor": "Secret key (operator)",
|
package/src/login/i18n/es.json
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"method": {
|
|
8
8
|
"google": "Continuar con Google",
|
|
9
9
|
"oidc": "Continuar con {{provider}}",
|
|
10
|
-
"oidc-default": "Iniciar sesión",
|
|
10
|
+
"oidc-default": "Iniciar sesión / Registrarse",
|
|
11
11
|
"oidc-client": "Continuar con {{provider}}",
|
|
12
12
|
"basic-ed25519": "Iniciar sesión con una clave",
|
|
13
13
|
"pk-supervisor": "Clave secreta (operador)",
|
package/src/login/i18n/pl.json
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"method": {
|
|
8
8
|
"google": "Kontynuuj z Google",
|
|
9
9
|
"oidc": "Kontynuuj z {{provider}}",
|
|
10
|
-
"oidc-default": "Zaloguj się",
|
|
10
|
+
"oidc-default": "Zaloguj się / Zarejestruj się",
|
|
11
11
|
"oidc-client": "Kontynuuj z {{provider}}",
|
|
12
12
|
"basic-ed25519": "Zaloguj się kluczem",
|
|
13
13
|
"pk-supervisor": "Klucz tajny (operator)",
|
package/src/login/i18n/ru.json
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"method": {
|
|
8
8
|
"google": "Продолжить с Google",
|
|
9
9
|
"oidc": "Продолжить с {{provider}}",
|
|
10
|
-
"oidc-default": "Войти",
|
|
10
|
+
"oidc-default": "Войти / Зарегистрироваться",
|
|
11
11
|
"oidc-client": "Продолжить с {{provider}}",
|
|
12
12
|
"basic-ed25519": "Войти с ключом",
|
|
13
13
|
"pk-supervisor": "Секретный ключ (оператор)",
|
package/src/login/i18n/uk.json
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"method": {
|
|
8
8
|
"google": "Продовжити з Google",
|
|
9
9
|
"oidc": "Продовжити з {{provider}}",
|
|
10
|
-
"oidc-default": "Увійти",
|
|
10
|
+
"oidc-default": "Увійти / Зареєструватися",
|
|
11
11
|
"oidc-client": "Продовжити з {{provider}}",
|
|
12
12
|
"basic-ed25519": "Увійти з ключем",
|
|
13
13
|
"pk-supervisor": "Секретний ключ (оператор)",
|
package/src/login/index.ts
CHANGED
package/src/login/resume.ts
CHANGED
|
@@ -1,5 +1,28 @@
|
|
|
1
1
|
import { LoginOutcome } from './types.js'
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* The message key a FINISHED sign-in attempt should show, or null when it actually went somewhere.
|
|
5
|
+
*
|
|
6
|
+
* A dispatcher may treat `Passed` as "carry on with the ordinary continuation", because it has one.
|
|
7
|
+
* A screen does not: the user clicked, the document did not move, and nothing rendered — which is
|
|
8
|
+
* indistinguishable from a broken button, and is exactly how a null authorization URL used to
|
|
9
|
+
* present itself. Every outcome that leaves the user looking at the same screen therefore has to
|
|
10
|
+
* say something.
|
|
11
|
+
*/
|
|
12
|
+
export const loginAttemptError = (outcome: LoginOutcome | null): string | null => {
|
|
13
|
+
switch (outcome) {
|
|
14
|
+
case LoginOutcome.Gesture:
|
|
15
|
+
// The window never opened. That is the popup blocker, and it has its own copy.
|
|
16
|
+
return 'login.error.blocked'
|
|
17
|
+
case LoginOutcome.Failed:
|
|
18
|
+
case LoginOutcome.Passed:
|
|
19
|
+
return 'login.error.failed'
|
|
20
|
+
default:
|
|
21
|
+
// Handled, Redirected and Orphaned all did something; Orphaned reports itself elsewhere.
|
|
22
|
+
return null
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
3
26
|
/** What a dispatcher does once `login().resume(...)` has answered. */
|
|
4
27
|
export enum ResumeAction {
|
|
5
28
|
/** The plugin took it over — the browser is leaving, or the window is closing. */
|
package/tests/login.spec.ts
CHANGED
|
@@ -6,7 +6,7 @@ import { resolveCredit } from '../src/login/credit.js'
|
|
|
6
6
|
import { pluginMethodSource } from '../src/manager/plugins/methods.js'
|
|
7
7
|
import { registerAuthPlugin } from '../src/manager/plugins/registry.js'
|
|
8
8
|
import type { AuthenticationPlugin } from '../src/manager/plugins/types.js'
|
|
9
|
-
import { resumeAction, ResumeAction } from '../src/login/resume.js'
|
|
9
|
+
import { resumeAction, ResumeAction, loginAttemptError } from '../src/login/resume.js'
|
|
10
10
|
import { LoginOutcome } from '../src/login/types.js'
|
|
11
11
|
import type {
|
|
12
12
|
LoginEnv, LoginMethod, LoginMethodContext, LoginPlugin, LoginService,
|
|
@@ -282,6 +282,24 @@ describe('the authentication-plugin method source', () => {
|
|
|
282
282
|
})
|
|
283
283
|
})
|
|
284
284
|
|
|
285
|
+
describe('a finished sign-in attempt', () => {
|
|
286
|
+
test('reports every outcome that leaves the user on the screen', () => {
|
|
287
|
+
// The regression: a method that could not build an authorization URL returned `Passed`, the
|
|
288
|
+
// screen rendered nothing, and the button read as broken. `Passed` is a valid answer TO A
|
|
289
|
+
// DISPATCHER, which has a continuation; a screen does not.
|
|
290
|
+
expect(loginAttemptError(LoginOutcome.Passed)).toBe('login.error.failed')
|
|
291
|
+
expect(loginAttemptError(LoginOutcome.Failed)).toBe('login.error.failed')
|
|
292
|
+
expect(loginAttemptError(LoginOutcome.Gesture)).toBe('login.error.blocked')
|
|
293
|
+
})
|
|
294
|
+
|
|
295
|
+
test('says nothing when the attempt actually went somewhere', () => {
|
|
296
|
+
expect(loginAttemptError(LoginOutcome.Handled)).toBeNull()
|
|
297
|
+
expect(loginAttemptError(LoginOutcome.Redirected)).toBeNull()
|
|
298
|
+
expect(loginAttemptError(LoginOutcome.Orphaned)).toBeNull()
|
|
299
|
+
expect(loginAttemptError(null)).toBeNull()
|
|
300
|
+
})
|
|
301
|
+
})
|
|
302
|
+
|
|
285
303
|
describe('resume outcomes', () => {
|
|
286
304
|
test('map to exactly one action each', () => {
|
|
287
305
|
expect(resumeAction(LoginOutcome.Handled)).toBe(ResumeAction.Stop)
|