@adonis-agora/authkit-server 0.70.0 → 0.71.0
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/build/commands/commands.json +18 -0
- package/build/commands/import_users.js +1 -6
- package/build/commands/normalize_emails.d.ts +21 -0
- package/build/commands/normalize_emails.js +106 -0
- package/build/index.d.ts +3 -4
- package/build/index.js +2 -2
- package/build/src/accounts/account_store.d.ts +25 -1
- package/build/src/accounts/account_store.js +4 -0
- package/build/src/accounts/lucid_store/core.d.ts +2 -2
- package/build/src/accounts/lucid_store/core.js +16 -0
- package/build/src/commands/import_users.d.ts +0 -7
- package/build/src/commands/import_users.js +5 -12
- package/build/src/commands/normalize_emails.d.ts +78 -0
- package/build/src/commands/normalize_emails.js +129 -0
- package/build/src/define_config.d.ts +0 -16
- package/build/src/define_config.js +0 -1
- package/build/src/host/admin_api/admin_users_service.js +5 -7
- package/build/src/host/controllers/account_session_controller.js +6 -11
- package/build/src/host/controllers/interaction_controller.d.ts +5 -5
- package/build/src/host/controllers/interaction_controller.js +35 -62
- package/build/src/host/controllers/registration_controller.js +11 -27
- package/build/src/host/controllers/social_controller.js +5 -7
- package/build/src/host/email_identifier.d.ts +7 -70
- package/build/src/host/email_identifier.js +7 -210
- package/package.json +1 -1
|
@@ -18,217 +18,14 @@
|
|
|
18
18
|
* Use em TODO ponto que grava ou busca a identidade: cadastro (com e sem senha),
|
|
19
19
|
* "esqueci a senha", troca de e-mail, criação por admin, convite de organização,
|
|
20
20
|
* import de usuários, cadastro social e o passo de identificador do login.
|
|
21
|
+
*
|
|
22
|
+
* As contas GRAVADAS antes disto (com o endereço mutilado, ou com maiúsculas
|
|
23
|
+
* vindas de import/convite/provider social) ficam inalcançáveis pelo login, que
|
|
24
|
+
* busca a forma normalizada. Elas pedem MIGRAÇÃO do endereço gravado — é o que o
|
|
25
|
+
* comando `authkit:users:normalize-emails` faz (ver `commands/normalize_emails.ts`).
|
|
26
|
+
* A lib não tenta adivinhar grafias no caminho do login: cada tentativa extra é
|
|
27
|
+
* uma query a mais por e-mail desconhecido, que é justamente o caminho de ataque.
|
|
21
28
|
*/
|
|
22
29
|
export function normalizeEmailIdentifier(raw) {
|
|
23
30
|
return typeof raw === 'string' ? raw.trim().toLowerCase() : '';
|
|
24
31
|
}
|
|
25
|
-
// ─── Ponte de compatibilidade com a normalização LEGADA ─────────────────────
|
|
26
|
-
/** Domínios do gmail (pontos e sub-endereço eram removidos do local part). */
|
|
27
|
-
const GMAIL_DOMAINS = ['gmail.com', 'googlemail.com'];
|
|
28
|
-
/** Domínios do iCloud (sub-endereço `+tag` removido). */
|
|
29
|
-
const ICLOUD_DOMAINS = ['icloud.com', 'me.com'];
|
|
30
|
-
/** Domínios do Outlook.com/Hotmail/Live (sub-endereço `+tag` removido). */
|
|
31
|
-
const OUTLOOK_DOMAINS = [
|
|
32
|
-
'hotmail.at',
|
|
33
|
-
'hotmail.be',
|
|
34
|
-
'hotmail.ca',
|
|
35
|
-
'hotmail.cl',
|
|
36
|
-
'hotmail.co.il',
|
|
37
|
-
'hotmail.co.nz',
|
|
38
|
-
'hotmail.co.th',
|
|
39
|
-
'hotmail.co.uk',
|
|
40
|
-
'hotmail.com',
|
|
41
|
-
'hotmail.com.ar',
|
|
42
|
-
'hotmail.com.au',
|
|
43
|
-
'hotmail.com.br',
|
|
44
|
-
'hotmail.com.gr',
|
|
45
|
-
'hotmail.com.mx',
|
|
46
|
-
'hotmail.com.pe',
|
|
47
|
-
'hotmail.com.tr',
|
|
48
|
-
'hotmail.com.vn',
|
|
49
|
-
'hotmail.cz',
|
|
50
|
-
'hotmail.de',
|
|
51
|
-
'hotmail.dk',
|
|
52
|
-
'hotmail.es',
|
|
53
|
-
'hotmail.fr',
|
|
54
|
-
'hotmail.hu',
|
|
55
|
-
'hotmail.id',
|
|
56
|
-
'hotmail.ie',
|
|
57
|
-
'hotmail.in',
|
|
58
|
-
'hotmail.it',
|
|
59
|
-
'hotmail.jp',
|
|
60
|
-
'hotmail.kr',
|
|
61
|
-
'hotmail.lv',
|
|
62
|
-
'hotmail.my',
|
|
63
|
-
'hotmail.ph',
|
|
64
|
-
'hotmail.pt',
|
|
65
|
-
'hotmail.sa',
|
|
66
|
-
'hotmail.sg',
|
|
67
|
-
'hotmail.sk',
|
|
68
|
-
'live.be',
|
|
69
|
-
'live.co.uk',
|
|
70
|
-
'live.com',
|
|
71
|
-
'live.com.ar',
|
|
72
|
-
'live.com.mx',
|
|
73
|
-
'live.de',
|
|
74
|
-
'live.es',
|
|
75
|
-
'live.eu',
|
|
76
|
-
'live.fr',
|
|
77
|
-
'live.it',
|
|
78
|
-
'live.nl',
|
|
79
|
-
'msn.com',
|
|
80
|
-
'outlook.at',
|
|
81
|
-
'outlook.be',
|
|
82
|
-
'outlook.cl',
|
|
83
|
-
'outlook.co.il',
|
|
84
|
-
'outlook.co.nz',
|
|
85
|
-
'outlook.co.th',
|
|
86
|
-
'outlook.com',
|
|
87
|
-
'outlook.com.ar',
|
|
88
|
-
'outlook.com.au',
|
|
89
|
-
'outlook.com.br',
|
|
90
|
-
'outlook.com.gr',
|
|
91
|
-
'outlook.com.pe',
|
|
92
|
-
'outlook.com.tr',
|
|
93
|
-
'outlook.com.vn',
|
|
94
|
-
'outlook.cz',
|
|
95
|
-
'outlook.de',
|
|
96
|
-
'outlook.dk',
|
|
97
|
-
'outlook.es',
|
|
98
|
-
'outlook.fr',
|
|
99
|
-
'outlook.hu',
|
|
100
|
-
'outlook.id',
|
|
101
|
-
'outlook.ie',
|
|
102
|
-
'outlook.in',
|
|
103
|
-
'outlook.it',
|
|
104
|
-
'outlook.jp',
|
|
105
|
-
'outlook.kr',
|
|
106
|
-
'outlook.lv',
|
|
107
|
-
'outlook.my',
|
|
108
|
-
'outlook.ph',
|
|
109
|
-
'outlook.pt',
|
|
110
|
-
'outlook.sa',
|
|
111
|
-
'outlook.sg',
|
|
112
|
-
'outlook.sk',
|
|
113
|
-
'passport.com',
|
|
114
|
-
];
|
|
115
|
-
/** Domínios do Yahoo (sub-endereço `-tag` removido). */
|
|
116
|
-
const YAHOO_DOMAINS = [
|
|
117
|
-
'rocketmail.com',
|
|
118
|
-
'yahoo.ca',
|
|
119
|
-
'yahoo.co.uk',
|
|
120
|
-
'yahoo.com',
|
|
121
|
-
'yahoo.de',
|
|
122
|
-
'yahoo.fr',
|
|
123
|
-
'yahoo.in',
|
|
124
|
-
'yahoo.it',
|
|
125
|
-
'ymail.com',
|
|
126
|
-
];
|
|
127
|
-
/** Domínios do Yandex (todos colapsavam em `yandex.ru`). */
|
|
128
|
-
const YANDEX_DOMAINS = ['yandex.ru', 'yandex.ua', 'yandex.kz', 'yandex.com', 'yandex.by', 'ya.ru'];
|
|
129
|
-
/** Remove pontos SOLTOS do local part (pontos consecutivos ficam — regra do validator.js). */
|
|
130
|
-
function stripSingleDots(local) {
|
|
131
|
-
return local.replace(/\.+/g, (match) => (match.length > 1 ? match : ''));
|
|
132
|
-
}
|
|
133
|
-
/**
|
|
134
|
-
* Réplica da normalização LEGADA — `normalizeEmail()` do validator.js com os
|
|
135
|
-
* defaults, que é o que o `.normalizeEmail()` do VineJS aplicava no cadastro até
|
|
136
|
-
* a v0.68. Existe SÓ para reencontrar as contas que nasceram com o endereço
|
|
137
|
-
* mutilado; nada novo deve ser gravado com ela.
|
|
138
|
-
*
|
|
139
|
-
* É uma PONTE TEMPORÁRIA: quando as contas antigas tiverem sido migradas para o
|
|
140
|
-
* endereço real (ou o suficiente delas), esta função, a opção
|
|
141
|
-
* `login.legacyEmailFallback` e {@link resolveEmailIdentifier} podem sair.
|
|
142
|
-
*
|
|
143
|
-
* Retorna `null` para entradas que o validator.js também recusaria (local part
|
|
144
|
-
* vazio depois do colapso) ou que não são um endereço com `@`.
|
|
145
|
-
*/
|
|
146
|
-
export function legacyNormalizeEmailIdentifier(raw) {
|
|
147
|
-
const email = normalizeEmailIdentifier(raw);
|
|
148
|
-
const at = email.lastIndexOf('@');
|
|
149
|
-
if (at <= 0 || at === email.length - 1)
|
|
150
|
-
return null;
|
|
151
|
-
let local = email.slice(0, at);
|
|
152
|
-
let domain = email.slice(at + 1);
|
|
153
|
-
if (GMAIL_DOMAINS.includes(domain)) {
|
|
154
|
-
local = local.split('+')[0];
|
|
155
|
-
local = stripSingleDots(local);
|
|
156
|
-
domain = 'gmail.com';
|
|
157
|
-
}
|
|
158
|
-
else if (ICLOUD_DOMAINS.includes(domain) || OUTLOOK_DOMAINS.includes(domain)) {
|
|
159
|
-
local = local.split('+')[0];
|
|
160
|
-
}
|
|
161
|
-
else if (YAHOO_DOMAINS.includes(domain)) {
|
|
162
|
-
const parts = local.split('-');
|
|
163
|
-
local = parts.length > 1 ? parts.slice(0, -1).join('-') : parts[0];
|
|
164
|
-
}
|
|
165
|
-
else if (YANDEX_DOMAINS.includes(domain)) {
|
|
166
|
-
domain = 'yandex.ru';
|
|
167
|
-
}
|
|
168
|
-
if (!local.length)
|
|
169
|
-
return null;
|
|
170
|
-
return `${local}@${domain}`;
|
|
171
|
-
}
|
|
172
|
-
/**
|
|
173
|
-
* Resolve o e-mail digitado na conta correspondente.
|
|
174
|
-
*
|
|
175
|
-
* Passe o valor **CRU** (como veio do formulário, do provider ou do arquivo): a
|
|
176
|
-
* normalização acontece aqui dentro, e a forma crua é uma das candidatas da
|
|
177
|
-
* ponte. Passar um valor já normalizado apaga essa candidata e reduz o alcance
|
|
178
|
-
* da ponte às contas gravadas com o endereço mutilado.
|
|
179
|
-
*
|
|
180
|
-
* 1. Busca pela forma normalizada NOVA (trim + lowercase) — o caminho de sempre,
|
|
181
|
-
* uma única query por igualdade (indexada).
|
|
182
|
-
* 2. Não achando, e com a ponte ligada (`login.legacyEmailFallback`, default
|
|
183
|
-
* `true`), tenta as formas de compatibilidade:
|
|
184
|
-
* - o endereço EXATAMENTE como digitado (só com `trim`), para as contas que
|
|
185
|
-
* foram gravadas com maiúsculas antes desta normalização existir (import,
|
|
186
|
-
* convite, criação por admin, provider social);
|
|
187
|
-
* - a {@link legacyNormalizeEmailIdentifier normalização legada}, para as
|
|
188
|
-
* contas que nasceram com o endereço mutilado.
|
|
189
|
-
* O resultado só é aceito quando as formas de compatibilidade apontam para
|
|
190
|
-
* EXATAMENTE UMA conta. Duas contas distintas (ex.: `Davi.C@Gmail.com` criada
|
|
191
|
-
* pelo social E `davic@gmail.com` criada pelo cadastro legado) são um empate:
|
|
192
|
-
* a lib não adivinha qual é a pessoa e trata como "não achei".
|
|
193
|
-
*
|
|
194
|
-
* LIMITE CONHECIDO: a ponte só alcança grafias que dá para derivar do que foi
|
|
195
|
-
* digitado. Uma conta gravada `Davi@Acme.com` é alcançada por quem digita
|
|
196
|
-
* `Davi@Acme.com` (a forma crua), mas NÃO por quem digita `davi@acme.com` — aí as
|
|
197
|
-
* três formas coincidem e só uma busca case-insensitive no store resolveria, o
|
|
198
|
-
* que exigiria varrer a tabela a cada login com e-mail desconhecido (justamente o
|
|
199
|
-
* caminho de ataque). Essas contas pedem migração do endereço gravado, não ponte.
|
|
200
|
-
*
|
|
201
|
-
* À PROVA DE ENUMERAÇÃO: nunca lança, nunca sinaliza nada para fora — quem chama
|
|
202
|
-
* segue com `account: null` exatamente como seguia antes. As buscas extras só
|
|
203
|
-
* acontecem quando as formas de compatibilidade DIFEREM da normalizada (e-mail
|
|
204
|
-
* digitado em minúsculas e sem ponto/tag → uma query só, como hoje).
|
|
205
|
-
*/
|
|
206
|
-
export async function resolveEmailIdentifier(store, raw, options = {}) {
|
|
207
|
-
const email = normalizeEmailIdentifier(raw);
|
|
208
|
-
const miss = {
|
|
209
|
-
email,
|
|
210
|
-
lookupEmail: email,
|
|
211
|
-
account: null,
|
|
212
|
-
viaLegacyFallback: false,
|
|
213
|
-
};
|
|
214
|
-
if (!email)
|
|
215
|
-
return miss;
|
|
216
|
-
const direct = await store.findByEmail(email);
|
|
217
|
-
if (direct)
|
|
218
|
-
return { email, lookupEmail: email, account: direct, viaLegacyFallback: false };
|
|
219
|
-
if (options.legacyFallback === false)
|
|
220
|
-
return miss;
|
|
221
|
-
const typed = typeof raw === 'string' ? raw.trim() : '';
|
|
222
|
-
const legacy = legacyNormalizeEmailIdentifier(email);
|
|
223
|
-
const candidates = [typed, legacy].filter((candidate) => !!candidate && candidate !== email);
|
|
224
|
-
const byId = new Map();
|
|
225
|
-
for (const candidate of new Set(candidates)) {
|
|
226
|
-
const found = await store.findByEmail(candidate);
|
|
227
|
-
if (found)
|
|
228
|
-
byId.set(found.id, found);
|
|
229
|
-
}
|
|
230
|
-
if (byId.size !== 1)
|
|
231
|
-
return miss;
|
|
232
|
-
const account = [...byId.values()][0];
|
|
233
|
-
return { email, lookupEmail: account.email, account, viaLegacyFallback: true };
|
|
234
|
-
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adonis-agora/authkit-server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.71.0",
|
|
4
4
|
"description": "AdonisJS OIDC/OAuth2 provider (Identity Provider) toolkit: ejectable auth server with sessions, rate-limiting, MFA/TOTP, audit log, federated logout and OpenTelemetry metrics.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "dudousxd",
|