@owlmeans/web-auth-email 0.0.0-stage → 0.1.19
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 +116 -2
- package/THIRD-PARTY-NOTICES.txt +24 -0
- package/agent-meta/manifest.json +16 -0
- package/agent-meta/skills/web-auth-email/SKILL.md +119 -0
- package/build/@/components/ui/alert.d.ts +10 -0
- package/build/@/components/ui/alert.d.ts.map +1 -0
- package/build/@/components/ui/alert.js +26 -0
- package/build/@/components/ui/alert.js.map +1 -0
- package/build/@/components/ui/button.d.ts +11 -0
- package/build/@/components/ui/button.d.ts.map +1 -0
- package/build/@/components/ui/button.js +32 -0
- package/build/@/components/ui/button.js.map +1 -0
- package/build/@/components/ui/card.d.ts +10 -0
- package/build/@/components/ui/card.d.ts.map +1 -0
- package/build/@/components/ui/card.js +25 -0
- package/build/@/components/ui/card.js.map +1 -0
- package/build/@/components/ui/input.d.ts +4 -0
- package/build/@/components/ui/input.d.ts.map +1 -0
- package/build/@/components/ui/input.js +7 -0
- package/build/@/components/ui/input.js.map +1 -0
- package/build/@/components/ui/label.d.ts +5 -0
- package/build/@/components/ui/label.d.ts.map +1 -0
- package/build/@/components/ui/label.js +8 -0
- package/build/@/components/ui/label.js.map +1 -0
- package/build/@/lib/utils.d.ts +3 -0
- package/build/@/lib/utils.d.ts.map +1 -0
- package/build/@/lib/utils.js +6 -0
- package/build/@/lib/utils.js.map +1 -0
- package/build/append.d.ts +23 -0
- package/build/append.d.ts.map +1 -0
- package/build/append.js +49 -0
- package/build/append.js.map +1 -0
- package/build/components/connected.d.ts +8 -0
- package/build/components/connected.d.ts.map +1 -0
- package/build/components/connected.js +16 -0
- package/build/components/connected.js.map +1 -0
- package/build/components/credit.d.ts +5 -0
- package/build/components/credit.d.ts.map +1 -0
- package/build/components/credit.js +16 -0
- package/build/components/credit.js.map +1 -0
- package/build/components/fields.d.ts +23 -0
- package/build/components/fields.d.ts.map +1 -0
- package/build/components/fields.js +39 -0
- package/build/components/fields.js.map +1 -0
- package/build/components/index.d.ts +9 -0
- package/build/components/index.d.ts.map +1 -0
- package/build/components/index.js +8 -0
- package/build/components/index.js.map +1 -0
- package/build/components/offer.d.ts +9 -0
- package/build/components/offer.d.ts.map +1 -0
- package/build/components/offer.js +99 -0
- package/build/components/offer.js.map +1 -0
- package/build/components/panel.d.ts +12 -0
- package/build/components/panel.d.ts.map +1 -0
- package/build/components/panel.js +129 -0
- package/build/components/panel.js.map +1 -0
- package/build/components/route.d.ts +9 -0
- package/build/components/route.d.ts.map +1 -0
- package/build/components/route.js +17 -0
- package/build/components/route.js.map +1 -0
- package/build/components/screen.d.ts +17 -0
- package/build/components/screen.d.ts.map +1 -0
- package/build/components/screen.js +79 -0
- package/build/components/screen.js.map +1 -0
- package/build/components/types.d.ts +81 -0
- package/build/components/types.d.ts.map +1 -0
- package/build/components/types.js +2 -0
- package/build/components/types.js.map +1 -0
- package/build/consts.d.ts +37 -0
- package/build/consts.d.ts.map +1 -0
- package/build/consts.js +43 -0
- package/build/consts.js.map +1 -0
- package/build/entrypoints.d.ts +10 -0
- package/build/entrypoints.d.ts.map +1 -0
- package/build/entrypoints.js +14 -0
- package/build/entrypoints.js.map +1 -0
- package/build/hooks/consts.local.d.ts +4 -0
- package/build/hooks/consts.local.d.ts.map +1 -0
- package/build/hooks/consts.local.js +9 -0
- package/build/hooks/consts.local.js.map +1 -0
- package/build/hooks/types.d.ts +78 -0
- package/build/hooks/types.d.ts.map +1 -0
- package/build/hooks/types.js +2 -0
- package/build/hooks/types.js.map +1 -0
- package/build/hooks/use-email-login.d.ts +13 -0
- package/build/hooks/use-email-login.d.ts.map +1 -0
- package/build/hooks/use-email-login.js +208 -0
- package/build/hooks/use-email-login.js.map +1 -0
- package/build/hooks/use-password.d.ts +13 -0
- package/build/hooks/use-password.d.ts.map +1 -0
- package/build/hooks/use-password.js +118 -0
- package/build/hooks/use-password.js.map +1 -0
- package/build/hooks/use-translate.d.ts +7 -0
- package/build/hooks/use-translate.d.ts.map +1 -0
- package/build/hooks/use-translate.js +12 -0
- package/build/hooks/use-translate.js.map +1 -0
- package/build/i18n/auth/be.json +7 -0
- package/build/i18n/auth/de.json +7 -0
- package/build/i18n/auth/en.json +7 -0
- package/build/i18n/auth/es.json +7 -0
- package/build/i18n/auth/fr.json +7 -0
- package/build/i18n/auth/pl.json +7 -0
- package/build/i18n/auth/ru.json +7 -0
- package/build/i18n/auth/uk.json +7 -0
- package/build/i18n/be.json +100 -0
- package/build/i18n/de.json +100 -0
- package/build/i18n/en.json +100 -0
- package/build/i18n/es.json +100 -0
- package/build/i18n/fr.json +100 -0
- package/build/i18n/pl.json +100 -0
- package/build/i18n/ru.json +100 -0
- package/build/i18n/uk.json +100 -0
- package/build/i18n.d.ts +2 -0
- package/build/i18n.d.ts.map +1 -0
- package/build/i18n.js +40 -0
- package/build/i18n.js.map +1 -0
- package/build/index.d.ts +23 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +17 -0
- package/build/index.js.map +1 -0
- package/build/password/types.d.ts +39 -0
- package/build/password/types.d.ts.map +1 -0
- package/build/password/types.js +2 -0
- package/build/password/types.js.map +1 -0
- package/build/password.d.ts +4 -0
- package/build/password.d.ts.map +1 -0
- package/build/password.js +45 -0
- package/build/password.js.map +1 -0
- package/build/plugin.d.ts +10 -0
- package/build/plugin.d.ts.map +1 -0
- package/build/plugin.js +21 -0
- package/build/plugin.js.map +1 -0
- package/build/refusal/consts.local.d.ts +3 -0
- package/build/refusal/consts.local.d.ts.map +1 -0
- package/build/refusal/consts.local.js +3 -0
- package/build/refusal/consts.local.js.map +1 -0
- package/build/refusal/types.d.ts +38 -0
- package/build/refusal/types.d.ts.map +1 -0
- package/build/refusal/types.js +2 -0
- package/build/refusal/types.js.map +1 -0
- package/build/refusal.d.ts +4 -0
- package/build/refusal.d.ts.map +1 -0
- package/build/refusal.js +131 -0
- package/build/refusal.js.map +1 -0
- package/build/service.d.ts +12 -0
- package/build/service.d.ts.map +1 -0
- package/build/service.js +66 -0
- package/build/service.js.map +1 -0
- package/build/state/types.d.ts +90 -0
- package/build/state/types.d.ts.map +1 -0
- package/build/state/types.js +2 -0
- package/build/state/types.js.map +1 -0
- package/build/state.d.ts +4 -0
- package/build/state.d.ts.map +1 -0
- package/build/state.js +98 -0
- package/build/state.js.map +1 -0
- package/build/step.d.ts +16 -0
- package/build/step.d.ts.map +1 -0
- package/build/step.js +31 -0
- package/build/step.js.map +1 -0
- package/build/storage/types.d.ts +42 -0
- package/build/storage/types.d.ts.map +1 -0
- package/build/storage/types.js +2 -0
- package/build/storage/types.js.map +1 -0
- package/build/storage.d.ts +4 -0
- package/build/storage.d.ts.map +1 -0
- package/build/storage.js +100 -0
- package/build/storage.js.map +1 -0
- package/build/types.d.ts +102 -0
- package/build/types.d.ts.map +1 -0
- package/build/types.js +2 -0
- package/build/types.js.map +1 -0
- package/build/utils/account.d.ts +4 -0
- package/build/utils/account.d.ts.map +1 -0
- package/build/utils/account.js +11 -0
- package/build/utils/account.js.map +1 -0
- package/build/utils/locale.d.ts +6 -0
- package/build/utils/locale.d.ts.map +1 -0
- package/build/utils/locale.js +10 -0
- package/build/utils/locale.js.map +1 -0
- package/build/utils/text/types.d.ts +23 -0
- package/build/utils/text/types.d.ts.map +1 -0
- package/build/utils/text/types.js +2 -0
- package/build/utils/text/types.js.map +1 -0
- package/build/utils/text.d.ts +4 -0
- package/build/utils/text.d.ts.map +1 -0
- package/build/utils/text.js +26 -0
- package/build/utils/text.js.map +1 -0
- package/build/utils.d.ts +8 -0
- package/build/utils.d.ts.map +1 -0
- package/build/utils.js +9 -0
- package/build/utils.js.map +1 -0
- package/components.json +21 -0
- package/package.json +71 -4
- package/src/@/components/ui/alert.tsx +70 -0
- package/src/@/components/ui/button.tsx +60 -0
- package/src/@/components/ui/card.tsx +93 -0
- package/src/@/components/ui/input.tsx +22 -0
- package/src/@/components/ui/label.tsx +23 -0
- package/src/@/globals.css +57 -0
- package/src/@/lib/utils.ts +6 -0
- package/src/append.ts +65 -0
- package/src/components/connected.tsx +36 -0
- package/src/components/credit.tsx +30 -0
- package/src/components/fields.tsx +112 -0
- package/src/components/index.ts +8 -0
- package/src/components/offer.tsx +197 -0
- package/src/components/panel.tsx +299 -0
- package/src/components/route.tsx +20 -0
- package/src/components/screen.tsx +253 -0
- package/src/components/types.ts +85 -0
- package/src/consts.ts +53 -0
- package/src/entrypoints.ts +15 -0
- package/src/hooks/consts.local.ts +12 -0
- package/src/hooks/types.ts +79 -0
- package/src/hooks/use-email-login.ts +234 -0
- package/src/hooks/use-password.ts +137 -0
- package/src/hooks/use-translate.ts +14 -0
- package/src/i18n/auth/be.json +7 -0
- package/src/i18n/auth/de.json +7 -0
- package/src/i18n/auth/en.json +7 -0
- package/src/i18n/auth/es.json +7 -0
- package/src/i18n/auth/fr.json +7 -0
- package/src/i18n/auth/pl.json +7 -0
- package/src/i18n/auth/ru.json +7 -0
- package/src/i18n/auth/uk.json +7 -0
- package/src/i18n/be.json +100 -0
- package/src/i18n/de.json +100 -0
- package/src/i18n/en.json +100 -0
- package/src/i18n/es.json +100 -0
- package/src/i18n/fr.json +100 -0
- package/src/i18n/pl.json +100 -0
- package/src/i18n/ru.json +100 -0
- package/src/i18n/uk.json +100 -0
- package/src/i18n.ts +43 -0
- package/src/index.ts +22 -0
- package/src/password/types.ts +43 -0
- package/src/password.ts +65 -0
- package/src/plugin.ts +22 -0
- package/src/refusal/consts.local.ts +2 -0
- package/src/refusal/types.ts +64 -0
- package/src/refusal.ts +145 -0
- package/src/service.ts +95 -0
- package/src/state/types.ts +72 -0
- package/src/state.ts +115 -0
- package/src/step.ts +38 -0
- package/src/storage/types.ts +43 -0
- package/src/storage.ts +113 -0
- package/src/types.ts +111 -0
- package/src/utils/account.ts +12 -0
- package/src/utils/locale.ts +11 -0
- package/src/utils/text/types.ts +24 -0
- package/src/utils/text.ts +34 -0
- package/src/utils.ts +9 -0
- package/tests/helpers.ts +22 -0
- package/tests/i18n.spec.ts +94 -0
- package/tests/package-boundary.spec.ts +35 -0
- package/tests/password.spec.ts +56 -0
- package/tests/refusal.spec.ts +91 -0
- package/tests/state.spec.ts +99 -0
- package/tests/step.spec.ts +82 -0
- package/tests/storage.spec.ts +83 -0
- package/tsconfig.json +21 -0
package/build/service.js
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { createLazyService } from '@owlmeans/context';
|
|
2
|
+
import { DEFAULT_ALIAS as AUTH_SERVICE } from '@owlmeans/client-auth';
|
|
3
|
+
import { loginLandingOf } from '@owlmeans/client-auth/login';
|
|
4
|
+
import { EMAIL_LOGIN_SERVICE, EmailAuthError } from '@owlmeans/auth-email';
|
|
5
|
+
import { emailStorageHelper } from './storage.js';
|
|
6
|
+
import { signedInAccount } from './utils/account.js';
|
|
7
|
+
/**
|
|
8
|
+
* Build the browser-side `EmailLoginClientService` over one protocol tree.
|
|
9
|
+
*
|
|
10
|
+
* Every call goes through `ctx.entrypoint(protocol)`, so the application binds the API routes
|
|
11
|
+
* itself (`bindAll`) — the same split as marketing consent's client.
|
|
12
|
+
*/
|
|
13
|
+
export const makeEmailLoginClient = (protocols, opts = {}) => {
|
|
14
|
+
const alias = opts.alias ?? EMAIL_LOGIN_SERVICE;
|
|
15
|
+
let options = null;
|
|
16
|
+
let screen = opts.screen ?? null;
|
|
17
|
+
const ctx = () => service.assertCtx(alias);
|
|
18
|
+
const service = createLazyService(alias, {
|
|
19
|
+
protocols: () => protocols,
|
|
20
|
+
options: async (request) => {
|
|
21
|
+
if (request?.fresh !== true && options != null) {
|
|
22
|
+
return options;
|
|
23
|
+
}
|
|
24
|
+
options = await ctx().entrypoint(protocols.options).call({});
|
|
25
|
+
return options;
|
|
26
|
+
},
|
|
27
|
+
sendPin: async (request) => await ctx().entrypoint(protocols.pin).call({ body: request }),
|
|
28
|
+
signIn: async (request) => await ctx().entrypoint(protocols.signIn).call({ body: request }),
|
|
29
|
+
complete: async (view) => {
|
|
30
|
+
if (view.token == null || view.token === '') {
|
|
31
|
+
throw new EmailAuthError('answer');
|
|
32
|
+
}
|
|
33
|
+
const context = ctx();
|
|
34
|
+
await context.service(AUTH_SERVICE).authenticate({ token: view.token });
|
|
35
|
+
// Kept AFTER the token is adopted, so the ticket names the account it belongs to and a sign-in
|
|
36
|
+
// that failed keeps nothing. Any older ticket is dropped by the sign-in that does not bring one.
|
|
37
|
+
if (view.offer != null && view.offer !== '') {
|
|
38
|
+
emailStorageHelper.keepOffer(view.offer, signedInAccount(context));
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
emailStorageHelper.dropOffer();
|
|
42
|
+
}
|
|
43
|
+
// The supervisor and Google plugins land the same way: a full load of the landing, which
|
|
44
|
+
// inside a surrogate window is the dispatcher that hands the session back to the opener.
|
|
45
|
+
const landings = loginLandingOf(context);
|
|
46
|
+
const landing = await landings.landAfterLogin();
|
|
47
|
+
window.location.href = await landings.landingUrl(landing);
|
|
48
|
+
},
|
|
49
|
+
passwordStatus: async () => await ctx().entrypoint(protocols.password.status).call({}),
|
|
50
|
+
passwordPin: async (request) => await ctx().entrypoint(protocols.password.pin).call({ body: request }),
|
|
51
|
+
setPassword: async (request) => await ctx().entrypoint(protocols.password.set).call({ body: request }),
|
|
52
|
+
removePassword: async (request) => await ctx().entrypoint(protocols.password.remove).call({ body: request }),
|
|
53
|
+
declinePassword: async () => await ctx().entrypoint(protocols.password.decline).call({ body: {} }),
|
|
54
|
+
screen: () => screen,
|
|
55
|
+
registerScreen: next => { screen = next; },
|
|
56
|
+
});
|
|
57
|
+
return service;
|
|
58
|
+
};
|
|
59
|
+
/** Register the client service, unless the application already registered its own under the alias. */
|
|
60
|
+
export const appendEmailLoginClient = (context, protocols, opts = {}) => {
|
|
61
|
+
const alias = opts.alias ?? EMAIL_LOGIN_SERVICE;
|
|
62
|
+
if (!context.hasService(alias)) {
|
|
63
|
+
context.registerService(makeEmailLoginClient(protocols, opts));
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
//# sourceMappingURL=service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service.js","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import type { EmailAuthOptionsView } from '@owlmeans/auth-email';
|
|
2
|
+
import type { EmailRefusal } from '../refusal/types.js';
|
|
3
|
+
/** Which part of the form is showing. `done` = signed in, the browser is leaving. */
|
|
4
|
+
export type EmailLoginStep = 'email' | 'pin' | 'password' | 'done';
|
|
5
|
+
/** The call in flight: mailing a PIN, or signing in (PIN or password). */
|
|
6
|
+
export type EmailLoginBusy = 'send' | 'sign-in';
|
|
7
|
+
/** Why the PIN step is up: a code was asked for, or a password sign-in met an unknown device. */
|
|
8
|
+
export type EmailLoginNotice = 'sent' | 'device';
|
|
9
|
+
/** The whole e-mail sign-in form, as a plain value. */
|
|
10
|
+
export interface EmailLoginState {
|
|
11
|
+
step: EmailLoginStep;
|
|
12
|
+
email: string;
|
|
13
|
+
pin: string;
|
|
14
|
+
password: string;
|
|
15
|
+
/** The password field shows what was typed. */
|
|
16
|
+
reveal: boolean;
|
|
17
|
+
/** The signed challenge of the PIN mailed last; null until one is. */
|
|
18
|
+
challenge: string | null;
|
|
19
|
+
notice: EmailLoginNotice | null;
|
|
20
|
+
busy: EmailLoginBusy | null;
|
|
21
|
+
refusal: EmailRefusal | null;
|
|
22
|
+
/** What the deployment offers; null until `GET options` answered. */
|
|
23
|
+
options: EmailAuthOptionsView | null;
|
|
24
|
+
/** The options read failed — the form still works, and the next send asks again. */
|
|
25
|
+
optionsFailed: boolean;
|
|
26
|
+
}
|
|
27
|
+
/** Everything that changes the form. */
|
|
28
|
+
export type EmailLoginAction = {
|
|
29
|
+
type: 'options';
|
|
30
|
+
options: EmailAuthOptionsView;
|
|
31
|
+
} | {
|
|
32
|
+
type: 'options-failed';
|
|
33
|
+
} | {
|
|
34
|
+
type: 'email';
|
|
35
|
+
value: string;
|
|
36
|
+
} | {
|
|
37
|
+
type: 'pin';
|
|
38
|
+
value: string;
|
|
39
|
+
} | {
|
|
40
|
+
type: 'password';
|
|
41
|
+
value: string;
|
|
42
|
+
} | {
|
|
43
|
+
type: 'reveal';
|
|
44
|
+
value: boolean;
|
|
45
|
+
} | {
|
|
46
|
+
type: 'choose-password';
|
|
47
|
+
} | {
|
|
48
|
+
type: 'choose-pin';
|
|
49
|
+
} | {
|
|
50
|
+
type: 'change-email';
|
|
51
|
+
} | {
|
|
52
|
+
type: 'start';
|
|
53
|
+
busy: EmailLoginBusy;
|
|
54
|
+
} | {
|
|
55
|
+
type: 'sent';
|
|
56
|
+
challenge: string;
|
|
57
|
+
} | {
|
|
58
|
+
type: 'device';
|
|
59
|
+
challenge: string;
|
|
60
|
+
} | {
|
|
61
|
+
type: 'signed-in';
|
|
62
|
+
} | {
|
|
63
|
+
type: 'refused';
|
|
64
|
+
refusal: EmailRefusal;
|
|
65
|
+
};
|
|
66
|
+
/**
|
|
67
|
+
* The e-mail sign-in form as pure transitions — what `useEmailLogin` runs through `useReducer`, and
|
|
68
|
+
* what a replacement screen or a test can drive without a DOM.
|
|
69
|
+
*/
|
|
70
|
+
export interface EmailLoginStateHelper {
|
|
71
|
+
/** The empty form on its e-mail step. */
|
|
72
|
+
initial: (email?: string) => EmailLoginState;
|
|
73
|
+
/** The next form after `action`. Never mutates `state`. */
|
|
74
|
+
reduce: (state: EmailLoginState, action: EmailLoginAction) => EmailLoginState;
|
|
75
|
+
/** A plausible address: one `@`, a dotted domain, no spaces, within the wire bound. */
|
|
76
|
+
validEmail: (email: string) => boolean;
|
|
77
|
+
/** The address as it is sent: trimmed and lowercased. */
|
|
78
|
+
normalizeEmail: (email: string) => string;
|
|
79
|
+
/** Digits in a PIN — the deployment's own when known. */
|
|
80
|
+
pinLength: (state: EmailLoginState) => number;
|
|
81
|
+
/** Password sign-in is offered here. */
|
|
82
|
+
passwordOffered: (state: EmailLoginState) => boolean;
|
|
83
|
+
/** What stops "send a PIN" right now (the address), or null when it may go. */
|
|
84
|
+
sendBlock: (state: EmailLoginState) => EmailRefusal | null;
|
|
85
|
+
/** What stops "sign in with the PIN" right now, or null when it may go. */
|
|
86
|
+
verifyBlock: (state: EmailLoginState) => EmailRefusal | null;
|
|
87
|
+
/** What stops a password sign-in right now, or null when it may go. */
|
|
88
|
+
signInBlock: (state: EmailLoginState) => EmailRefusal | null;
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/state/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/state/types.ts"],"names":[],"mappings":""}
|
package/build/state.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../src/state.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAqC,qBAAqB,EAAE,MAAM,kBAAkB,CAAA;AAEhG,eAAO,MAAM,2BAA2B,QAAO,qBA4G9C,CAAA;AAED,eAAO,MAAM,qBAAqB,uBAAgC,CAAA"}
|
package/build/state.js
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { EMAIL_ADDRESS_MAX_LENGTH, EMAIL_PIN_LENGTH } from '@owlmeans/auth-email';
|
|
2
|
+
export const createEmailLoginStateHelper = () => {
|
|
3
|
+
const address = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
4
|
+
const initial = (email = '') => ({
|
|
5
|
+
step: 'email', email, pin: '', password: '', reveal: false, challenge: null, notice: null,
|
|
6
|
+
busy: null, refusal: null, options: null, optionsFailed: false,
|
|
7
|
+
});
|
|
8
|
+
const normalizeEmail = (email) => email.trim().toLowerCase();
|
|
9
|
+
const validEmail = (email) => {
|
|
10
|
+
const value = normalizeEmail(email);
|
|
11
|
+
return value.length <= EMAIL_ADDRESS_MAX_LENGTH && address.test(value);
|
|
12
|
+
};
|
|
13
|
+
const pinLength = (state) => state.options?.pinLength ?? EMAIL_PIN_LENGTH;
|
|
14
|
+
const passwordOffered = (state) => state.options?.password === true;
|
|
15
|
+
const sendBlock = (state) => validEmail(state.email) ? null : { kind: 'email' };
|
|
16
|
+
const verifyBlock = (state) => {
|
|
17
|
+
if (state.challenge == null) {
|
|
18
|
+
// Nothing was mailed for this form yet — the person has to ask for a code first.
|
|
19
|
+
return { kind: 'code' };
|
|
20
|
+
}
|
|
21
|
+
return new RegExp(`^[0-9]{${pinLength(state)}}$`).test(state.pin) ? null : { kind: 'pin-format' };
|
|
22
|
+
};
|
|
23
|
+
const signInBlock = (state) => {
|
|
24
|
+
if (!validEmail(state.email)) {
|
|
25
|
+
return { kind: 'email' };
|
|
26
|
+
}
|
|
27
|
+
if (!passwordOffered(state)) {
|
|
28
|
+
return { kind: 'password-disabled' };
|
|
29
|
+
}
|
|
30
|
+
return state.password === '' ? { kind: 'password-empty' } : null;
|
|
31
|
+
};
|
|
32
|
+
const reduce = (state, action) => {
|
|
33
|
+
switch (action.type) {
|
|
34
|
+
case 'options':
|
|
35
|
+
return {
|
|
36
|
+
...state, options: action.options, optionsFailed: false,
|
|
37
|
+
// The deployment turned passwords off under an open password step: back to the code.
|
|
38
|
+
...(state.step === 'password' && action.options.password !== true
|
|
39
|
+
? { step: 'email', password: '', reveal: false } : {}),
|
|
40
|
+
};
|
|
41
|
+
case 'options-failed':
|
|
42
|
+
return { ...state, optionsFailed: true };
|
|
43
|
+
case 'email':
|
|
44
|
+
return state.step === 'done' ? state : { ...state, email: action.value, refusal: null };
|
|
45
|
+
case 'pin':
|
|
46
|
+
return state.step === 'done' ? state : {
|
|
47
|
+
...state, pin: action.value.replace(/\D/g, '').slice(0, pinLength(state)), refusal: null,
|
|
48
|
+
};
|
|
49
|
+
case 'password':
|
|
50
|
+
return state.step === 'done' ? state : { ...state, password: action.value, refusal: null };
|
|
51
|
+
case 'reveal':
|
|
52
|
+
return { ...state, reveal: action.value };
|
|
53
|
+
case 'choose-password':
|
|
54
|
+
return state.busy != null || !passwordOffered(state) || state.step === 'done' ? state : {
|
|
55
|
+
...state, step: 'password', pin: '', notice: null, refusal: null,
|
|
56
|
+
};
|
|
57
|
+
case 'choose-pin':
|
|
58
|
+
return state.busy != null || state.step === 'done' ? state : {
|
|
59
|
+
...state, step: 'email', password: '', reveal: false, refusal: null,
|
|
60
|
+
};
|
|
61
|
+
case 'change-email':
|
|
62
|
+
return state.busy != null || state.step === 'done' ? state : {
|
|
63
|
+
...state, step: 'email', pin: '', password: '', reveal: false, challenge: null, notice: null, refusal: null,
|
|
64
|
+
};
|
|
65
|
+
case 'start':
|
|
66
|
+
return state.busy != null || state.step === 'done' ? state : { ...state, busy: action.busy, refusal: null };
|
|
67
|
+
case 'sent':
|
|
68
|
+
return { ...state, step: 'pin', challenge: action.challenge, notice: 'sent', pin: '', busy: null, refusal: null };
|
|
69
|
+
case 'device':
|
|
70
|
+
// A password sign-in on a device the account does not know: the password was NOT checked,
|
|
71
|
+
// a PIN was mailed instead, and the password is not kept around for later.
|
|
72
|
+
return {
|
|
73
|
+
...state, step: 'pin', challenge: action.challenge, notice: 'device', pin: '', password: '',
|
|
74
|
+
reveal: false, busy: null, refusal: null,
|
|
75
|
+
};
|
|
76
|
+
case 'signed-in':
|
|
77
|
+
// Nothing secret stays in the form while the browser is leaving.
|
|
78
|
+
return { ...state, step: 'done', pin: '', password: '', reveal: false, busy: null, refusal: null };
|
|
79
|
+
case 'refused':
|
|
80
|
+
return {
|
|
81
|
+
...state,
|
|
82
|
+
// Completing a sign-in failed after the answer: the person starts over from the address.
|
|
83
|
+
...(state.step === 'done' ? { step: 'email', challenge: null, notice: null } : {}),
|
|
84
|
+
busy: null,
|
|
85
|
+
refusal: action.refusal,
|
|
86
|
+
...(action.refusal.kind === 'code' ? { pin: '' } : {}),
|
|
87
|
+
...(action.refusal.kind === 'credentials' ? { password: '' } : {}),
|
|
88
|
+
};
|
|
89
|
+
default:
|
|
90
|
+
return state;
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
return {
|
|
94
|
+
initial, reduce, validEmail, normalizeEmail, pinLength, passwordOffered, sendBlock, verifyBlock, signInBlock,
|
|
95
|
+
};
|
|
96
|
+
};
|
|
97
|
+
export const emailLoginStateHelper = createEmailLoginStateHelper();
|
|
98
|
+
//# sourceMappingURL=state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state.js","sourceRoot":"","sources":["../src/state.ts"],"names":[],"mappings":"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"}
|
package/build/step.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { LoginStep } from '@owlmeans/client-auth/login';
|
|
2
|
+
import type { EmailStorageHelper } from './storage/types.js';
|
|
3
|
+
import type { EmailLoginClientService } from './types.js';
|
|
4
|
+
/**
|
|
5
|
+
* The post-sign-in "set a password" step.
|
|
6
|
+
*
|
|
7
|
+
* Pending only while BOTH hold: this tab keeps an offer ticket from a fresh PIN sign-in (unexpired,
|
|
8
|
+
* this account's), and the account's password status still says enabled, unset and not declined.
|
|
9
|
+
* A ticket the status no longer allows is forgotten on the spot. Optional: a status read that throws
|
|
10
|
+
* or hangs is "not pending" (the login host fails open), so a broken read never blocks a sign-in.
|
|
11
|
+
*
|
|
12
|
+
* Its priority sits below the marketing-consent step, so a Terms confirmation and the consent
|
|
13
|
+
* choices come first.
|
|
14
|
+
*/
|
|
15
|
+
export declare const emailOfferStep: (client: Pick<EmailLoginClientService, 'passwordStatus'>, entrypointAlias: string, storage?: EmailStorageHelper) => LoginStep;
|
|
16
|
+
//# sourceMappingURL=step.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"step.d.ts","sourceRoot":"","sources":["../src/step.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAA;AAG5D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAA;AAC5D,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAA;AAGzD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,cAAc,WACjB,IAAI,CAAC,uBAAuB,EAAE,gBAAgB,CAAC,mBAAmB,MAAM,YACvE,kBAAkB,KAC1B,SAgBD,CAAA"}
|
package/build/step.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { EMAIL_OFFER_LOGIN_STEP, EMAIL_OFFER_STEP_PRIORITY } from './consts.js';
|
|
2
|
+
import { emailStorageHelper } from './storage.js';
|
|
3
|
+
import { signedInAccount } from './utils/account.js';
|
|
4
|
+
/**
|
|
5
|
+
* The post-sign-in "set a password" step.
|
|
6
|
+
*
|
|
7
|
+
* Pending only while BOTH hold: this tab keeps an offer ticket from a fresh PIN sign-in (unexpired,
|
|
8
|
+
* this account's), and the account's password status still says enabled, unset and not declined.
|
|
9
|
+
* A ticket the status no longer allows is forgotten on the spot. Optional: a status read that throws
|
|
10
|
+
* or hangs is "not pending" (the login host fails open), so a broken read never blocks a sign-in.
|
|
11
|
+
*
|
|
12
|
+
* Its priority sits below the marketing-consent step, so a Terms confirmation and the consent
|
|
13
|
+
* choices come first.
|
|
14
|
+
*/
|
|
15
|
+
export const emailOfferStep = (client, entrypointAlias, storage = emailStorageHelper) => ({
|
|
16
|
+
alias: EMAIL_OFFER_LOGIN_STEP,
|
|
17
|
+
priority: EMAIL_OFFER_STEP_PRIORITY,
|
|
18
|
+
entrypoint: entrypointAlias,
|
|
19
|
+
pending: async (ctx) => {
|
|
20
|
+
if (storage.offer(signedInAccount(ctx)) == null) {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
const status = await client.passwordStatus();
|
|
24
|
+
if (status.enabled && !status.set && !status.declined) {
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
storage.dropOffer();
|
|
28
|
+
return false;
|
|
29
|
+
},
|
|
30
|
+
});
|
|
31
|
+
//# sourceMappingURL=step.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"step.js","sourceRoot":"","sources":["../src/step.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,sBAAsB,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAA;AAC/E,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAA;AAGjD,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AAEpD;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAC5B,MAAuD,EAAE,eAAuB,EAChF,OAAO,GAAuB,kBAAkB,EACrC,EAAE,CAAC,CAAC;IACf,KAAK,EAAE,sBAAsB;IAC7B,QAAQ,EAAE,yBAAyB;IACnC,UAAU,EAAE,eAAe;IAC3B,OAAO,EAAE,KAAK,EAAC,GAAG,EAAC,EAAE;QACnB,IAAI,OAAO,CAAC,KAAK,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC;YAChD,OAAO,KAAK,CAAA;QACd,CAAC;QACD,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,cAAc,EAAE,CAAA;QAC5C,IAAI,MAAM,CAAC,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC;YACtD,OAAO,IAAI,CAAA;QACb,CAAC;QACD,OAAO,CAAC,SAAS,EAAE,CAAA;QAEnB,OAAO,KAAK,CAAA;IACd,CAAC;CACF,CAAC,CAAA"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/** The part of a Web Storage this package uses. */
|
|
2
|
+
export interface EmailStorageArea extends Pick<Storage, 'getItem' | 'setItem' | 'removeItem'> {
|
|
3
|
+
}
|
|
4
|
+
export interface EmailStorageHelperOptions {
|
|
5
|
+
/** Where the device id lives. Default: `window.localStorage`, or nothing when it is unavailable. */
|
|
6
|
+
local?: () => EmailStorageArea | null;
|
|
7
|
+
/** Where the offer ticket waits. Default: `window.sessionStorage`, or nothing when it is unavailable. */
|
|
8
|
+
session?: () => EmailStorageArea | null;
|
|
9
|
+
/** `count` random bytes. Default: `crypto.getRandomValues`. */
|
|
10
|
+
random?: (count: number) => Uint8Array;
|
|
11
|
+
/** The clock, in milliseconds. Default: `Date.now`. */
|
|
12
|
+
now?: () => number;
|
|
13
|
+
}
|
|
14
|
+
/** The offer ticket as it is kept — with the account it was issued to and when it stops counting. */
|
|
15
|
+
export interface StoredEmailOffer {
|
|
16
|
+
ticket: string;
|
|
17
|
+
owner?: string;
|
|
18
|
+
expiresAt: number;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* What a browser keeps for e-mail sign-in: its device id, and a fresh PIN sign-in's offer ticket.
|
|
22
|
+
*
|
|
23
|
+
* Every storage access tolerates a browser that refuses site data (private modes, blocked
|
|
24
|
+
* storage): the device id then lives for the page alone, and no offer is shown.
|
|
25
|
+
*/
|
|
26
|
+
export interface EmailStorageHelper {
|
|
27
|
+
/**
|
|
28
|
+
* This browser's device id — 16 random bytes, base64url (22 characters). Created on first use and
|
|
29
|
+
* kept in `localStorage`; without storage, one id for as long as this page lives.
|
|
30
|
+
*/
|
|
31
|
+
deviceId: () => string;
|
|
32
|
+
/**
|
|
33
|
+
* The waiting offer ticket, or null — also when it has expired, or was issued to another account
|
|
34
|
+
* than `owner` (when both are known).
|
|
35
|
+
*/
|
|
36
|
+
offer: (owner?: string) => string | null;
|
|
37
|
+
/** Keep a PIN sign-in's offer ticket for the offer step, until `EMAIL_OFFER_TTL_SECONDS` pass. */
|
|
38
|
+
keepOffer: (ticket: string, owner?: string) => void;
|
|
39
|
+
/** Forget the offer ticket — it was used, declined, or cannot be used any more. */
|
|
40
|
+
dropOffer: () => void;
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/storage/types.ts"],"names":[],"mappings":"AAAA,mDAAmD;AACnD,MAAM,WAAW,gBAAiB,SAAQ,IAAI,CAAC,OAAO,EAAE,SAAS,GAAG,SAAS,GAAG,YAAY,CAAC;CAAG;AAEhG,MAAM,WAAW,yBAAyB;IACxC,oGAAoG;IACpG,KAAK,CAAC,EAAE,MAAM,gBAAgB,GAAG,IAAI,CAAA;IACrC,yGAAyG;IACzG,OAAO,CAAC,EAAE,MAAM,gBAAgB,GAAG,IAAI,CAAA;IACvC,+DAA+D;IAC/D,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,UAAU,CAAA;IACtC,uDAAuD;IACvD,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;CACnB;AAED,qGAAqG;AACrG,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,SAAS,EAAE,MAAM,CAAA;CAClB;AAED;;;;;GAKG;AACH,MAAM,WAAW,kBAAkB;IACjC;;;OAGG;IACH,QAAQ,EAAE,MAAM,MAAM,CAAA;IACtB;;;OAGG;IACH,KAAK,EAAE,CAAC,KAAK,CAAC,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAA;IACxC,kGAAkG;IAClG,SAAS,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,KAAK,IAAI,CAAA;IACnD,mFAAmF;IACnF,SAAS,EAAE,MAAM,IAAI,CAAA;CACtB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/storage/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { EmailStorageHelper, EmailStorageHelperOptions } from './storage/types.js';
|
|
2
|
+
export declare const createEmailStorageHelper: (opts?: EmailStorageHelperOptions) => EmailStorageHelper;
|
|
3
|
+
export declare const emailStorageHelper: EmailStorageHelper;
|
|
4
|
+
//# sourceMappingURL=storage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACQ,kBAAkB,EAAE,yBAAyB,EAChE,MAAM,oBAAoB,CAAA;AAW3B,eAAO,MAAM,wBAAwB,UAAU,yBAAyB,KAAQ,kBA+F/E,CAAA;AAED,eAAO,MAAM,kBAAkB,oBAA6B,CAAA"}
|
package/build/storage.js
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { EMAIL_DEVICE_ID_PATTERN, EMAIL_OFFER_TTL_SECONDS } from '@owlmeans/auth-email';
|
|
2
|
+
import { EMAIL_DEVICE_ID_BYTES, EMAIL_DEVICE_STORAGE, EMAIL_OFFER_STORAGE } from './consts.js';
|
|
3
|
+
/** A storage area of the page, or null where there is no page or the browser refuses it. */
|
|
4
|
+
const areaOf = (name) => () => {
|
|
5
|
+
try {
|
|
6
|
+
return typeof window !== 'undefined' ? window[name] ?? null : null;
|
|
7
|
+
}
|
|
8
|
+
catch {
|
|
9
|
+
return null;
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
export const createEmailStorageHelper = (opts = {}) => {
|
|
13
|
+
const local = opts.local ?? areaOf('localStorage');
|
|
14
|
+
const session = opts.session ?? areaOf('sessionStorage');
|
|
15
|
+
const random = opts.random ?? ((count) => crypto.getRandomValues(new Uint8Array(count)));
|
|
16
|
+
const now = opts.now ?? (() => Date.now());
|
|
17
|
+
const valid = new RegExp(EMAIL_DEVICE_ID_PATTERN);
|
|
18
|
+
/** The id of this page when the browser keeps nothing — still one id, not one per request. */
|
|
19
|
+
let ephemeral = null;
|
|
20
|
+
const base64url = (bytes) => {
|
|
21
|
+
let binary = '';
|
|
22
|
+
for (const byte of bytes) {
|
|
23
|
+
binary += String.fromCharCode(byte);
|
|
24
|
+
}
|
|
25
|
+
return btoa(binary).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
|
|
26
|
+
};
|
|
27
|
+
const read = (area, key) => {
|
|
28
|
+
try {
|
|
29
|
+
return area?.getItem(key) ?? null;
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
const write = (area, key, value) => {
|
|
36
|
+
if (area == null) {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
try {
|
|
40
|
+
if (value == null) {
|
|
41
|
+
area.removeItem(key);
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
area.setItem(key, value);
|
|
45
|
+
}
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
const deviceId = () => {
|
|
53
|
+
const area = local();
|
|
54
|
+
const stored = read(area, EMAIL_DEVICE_STORAGE);
|
|
55
|
+
if (stored != null && valid.test(stored)) {
|
|
56
|
+
return stored;
|
|
57
|
+
}
|
|
58
|
+
if (ephemeral != null) {
|
|
59
|
+
return ephemeral;
|
|
60
|
+
}
|
|
61
|
+
const created = base64url(random(EMAIL_DEVICE_ID_BYTES));
|
|
62
|
+
if (!write(area, EMAIL_DEVICE_STORAGE, created)) {
|
|
63
|
+
ephemeral = created;
|
|
64
|
+
}
|
|
65
|
+
return created;
|
|
66
|
+
};
|
|
67
|
+
const offer = (owner) => {
|
|
68
|
+
const raw = read(session(), EMAIL_OFFER_STORAGE);
|
|
69
|
+
if (raw == null) {
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
let stored = null;
|
|
73
|
+
try {
|
|
74
|
+
stored = JSON.parse(raw);
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
if (typeof stored?.ticket !== 'string' || stored.ticket === ''
|
|
80
|
+
|| typeof stored.expiresAt !== 'number' || stored.expiresAt <= now()) {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
if (owner != null && stored.owner != null && stored.owner !== owner) {
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
return stored.ticket;
|
|
87
|
+
};
|
|
88
|
+
const keepOffer = (ticket, owner) => {
|
|
89
|
+
const stored = {
|
|
90
|
+
ticket, ...(owner != null ? { owner } : {}), expiresAt: now() + EMAIL_OFFER_TTL_SECONDS * 1000,
|
|
91
|
+
};
|
|
92
|
+
write(session(), EMAIL_OFFER_STORAGE, JSON.stringify(stored));
|
|
93
|
+
};
|
|
94
|
+
const dropOffer = () => {
|
|
95
|
+
write(session(), EMAIL_OFFER_STORAGE, null);
|
|
96
|
+
};
|
|
97
|
+
return { deviceId, offer, keepOffer, dropOffer };
|
|
98
|
+
};
|
|
99
|
+
export const emailStorageHelper = createEmailStorageHelper();
|
|
100
|
+
//# sourceMappingURL=storage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.js","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"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"}
|
package/build/types.d.ts
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import type { ComponentType } from 'react';
|
|
2
|
+
import type { LazyService } from '@owlmeans/context';
|
|
3
|
+
import type { ClientConfig, ClientContext } from '@owlmeans/client-context';
|
|
4
|
+
import type { AuthMethodMeta } from '@owlmeans/client-auth/manager/plugins';
|
|
5
|
+
import type { LoginScreenProps } from '@owlmeans/client-auth/login';
|
|
6
|
+
import type { EmailAuthEntrypoints, EmailAuthOptionsView, EmailChallengeView, EmailPasswordPinRequest, EmailPasswordRemoveRequest, EmailPasswordSetRequest, EmailPasswordStatusView, EmailPinRequest, EmailSignInRequest, EmailSignInView } from '@owlmeans/auth-email';
|
|
7
|
+
/**
|
|
8
|
+
* `(key, defaultValue) => string` — this package's own translator, or an application's.
|
|
9
|
+
*
|
|
10
|
+
* Keys are this package's (`login.title`, `error.code`, …, resource `auth-email`); the default is
|
|
11
|
+
* the English text. Placeholders such as `{{email}}` are filled by the component, so a translator
|
|
12
|
+
* returns the sentence as it is.
|
|
13
|
+
*/
|
|
14
|
+
export interface Translate {
|
|
15
|
+
(key: string, defaultValue: string): string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* How an application dresses the e-mail sign-in card — the same props the chooser card
|
|
19
|
+
* (`@owlmeans/web-panel`'s `LoginScreen`) takes for the same purpose.
|
|
20
|
+
*/
|
|
21
|
+
export interface EmailLoginScreenSetup extends Pick<LoginScreenProps, 'Logo' | 'title' | 'subtitle' | 'footer' | 'className' | 'containerClassName' | 'style' | 'locale' | 'translate'> {
|
|
22
|
+
}
|
|
23
|
+
export interface EmailLoginScreenProps extends EmailLoginScreenSetup {
|
|
24
|
+
}
|
|
25
|
+
export type EmailLoginScreenComponent = ComponentType<EmailLoginScreenProps>;
|
|
26
|
+
export interface EmailLoginAppendOptions {
|
|
27
|
+
/**
|
|
28
|
+
* From `makeEmailAuthProtocols(...)` — the tree the application also binds with `bindAll` (the
|
|
29
|
+
* API routes) and `emailAuthEntrypoints` (the offer screen).
|
|
30
|
+
*/
|
|
31
|
+
protocols: EmailAuthEntrypoints;
|
|
32
|
+
/** Logo, copy and classes of the e-mail card; merged under the props a host passes itself. */
|
|
33
|
+
screen?: EmailLoginScreenSetup;
|
|
34
|
+
/**
|
|
35
|
+
* How the method presents itself on the chooser, merged over `EMAIL_LOGIN_METHOD_META`.
|
|
36
|
+
* `available` is always this package's own (the client service is registered).
|
|
37
|
+
*/
|
|
38
|
+
method?: Partial<AuthMethodMeta>;
|
|
39
|
+
/** Register the post-sign-in "set a password" step. Default `true`. */
|
|
40
|
+
offer?: boolean;
|
|
41
|
+
}
|
|
42
|
+
export type EmailLoginClientContext = ClientContext<ClientConfig>;
|
|
43
|
+
/**
|
|
44
|
+
* The browser side of e-mail sign-in, registered as `EMAIL_LOGIN_SERVICE` by `appendEmailLogin`.
|
|
45
|
+
*
|
|
46
|
+
* A thin transport over the protocol tree: every call rejects with the error its route answered,
|
|
47
|
+
* and the caller phrases it (`emailRefusalHelper`). Nothing here swallows a failure.
|
|
48
|
+
*/
|
|
49
|
+
export interface EmailLoginClientService extends LazyService {
|
|
50
|
+
/** The protocol tree the service calls. */
|
|
51
|
+
protocols: () => EmailAuthEntrypoints;
|
|
52
|
+
/** `GET options`, cached after the first success; `fresh` asks again. */
|
|
53
|
+
options: (opts?: {
|
|
54
|
+
fresh?: boolean;
|
|
55
|
+
}) => Promise<EmailAuthOptionsView>;
|
|
56
|
+
/** `POST pin` — mail a sign-in PIN. */
|
|
57
|
+
sendPin: (request: EmailPinRequest) => Promise<EmailChallengeView>;
|
|
58
|
+
/** `POST sign-in` — PIN mode or password mode. */
|
|
59
|
+
signIn: (request: EmailSignInRequest) => Promise<EmailSignInView>;
|
|
60
|
+
/**
|
|
61
|
+
* Finish a signed-in answer the way every self-contained plugin does: adopt the token through the
|
|
62
|
+
* client auth service, keep the offer ticket (when one came) for the offer step, then land with
|
|
63
|
+
* `loginLandingOf(ctx).landAfterLogin()` — a pending step, a parked target, else home; inside a
|
|
64
|
+
* surrogate window the dispatcher, which hands the session to the opener.
|
|
65
|
+
*
|
|
66
|
+
* @throws when the answer carries no token, or the token is refused.
|
|
67
|
+
*/
|
|
68
|
+
complete: (view: EmailSignInView) => Promise<void>;
|
|
69
|
+
/** `GET password` — the signed-in account's password state. */
|
|
70
|
+
passwordStatus: () => Promise<EmailPasswordStatusView>;
|
|
71
|
+
/** `POST password/pin` — mail a confirmation PIN to the account's own address. */
|
|
72
|
+
passwordPin: (request: EmailPasswordPinRequest) => Promise<EmailChallengeView>;
|
|
73
|
+
/** `POST password/set`. */
|
|
74
|
+
setPassword: (request: EmailPasswordSetRequest) => Promise<EmailPasswordStatusView>;
|
|
75
|
+
/** `POST password/remove`. */
|
|
76
|
+
removePassword: (request: EmailPasswordRemoveRequest) => Promise<EmailPasswordStatusView>;
|
|
77
|
+
/** `POST password/decline` — "Not now" on the offer. */
|
|
78
|
+
declinePassword: () => Promise<EmailPasswordStatusView>;
|
|
79
|
+
/** The screen the e-mail route renders; null = the package's own. */
|
|
80
|
+
screen: () => EmailLoginScreenComponent | null;
|
|
81
|
+
/** Replace the screen the e-mail route renders (`registerEmailLoginScreen`). */
|
|
82
|
+
registerScreen: (screen: EmailLoginScreenComponent) => void;
|
|
83
|
+
}
|
|
84
|
+
export interface MakeEmailLoginClientOptions {
|
|
85
|
+
alias?: string;
|
|
86
|
+
/** The screen the e-mail route renders until another is registered. */
|
|
87
|
+
screen?: EmailLoginScreenComponent;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* The entrypoint aliases `usePassword` addresses.
|
|
91
|
+
*
|
|
92
|
+
* By default those of the tree given to `appendEmailLogin`, else the `EMAIL_AUTH_PASSWORD_*` aliases
|
|
93
|
+
* `makeEmailAuthProtocols` declares — an application that mounted the password routes under its own
|
|
94
|
+
* aliases (a facade in front of them, say) passes its own here.
|
|
95
|
+
*/
|
|
96
|
+
export interface EmailPasswordAliases {
|
|
97
|
+
status: string;
|
|
98
|
+
pin: string;
|
|
99
|
+
set: string;
|
|
100
|
+
remove: string;
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=types.d.ts.map
|