@webda/auth 0.0.0-stage → 4.0.0-beta.10
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/LICENSE +166 -0
- package/README.md +59 -2
- package/lib/authentication.service.d.ts +322 -0
- package/lib/authentication.service.d.ts.map +1 -0
- package/lib/authentication.service.js +978 -0
- package/lib/authentication.service.js.map +1 -0
- package/lib/certificate/certificate.service.d.ts +139 -0
- package/lib/certificate/certificate.service.d.ts.map +1 -0
- package/lib/certificate/certificate.service.js +343 -0
- package/lib/certificate/certificate.service.js.map +1 -0
- package/lib/compat/upgrade.d.ts +71 -0
- package/lib/compat/upgrade.d.ts.map +1 -0
- package/lib/compat/upgrade.js +200 -0
- package/lib/compat/upgrade.js.map +1 -0
- package/lib/email/emailpassword.service.d.ts +249 -0
- package/lib/email/emailpassword.service.d.ts.map +1 -0
- package/lib/email/emailpassword.service.js +714 -0
- package/lib/email/emailpassword.service.js.map +1 -0
- package/lib/email/tokens.d.ts +36 -0
- package/lib/email/tokens.d.ts.map +1 -0
- package/lib/email/tokens.js +46 -0
- package/lib/email/tokens.js.map +1 -0
- package/lib/errors.d.ts +53 -0
- package/lib/errors.d.ts.map +1 -0
- package/lib/errors.js +74 -0
- package/lib/errors.js.map +1 -0
- package/lib/index.d.ts +12 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +12 -0
- package/lib/index.js.map +1 -0
- package/lib/mfa/secondfactor.service.d.ts +44 -0
- package/lib/mfa/secondfactor.service.d.ts.map +1 -0
- package/lib/mfa/secondfactor.service.js +38 -0
- package/lib/mfa/secondfactor.service.js.map +1 -0
- package/lib/mfa/totp.service.d.ts +41 -0
- package/lib/mfa/totp.service.d.ts.map +1 -0
- package/lib/mfa/totp.service.js +63 -0
- package/lib/mfa/totp.service.js.map +1 -0
- package/lib/oauth/oauth.service.d.ts +296 -0
- package/lib/oauth/oauth.service.d.ts.map +1 -0
- package/lib/oauth/oauth.service.js +560 -0
- package/lib/oauth/oauth.service.js.map +1 -0
- package/lib/provider.d.ts +53 -0
- package/lib/provider.d.ts.map +1 -0
- package/lib/provider.js +55 -0
- package/lib/provider.js.map +1 -0
- package/lib/test/authtest.d.ts +39 -0
- package/lib/test/authtest.d.ts.map +1 -0
- package/lib/test/authtest.js +62 -0
- package/lib/test/authtest.js.map +1 -0
- package/lib/test/emailtest.d.ts +25 -0
- package/lib/test/emailtest.d.ts.map +1 -0
- package/lib/test/emailtest.js +42 -0
- package/lib/test/emailtest.js.map +1 -0
- package/lib/test/fakeoauth.service.d.ts +45 -0
- package/lib/test/fakeoauth.service.d.ts.map +1 -0
- package/lib/test/fakeoauth.service.js +78 -0
- package/lib/test/fakeoauth.service.js.map +1 -0
- package/lib/test/mfauser.fixture.model.d.ts +11 -0
- package/lib/test/mfauser.fixture.model.d.ts.map +1 -0
- package/lib/test/mfauser.fixture.model.js +44 -0
- package/lib/test/mfauser.fixture.model.js.map +1 -0
- package/lib/test/stubprovider.d.ts +35 -0
- package/lib/test/stubprovider.d.ts.map +1 -0
- package/lib/test/stubprovider.js +46 -0
- package/lib/test/stubprovider.js.map +1 -0
- package/lib/test/v3.d.ts +29 -0
- package/lib/test/v3.d.ts.map +1 -0
- package/lib/test/v3.js +47 -0
- package/lib/test/v3.js.map +1 -0
- package/lib/throttle.d.ts +41 -0
- package/lib/throttle.d.ts.map +1 -0
- package/lib/throttle.js +49 -0
- package/lib/throttle.js.map +1 -0
- package/package.json +69 -3
- package/test/config.json +23 -0
- package/webda.module.json +891 -0
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import { Ident } from "@webda/core";
|
|
2
|
+
import { IdentConflict } from "../errors.js";
|
|
3
|
+
/**
|
|
4
|
+
* v3 ident records
|
|
5
|
+
*
|
|
6
|
+
* v3 stored idents under `"<providerUid>_<provider>"` (plain JSON, `__type: "Webda/Ident"`, `uuid` kept in the
|
|
7
|
+
* body). The core `Ident` repository addresses and queries them through `Ident.parseLegacyUID` (a model-level
|
|
8
|
+
* legacy key hook): they load as `Ident` instances without `providerUid`, recognised by `ident.getLegacyUID()`.
|
|
9
|
+
* Nothing else may use such an instance: it must go through {@link upgradeIdent} first.
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* @param providerUid - uid on the provider
|
|
13
|
+
* @param provider - provider name
|
|
14
|
+
* @returns the v3 key `"<providerUid>_<provider>"`
|
|
15
|
+
*/
|
|
16
|
+
export function legacyKey(providerUid, provider) {
|
|
17
|
+
return `${providerUid}_${provider}`;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Split a v3 key on its LAST "_" (provider names never contain "_", emails may)
|
|
21
|
+
* @param uuid - v3 key
|
|
22
|
+
* @returns the parts, or undefined when not a v3 key
|
|
23
|
+
*/
|
|
24
|
+
export function splitLegacyKey(uuid) {
|
|
25
|
+
return Ident.parseLegacyUID(uuid);
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* @param value - a v3 date (ISO string, timestamp or Date)
|
|
29
|
+
* @returns the date, undefined when absent or unreadable
|
|
30
|
+
*/
|
|
31
|
+
function toDate(value) {
|
|
32
|
+
if (value === undefined || value === null || value === "" || value === false) {
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
const date = value instanceof Date ? value : new Date(value);
|
|
36
|
+
return isNaN(date.getTime()) ? undefined : date;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* @param value - a v3 timestamp (number, ISO string or Date)
|
|
40
|
+
* @returns the timestamp in ms, undefined when absent or unreadable
|
|
41
|
+
*/
|
|
42
|
+
function toTimestamp(value) {
|
|
43
|
+
if (typeof value === "number") {
|
|
44
|
+
return value || undefined;
|
|
45
|
+
}
|
|
46
|
+
return toDate(value)?.getTime();
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Whether a row loaded under a v3 key really is a v3 ident of this application
|
|
50
|
+
*
|
|
51
|
+
* The row must be an instance of the ident model, carry a v3 key and be stored untyped, as `Webda/Ident`, or as
|
|
52
|
+
* the ident model, one of its ancestors or transitive subclasses: a v3-looking key of a shared store may hold
|
|
53
|
+
* another model's row.
|
|
54
|
+
* @param row - the loaded row
|
|
55
|
+
* @param IdentModel - ident model of the application
|
|
56
|
+
* @returns true for a v3 ident
|
|
57
|
+
*/
|
|
58
|
+
export function isLegacyIdent(row, IdentModel = Ident) {
|
|
59
|
+
if (!(row instanceof IdentModel) || !row.getLegacyUID()) {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
const type = row.__type;
|
|
63
|
+
return type === undefined || identIdentifiers(IdentModel).has(type) || rowClassIdentifiers(row).has(type);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Identifiers of the class a row loaded as and of its ancestors: a subclass of the ident model defined by another
|
|
67
|
+
* package (e.g. an application `MyApp/Ident`) is not listed in the ident model `Metadata.Subclasses`, yet a row
|
|
68
|
+
* typed as it loads as it
|
|
69
|
+
* @param row - the loaded row, an instance of the ident model
|
|
70
|
+
* @returns the identifiers
|
|
71
|
+
*/
|
|
72
|
+
function rowClassIdentifiers(row) {
|
|
73
|
+
const ids = new Set();
|
|
74
|
+
for (let clazz = row?.constructor; clazz && clazz !== Function.prototype; clazz = Object.getPrototypeOf(clazz)) {
|
|
75
|
+
if (clazz.Metadata?.Identifier)
|
|
76
|
+
ids.add(clazz.Metadata.Identifier);
|
|
77
|
+
}
|
|
78
|
+
return ids;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Identifiers a v3 ident row of this ident model may be stored as: `Webda/Ident`, the model, its ancestors and
|
|
82
|
+
* its transitive subclasses
|
|
83
|
+
* @param IdentModel - ident model of the application
|
|
84
|
+
* @returns the identifiers
|
|
85
|
+
*/
|
|
86
|
+
function identIdentifiers(IdentModel) {
|
|
87
|
+
const ids = new Set(["Webda/Ident"]);
|
|
88
|
+
for (let parent = Object.getPrototypeOf(IdentModel); parent && parent !== Function.prototype;) {
|
|
89
|
+
if (parent.Metadata?.Identifier)
|
|
90
|
+
ids.add(parent.Metadata.Identifier);
|
|
91
|
+
parent = Object.getPrototypeOf(parent);
|
|
92
|
+
}
|
|
93
|
+
const queue = [IdentModel];
|
|
94
|
+
const seen = new Set();
|
|
95
|
+
while (queue.length) {
|
|
96
|
+
const clazz = queue.shift();
|
|
97
|
+
if (!clazz || seen.has(clazz))
|
|
98
|
+
continue;
|
|
99
|
+
seen.add(clazz);
|
|
100
|
+
if (clazz.Metadata?.Identifier)
|
|
101
|
+
ids.add(clazz.Metadata.Identifier);
|
|
102
|
+
queue.push(...(clazz.Metadata?.Subclasses ?? []));
|
|
103
|
+
}
|
|
104
|
+
return ids;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Upgrade a v3 ident: create the `"<providerUid>:<provider>"` record, then delete the v3 one
|
|
108
|
+
*
|
|
109
|
+
* Idempotent and crash-safe: when the new record already exists (an earlier upgrade stopped before the delete,
|
|
110
|
+
* or a concurrent one won) it is kept as is and only the v3 record is deleted. Field map: `_user` → owner,
|
|
111
|
+
* `_validation` → `verifiedAt`, `_lastUsed` → `lastUsedAt`, `_failedLogin` → `_loginAttempts`,
|
|
112
|
+
* `_lastFailedLogin` → `_lastLoginAttemptAt` (number or date; absent, the count is treated as an expired lock),
|
|
113
|
+
* `_lastValidationEmail` → `_throttle.lastSentAt`; `email`, `__profile` are kept, `__tokens` is encrypted into `tokens`; provider is
|
|
114
|
+
* `provider ?? _type ?? key suffix`, providerUid the key prefix (normalised for the email provider: v3 kept the
|
|
115
|
+
* email case). Callers run it as system.
|
|
116
|
+
* @throws Error when `legacy` is not a v3 ident (see {@link isLegacyIdent})
|
|
117
|
+
* @throws IdentConflict when the upgraded key exists, or is created concurrently, with another owner: the v3
|
|
118
|
+
* record is kept for a manual resolution
|
|
119
|
+
* @param legacy - a v3 ident (`legacy.getLegacyUID()` is set)
|
|
120
|
+
* @param IdentModel - ident model of the application
|
|
121
|
+
* @param options - options
|
|
122
|
+
* @param options.dryRun - run the checks only: nothing is written, the returned ident is not saved
|
|
123
|
+
* @returns the upgraded ident
|
|
124
|
+
*/
|
|
125
|
+
export async function upgradeIdent(legacy, IdentModel = Ident, options = {}) {
|
|
126
|
+
const uid = isLegacyIdent(legacy, IdentModel) ? legacy.getLegacyUID() : undefined;
|
|
127
|
+
const parts = uid ? splitLegacyKey(uid) : undefined;
|
|
128
|
+
if (!parts) {
|
|
129
|
+
throw new Error("Not a v3 ident");
|
|
130
|
+
}
|
|
131
|
+
const v3 = legacy;
|
|
132
|
+
const provider = v3.provider ?? v3._type ?? parts.provider;
|
|
133
|
+
// v3 did not normalise emails: an email key is upgraded under its normalised (lowercase) form
|
|
134
|
+
const providerUid = provider === "email" ? Ident.normalizeEmail(parts.providerUid) : parts.providerUid;
|
|
135
|
+
const key = Ident.key(providerUid, provider);
|
|
136
|
+
const ref = IdentModel.ref(key);
|
|
137
|
+
const owner = v3._user?.toString();
|
|
138
|
+
// Another account may already hold the upgraded key (e.g. two v3 keys differing only by case)
|
|
139
|
+
const checkOwner = (existing) => {
|
|
140
|
+
if (existing.getUser()?.toString() !== owner)
|
|
141
|
+
throw new IdentConflict();
|
|
142
|
+
return existing;
|
|
143
|
+
};
|
|
144
|
+
let ident = (await ref.exists()) ? checkOwner(await ref.get()) : undefined;
|
|
145
|
+
if (!ident) {
|
|
146
|
+
const created = new IdentModel({
|
|
147
|
+
...key,
|
|
148
|
+
email: v3.email ?? (provider === "email" ? providerUid : undefined),
|
|
149
|
+
verifiedAt: v3._validation ? (toDate(v3._validation) ?? new Date()) : undefined,
|
|
150
|
+
lastUsedAt: toDate(v3._lastUsed),
|
|
151
|
+
_throttle: { lastSentAt: toTimestamp(v3._lastValidationEmail) },
|
|
152
|
+
_loginAttempts: typeof v3._failedLogin === "number" ? v3._failedLogin : 0,
|
|
153
|
+
_lastLoginAttemptAt: toTimestamp(v3._lastFailedLogin),
|
|
154
|
+
__profile: v3.__profile
|
|
155
|
+
});
|
|
156
|
+
if (owner) {
|
|
157
|
+
created.setUser(owner);
|
|
158
|
+
}
|
|
159
|
+
// v3 kept plaintext tokens: they are only stored encrypted
|
|
160
|
+
if (v3.__tokens && !options.dryRun) {
|
|
161
|
+
await created.tokens.set(v3.__tokens);
|
|
162
|
+
}
|
|
163
|
+
if (options.dryRun) {
|
|
164
|
+
return created;
|
|
165
|
+
}
|
|
166
|
+
try {
|
|
167
|
+
ident = await created.getRepository().create(created);
|
|
168
|
+
}
|
|
169
|
+
catch (err) {
|
|
170
|
+
// Store-agnostic lost race: the record now exists, whatever error the store reported
|
|
171
|
+
if (!(await ref.exists()))
|
|
172
|
+
throw err;
|
|
173
|
+
// The race may have been won by another v3 record of another user: never delete this one then
|
|
174
|
+
ident = checkOwner(await ref.get());
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
if (!options.dryRun) {
|
|
178
|
+
await IdentModel.ref(uid).delete();
|
|
179
|
+
}
|
|
180
|
+
return ident;
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Enumerate the v3 idents of a store, for a batch migration (`webda auth migrate`)
|
|
184
|
+
*
|
|
185
|
+
* Iterates the ident model (all idents, the v3 ones are filtered client side: they lack `providerUid`, which
|
|
186
|
+
* stores cannot portably query for) and yields only the v3 records. Pass each to {@link upgradeIdent}.
|
|
187
|
+
* Upgrading deletes records, which shifts offset-based pagination (memory and file stores page by position):
|
|
188
|
+
* a migration upgrading while iterating must run passes until one yields nothing (upgrades are idempotent).
|
|
189
|
+
* @param IdentModel - ident model of the application
|
|
190
|
+
* @param query - optional WebdaQL filter, e.g. `"_user = 'uid'"`
|
|
191
|
+
* @returns the v3 idents
|
|
192
|
+
*/
|
|
193
|
+
export async function* legacyIdents(IdentModel = Ident, query = "") {
|
|
194
|
+
for await (const ident of IdentModel.iterate(query)) {
|
|
195
|
+
if (ident.getLegacyUID()) {
|
|
196
|
+
yield ident;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
//# sourceMappingURL=upgrade.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"upgrade.js","sourceRoot":"","sources":["../../src/compat/upgrade.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
import { type AuthResult, Ident, type ProviderInfo, Service, ServiceParameters, type WebContext } from "@webda/core";
|
|
2
|
+
import type { AuthProvider } from "../provider.js";
|
|
3
|
+
/** When the email is verified relative to account creation */
|
|
4
|
+
export type VerificationMode = "before" | "after" | "none";
|
|
5
|
+
/** EmailPasswordProvider parameters */
|
|
6
|
+
export declare class EmailPasswordParameters extends ServiceParameters {
|
|
7
|
+
/**
|
|
8
|
+
* Mailer service name
|
|
9
|
+
* @default "Mailer"
|
|
10
|
+
*/
|
|
11
|
+
mailer: string;
|
|
12
|
+
/**
|
|
13
|
+
* Verification mode
|
|
14
|
+
* @default "before"
|
|
15
|
+
*/
|
|
16
|
+
verification: VerificationMode;
|
|
17
|
+
/** Password rules
|
|
18
|
+
* @default { "policy": ".{8,}" }
|
|
19
|
+
*/
|
|
20
|
+
password: {
|
|
21
|
+
/** @default ".{8,}" */
|
|
22
|
+
policy: string;
|
|
23
|
+
verifier?: string;
|
|
24
|
+
};
|
|
25
|
+
/** Throttling
|
|
26
|
+
* @default { "resendDelay": 14400000, "failedBeforeDelay": 3, "lockout": 900000 }
|
|
27
|
+
*/
|
|
28
|
+
throttle: {
|
|
29
|
+
/** @default 14400000 */
|
|
30
|
+
resendDelay: number;
|
|
31
|
+
/** @default 3 */
|
|
32
|
+
failedBeforeDelay: number;
|
|
33
|
+
/** @default 900000 */
|
|
34
|
+
lockout: number;
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Browser redirects for emailed links (no defaults: init() refuses a missing required one). `failure` and `recover`
|
|
38
|
+
* are always required, `verified` and `register` unless `verification` is "none". `recover` receives the recovery
|
|
39
|
+
* link as `?token=...` (the page then calls Auth.Password.Recover). `confirm` (default `failure`) receives a
|
|
40
|
+
* verification link opened without the matching session, with `?reason=LOGIN_REQUIRED&token=...`: log in then call
|
|
41
|
+
* Auth.Email.Verify with the token
|
|
42
|
+
*/
|
|
43
|
+
redirects: {
|
|
44
|
+
verified?: string;
|
|
45
|
+
failure?: string;
|
|
46
|
+
register?: string;
|
|
47
|
+
confirm?: string;
|
|
48
|
+
recover?: string;
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* Base url for emailed links
|
|
52
|
+
* @default "/auth/email"
|
|
53
|
+
*/
|
|
54
|
+
url: string;
|
|
55
|
+
/** Only these email domains may use this provider (see ProviderEmailPolicy) */
|
|
56
|
+
allowedEmailDomains?: string[];
|
|
57
|
+
/** Whether the verification of the email is believed (see ProviderEmailPolicy) */
|
|
58
|
+
trustEmailVerification?: boolean | string[];
|
|
59
|
+
/**
|
|
60
|
+
* @param params - raw parameters
|
|
61
|
+
* @returns this
|
|
62
|
+
*/
|
|
63
|
+
load(params?: any): this;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Email + password login method
|
|
67
|
+
*
|
|
68
|
+
* The password policy is process-wide: resolve() registers the one of this provider and stop() restores the
|
|
69
|
+
* default. With several instances the last one resolved wins.
|
|
70
|
+
*
|
|
71
|
+
* Known residual exposure: Auth.Email.Register answers AccountExists for a registered email (enumeration), and
|
|
72
|
+
* login timing differs slightly for known emails. An unverified squatter owning an email blocks its registration
|
|
73
|
+
* until the real owner goes through account recovery.
|
|
74
|
+
*
|
|
75
|
+
* Under `allowedEmailDomains` an email must be verified: with `verification` "after" or "none" a new registration is
|
|
76
|
+
* unverified and therefore refused (EMAIL_DOMAIN_NOT_ALLOWED); use "before".
|
|
77
|
+
* @WebdaModda EmailPasswordProvider
|
|
78
|
+
*/
|
|
79
|
+
export declare class EmailPasswordProvider<T extends EmailPasswordParameters = EmailPasswordParameters> extends Service<T> implements AuthProvider {
|
|
80
|
+
static Parameters: typeof EmailPasswordParameters;
|
|
81
|
+
readonly providerName = "email";
|
|
82
|
+
/** @override */
|
|
83
|
+
resolve(): this;
|
|
84
|
+
/** @override */
|
|
85
|
+
init(): Promise<this>;
|
|
86
|
+
/** @override */
|
|
87
|
+
stop(): Promise<void>;
|
|
88
|
+
/**
|
|
89
|
+
* @returns public info
|
|
90
|
+
*/
|
|
91
|
+
getPublicInfo(): ProviderInfo;
|
|
92
|
+
/**
|
|
93
|
+
* @param email - normalised email
|
|
94
|
+
* @returns the email ident
|
|
95
|
+
*/
|
|
96
|
+
protected getIdent(email: string): Promise<Ident | undefined>;
|
|
97
|
+
/**
|
|
98
|
+
* Absolute link for an emailed token
|
|
99
|
+
* @param path - path under the provider url
|
|
100
|
+
* @param token - token
|
|
101
|
+
* @returns url
|
|
102
|
+
*/
|
|
103
|
+
buildLink(path: string, token: string): string;
|
|
104
|
+
/**
|
|
105
|
+
* @param template - mail template
|
|
106
|
+
* @param to - recipient
|
|
107
|
+
* @param url - link
|
|
108
|
+
* @param token - token
|
|
109
|
+
*/
|
|
110
|
+
protected sendMail(template: "EMAIL_REGISTER" | "EMAIL_RECOVERY", to: string, url: string, token: string): Promise<void>;
|
|
111
|
+
/**
|
|
112
|
+
* Count a login attempt before verifying it and decide whether the ident is locked
|
|
113
|
+
*
|
|
114
|
+
* Rule, equivalent to `isLocked(ident, failedBeforeDelay, lockout)` on the state before this attempt:
|
|
115
|
+
* `_loginAttempts` is incremented first (atomically; the new value is returned by the memory repository and
|
|
116
|
+
* re-read otherwise), so this attempt is locked when the count of PREVIOUS attempts (`_loginAttempts - 1`) is at
|
|
117
|
+
* least `failedBeforeDelay`, unless that lock has expired, ie `_lastLoginAttemptAt` as read when this call started
|
|
118
|
+
* is older than `lockout`. `_lastLoginAttemptAt` is only refreshed by attempts that are not refused, so hammering
|
|
119
|
+
* a locked ident does not extend the lock; a count reaching the threshold without timestamp is an expired lock.
|
|
120
|
+
* Both are top-level attributes: stores implement atomic increment and
|
|
121
|
+
* single attribute set on them (nested-path atomic operations are not portable across stores). The timestamp
|
|
122
|
+
* is a plain set (last writer wins); the counter is never written back from a snapshot. A burst starting exactly
|
|
123
|
+
* when an expired lock is read is verified as a whole: it is bounded to one burst per lock window.
|
|
124
|
+
* @param ident - the ident
|
|
125
|
+
* @returns true when this attempt must be refused without checking the password
|
|
126
|
+
*/
|
|
127
|
+
protected countAttempt(ident: Ident): Promise<boolean>;
|
|
128
|
+
/**
|
|
129
|
+
* Login with email and password
|
|
130
|
+
* @param email - email
|
|
131
|
+
* @param password - password
|
|
132
|
+
* @returns the auth result
|
|
133
|
+
*/
|
|
134
|
+
login(email: string, password: string): Promise<AuthResult>;
|
|
135
|
+
/**
|
|
136
|
+
* Register with email and password
|
|
137
|
+
* @param email - email
|
|
138
|
+
* @param password - password
|
|
139
|
+
* @param token - register token from the emailed link (verification "before")
|
|
140
|
+
* @param profile - extra user fields
|
|
141
|
+
* @returns the auth result, or verification_sent
|
|
142
|
+
*/
|
|
143
|
+
register(email: string, password: string, token?: string, profile?: any): Promise<any>;
|
|
144
|
+
/**
|
|
145
|
+
* Send (or resend) a verification link
|
|
146
|
+
*
|
|
147
|
+
* Logged in: the link proves the email for the current account (`sub` is only in the token, the ident stays
|
|
148
|
+
* unowned until Auth.Email.Verify is called by the same session). Logged out: always answers with no content and
|
|
149
|
+
* never reveals anything; a link is only sent for an unowned or unknown email.
|
|
150
|
+
* @param email - email
|
|
151
|
+
*/
|
|
152
|
+
startVerification(email: string): Promise<void>;
|
|
153
|
+
/**
|
|
154
|
+
* Logged-out link: a register link is emailed, without awaiting the mail, only for an unknown or unowned and
|
|
155
|
+
* unverified email whose send throttle allows it; anything else is silently ignored
|
|
156
|
+
* @param normalized - normalised email
|
|
157
|
+
*/
|
|
158
|
+
protected sendUnownedLink(normalized: string): Promise<void>;
|
|
159
|
+
/**
|
|
160
|
+
* Check and mark the send throttle of an email ident, then sign the token to email; runs as system
|
|
161
|
+
* @param normalized - normalised email
|
|
162
|
+
* @param userId - logged user (verify token), undefined for a logged-out register token
|
|
163
|
+
* @returns the token to send, undefined when nothing must be sent (logged out only)
|
|
164
|
+
* @throws IdentLinkedElsewhere / PreconditionFailed / Throttled (logged in only)
|
|
165
|
+
*/
|
|
166
|
+
protected prepareLink(normalized: string, userId: string | undefined): Promise<string | undefined>;
|
|
167
|
+
/**
|
|
168
|
+
* Send a mail without awaiting it; failures are logged without any secret
|
|
169
|
+
* @param template - mail template
|
|
170
|
+
* @param to - recipient
|
|
171
|
+
* @param url - link
|
|
172
|
+
* @param token - token
|
|
173
|
+
*/
|
|
174
|
+
protected sendMailDetached(template: "EMAIL_REGISTER" | "EMAIL_RECOVERY", to: string, url: string, token: string): void;
|
|
175
|
+
/** Mails sent without being awaited */
|
|
176
|
+
protected pendingMails: Set<Promise<void>>;
|
|
177
|
+
/**
|
|
178
|
+
* Wait for the mails sent without being awaited (logged out verification, recovery)
|
|
179
|
+
*/
|
|
180
|
+
flushMails(): Promise<void>;
|
|
181
|
+
/**
|
|
182
|
+
* Mark an email as verified: only the session of the user named by the token can complete it
|
|
183
|
+
* @param token - verify token
|
|
184
|
+
* @returns status
|
|
185
|
+
*/
|
|
186
|
+
verify(token: string): Promise<{
|
|
187
|
+
status: "verified";
|
|
188
|
+
}>;
|
|
189
|
+
/**
|
|
190
|
+
* Verify with an explicit context
|
|
191
|
+
* @param token - verify token
|
|
192
|
+
* @param ctx - context whose session must match the token
|
|
193
|
+
* @returns status
|
|
194
|
+
*/
|
|
195
|
+
protected verifyWith(token: string, ctx: any): Promise<{
|
|
196
|
+
status: "verified";
|
|
197
|
+
}>;
|
|
198
|
+
/**
|
|
199
|
+
* @param claims - verified token claims
|
|
200
|
+
* @param claims.sub - user id
|
|
201
|
+
* @param ctx - context
|
|
202
|
+
* @returns true when the session is logged as the user of the token
|
|
203
|
+
*/
|
|
204
|
+
protected sessionMatches(claims: {
|
|
205
|
+
sub?: string;
|
|
206
|
+
}, ctx: any): boolean;
|
|
207
|
+
/**
|
|
208
|
+
* Complete a verification; nothing changes unless every check passes
|
|
209
|
+
* @param claims - verified token claims
|
|
210
|
+
* @param claims.email - email of the token
|
|
211
|
+
* @param claims.sub - user id
|
|
212
|
+
* @param ctx - context
|
|
213
|
+
*/
|
|
214
|
+
protected completeVerify(claims: {
|
|
215
|
+
email: string;
|
|
216
|
+
sub?: string;
|
|
217
|
+
}, ctx: any): Promise<void>;
|
|
218
|
+
/**
|
|
219
|
+
* Start password recovery; always succeeds to avoid revealing accounts
|
|
220
|
+
* @param email - email
|
|
221
|
+
*/
|
|
222
|
+
startRecovery(email: string): Promise<void>;
|
|
223
|
+
/**
|
|
224
|
+
* Set a new password from a recovery link (does not log in): revokes the refresh tokens and ends every session of
|
|
225
|
+
* the user (see `Session.authAt`), resets the login attempts of the email ident
|
|
226
|
+
* @param token - recover token
|
|
227
|
+
* @param password - new password
|
|
228
|
+
*/
|
|
229
|
+
recover(token: string, password: string): Promise<void>;
|
|
230
|
+
/**
|
|
231
|
+
* Change the current user's password: revokes the refresh tokens and ends the other sessions of the user, the
|
|
232
|
+
* calling cookie session is re-stamped and stays logged in
|
|
233
|
+
* @param current - current password
|
|
234
|
+
* @param next - new password
|
|
235
|
+
*/
|
|
236
|
+
changePassword(current: string, next: string): Promise<void>;
|
|
237
|
+
/**
|
|
238
|
+
* Browser landing for recovery links: redirects a valid recover token to `redirects.recover` without consuming it,
|
|
239
|
+
* anything else to `redirects.failure`; never throws
|
|
240
|
+
* @param ctx - web context
|
|
241
|
+
*/
|
|
242
|
+
recoverRedirect(ctx: WebContext): Promise<void>;
|
|
243
|
+
/**
|
|
244
|
+
* Browser landing for emailed links: verifies then redirects, never throws
|
|
245
|
+
* @param ctx - web context
|
|
246
|
+
*/
|
|
247
|
+
verifyRedirect(ctx: WebContext): Promise<void>;
|
|
248
|
+
}
|
|
249
|
+
//# sourceMappingURL=emailpassword.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emailpassword.service.d.ts","sourceRoot":"","sources":["../../src/email/emailpassword.service.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,UAAU,EACf,KAAK,EAKL,KAAK,YAAY,EAGjB,OAAO,EACP,iBAAiB,EAKjB,KAAK,UAAU,EAEhB,MAAM,aAAa,CAAC;AAErB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAMnD,8DAA8D;AAC9D,MAAM,MAAM,gBAAgB,GAAG,QAAQ,GAAG,OAAO,GAAG,MAAM,CAAC;AAE3D,uCAAuC;AACvC,qBAAa,uBAAwB,SAAQ,iBAAiB;IAC5D;;;OAGG;IACH,MAAM,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,YAAY,EAAE,gBAAgB,CAAC;IAC/B;;OAEG;IACH,QAAQ,EAAE;QACR,uBAAuB;QACvB,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,CAAC;IACF;;OAEG;IACH,QAAQ,EAAE;QACR,wBAAwB;QACxB,WAAW,EAAE,MAAM,CAAC;QACpB,iBAAiB;QACjB,iBAAiB,EAAE,MAAM,CAAC;QAC1B,sBAAsB;QACtB,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;IACF;;;;;;OAMG;IACH,SAAS,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC1G;;;OAGG;IACH,GAAG,EAAE,MAAM,CAAC;IACZ,+EAA+E;IAC/E,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC/B,kFAAkF;IAClF,sBAAsB,CAAC,EAAE,OAAO,GAAG,MAAM,EAAE,CAAC;IAE5C;;;OAGG;IACH,IAAI,CAAC,MAAM,GAAE,GAAQ,GAAG,IAAI,CAa3B;CACF;AA0CD;;;;;;;;;;;;;GAaG;AACH,qBAAa,qBAAqB,CAAC,CAAC,SAAS,uBAAuB,GAAG,uBAAuB,CAC5F,SAAQ,OAAO,CAAC,CAAC,CACjB,YAAW,YAAY;IAEvB,MAAM,CAAC,UAAU,iCAA2B;IAE5C,QAAQ,CAAC,YAAY,WAAW;IAEhC,gBAAgB;IAChB,OAAO,IAAI,IAAI,CAUd;IAED,gBAAgB;IACV,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAgB1B;IAED,gBAAgB;IACV,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAG1B;IAED;;OAEG;IACH,aAAa,IAAI,YAAY,CAE5B;IAED;;;OAGG;IACH,UAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,GAAG,SAAS,CAAC,CAElE;IAED;;;;;OAKG;IACH,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAI7C;IAED;;;;;OAKG;IACH,UAAgB,QAAQ,CACtB,QAAQ,EAAE,gBAAgB,GAAG,gBAAgB,EAC7C,EAAE,EAAE,MAAM,EACV,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,IAAI,CAAC,CAQf;IAED;;;;;;;;;;;;;;;OAeG;IACH,UAAgB,YAAY,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,CAE3D;IAED;;;;;OAKG;IAQG,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAqChE;IAED;;;;;;;OAOG;IAQG,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,CA0E3F;IAED;;;;;;;OAOG;IAMG,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAWpD;IAED;;;;OAIG;IACH,UAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAKjE;IAED;;;;;;OAMG;IACH,UAAgB,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAmCvG;IAED;;;;;;OAMG;IACH,SAAS,CAAC,gBAAgB,CAAC,QAAQ,EAAE,gBAAgB,GAAG,gBAAgB,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,QAK/G;IAED,uCAAuC;IACvC,SAAS,CAAC,YAAY,qBAA4B;IAElD;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAIhC;IAED;;;;OAIG;IAOG,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,UAAU,CAAA;KAAE,CAAC,CAE3D;IAED;;;;;OAKG;IACH,UAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,UAAU,CAAA;KAAE,CAAC,CAInF;IAED;;;;;OAKG;IACH,SAAS,CAAC,cAAc,CAAC,MAAM,EAAE;QAAE,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,GAAG,EAAE,GAAG,GAAG,OAAO,CAEpE;IAED;;;;;;OAMG;IACH,UAAgB,cAAc,CAAC,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,CAyB/F;IAED;;;OAGG;IAMG,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAmBhD;IAED;;;;;OAKG;IAMG,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAkC5D;IAED;;;;;OAKG;IAMG,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAcjE;IAED;;;;OAIG;IAEG,eAAe,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAWpD;IAED;;;OAGG;IAEG,cAAc,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAsBnD;CACF"}
|