@adonis-agora/authkit-server 1.0.0-rc.13 → 1.0.0-rc.14
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/CHANGELOG.md +6 -0
- package/build/src/host/account_api/account_api_controller.js +1 -1
- package/build/src/host/account_api/account_orgs_api_controller.js +1 -1
- package/build/src/host/admin_api/admin_orgs_service.js +1 -1
- package/build/src/host/admin_api/admin_users_service.js +1 -1
- package/build/src/host/controllers/account_orgs_controller.js +1 -1
- package/build/src/host/controllers/account_security_controller.js +1 -1
- package/build/src/host/controllers/interaction_controller.js +2 -2
- package/build/src/host/controllers/registration_controller.js +4 -4
- package/build/src/host/default_mailer.d.ts +13 -8
- package/build/src/host/default_mailer.js +142 -101
- package/build/src/host/sudo/methods/magic_link.js +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# @adonis-agora/authkit-server
|
|
2
2
|
|
|
3
|
+
## 1.0.0-rc.14
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#476](https://github.com/DavideCarvalho/adonis-agora-authkit/pull/476) [`b9f9119`](https://github.com/DavideCarvalho/adonis-agora-authkit/commit/b9f9119a4a030b1fb03befd73d018abd88e8bf6c) Thanks [@DavideCarvalho](https://github.com/DavideCarvalho)! - Default emails (new login / new device alerts, password reset, verification, magic link, sudo link, OTP unlock, email change, security notices, org invitations, `sendAuthkitCodeEmail`) now always use the host's `i18n.locale` and `branding`. They used to read the config through `ctx.containerResolver.app`, which a real request's container resolver does not have, so they silently fell back to English and the "AuthKit" brand. The mailer now uses the resolved config the caller already has, or resolves the `authkit.server` binding, and logs a warning once when it cannot find the config. The header falls back to `branding.company` when `branding.default` is absent.
|
|
8
|
+
|
|
3
9
|
## 1.0.0-rc.13
|
|
4
10
|
|
|
5
11
|
### Patch Changes
|
|
@@ -404,7 +404,7 @@ export default class AccountApiController {
|
|
|
404
404
|
});
|
|
405
405
|
}
|
|
406
406
|
else {
|
|
407
|
-
await sendEmailChangeConfirmationEmail(ctx, { email: newEmail, confirmUrl });
|
|
407
|
+
await sendEmailChangeConfirmationEmail(ctx, { email: newEmail, confirmUrl }, cfg);
|
|
408
408
|
}
|
|
409
409
|
if (account) {
|
|
410
410
|
if (cfg.mail?.onEmailChangeNotice) {
|
|
@@ -272,7 +272,7 @@ export default class AccountOrgsApiController {
|
|
|
272
272
|
if (c.cfg.mail?.onOrgInvitation)
|
|
273
273
|
await c.cfg.mail.onOrgInvitation(payload);
|
|
274
274
|
else
|
|
275
|
-
await sendOrgInvitationEmail(ctx, payload);
|
|
275
|
+
await sendOrgInvitationEmail(ctx, payload, c.cfg);
|
|
276
276
|
}
|
|
277
277
|
catch {
|
|
278
278
|
/* best-effort */
|
|
@@ -1098,7 +1098,7 @@ export default class AuthInteractionController {
|
|
|
1098
1098
|
await cfg.mail.onOtpUnlock({ email: account.email, unlockUrl, token: raw }).catch(() => { });
|
|
1099
1099
|
}
|
|
1100
1100
|
else {
|
|
1101
|
-
await sendOtpUnlockEmail(ctx, { email: account.email, unlockUrl }).catch(() => { });
|
|
1101
|
+
await sendOtpUnlockEmail(ctx, { email: account.email, unlockUrl }, cfg).catch(() => { });
|
|
1102
1102
|
}
|
|
1103
1103
|
}
|
|
1104
1104
|
catch {
|
|
@@ -1200,7 +1200,7 @@ export default class AuthInteractionController {
|
|
|
1200
1200
|
await cfg.mail.onMagicLink({ email: to, magicUrl, token: issued.token, code, channel });
|
|
1201
1201
|
}
|
|
1202
1202
|
else {
|
|
1203
|
-
await sendMagicLinkEmail(ctx, { email: to, magicUrl, code, channel });
|
|
1203
|
+
await sendMagicLinkEmail(ctx, { email: to, magicUrl, code, channel }, cfg);
|
|
1204
1204
|
}
|
|
1205
1205
|
}
|
|
1206
1206
|
}
|
|
@@ -210,7 +210,7 @@ export default class AuthRegistrationController {
|
|
|
210
210
|
await cfg.mail.onEmailVerification({ email: data.email, verifyUrl, token: issued.token });
|
|
211
211
|
}
|
|
212
212
|
else {
|
|
213
|
-
await sendEmailVerificationEmail(ctx, { email: data.email, verifyUrl });
|
|
213
|
+
await sendEmailVerificationEmail(ctx, { email: data.email, verifyUrl }, cfg);
|
|
214
214
|
}
|
|
215
215
|
}
|
|
216
216
|
}
|
|
@@ -255,7 +255,7 @@ export default class AuthRegistrationController {
|
|
|
255
255
|
await cfg.mail.onMagicLink({ email: to, magicUrl, token: issued.token, code });
|
|
256
256
|
}
|
|
257
257
|
else {
|
|
258
|
-
await sendMagicLinkEmail(ctx, { email: to, magicUrl, code });
|
|
258
|
+
await sendMagicLinkEmail(ctx, { email: to, magicUrl, code }, cfg);
|
|
259
259
|
}
|
|
260
260
|
}
|
|
261
261
|
}
|
|
@@ -279,7 +279,7 @@ export default class AuthRegistrationController {
|
|
|
279
279
|
await cfg.mail.onMagicLink({ email: data.email, magicUrl, token, code, kind: 'signup' });
|
|
280
280
|
}
|
|
281
281
|
else {
|
|
282
|
-
await sendMagicLinkEmail(ctx, { email: data.email, magicUrl, code });
|
|
282
|
+
await sendMagicLinkEmail(ctx, { email: data.email, magicUrl, code }, cfg);
|
|
283
283
|
}
|
|
284
284
|
}
|
|
285
285
|
// Resposta uniforme: "enviamos um link" (não vaza existência da conta).
|
|
@@ -436,7 +436,7 @@ export default class AuthRegistrationController {
|
|
|
436
436
|
await cfg.mail.onPasswordReset({ email: to, resetUrl: url, token: result.token });
|
|
437
437
|
}
|
|
438
438
|
else {
|
|
439
|
-
await sendPasswordResetEmail(ctx, { email: to, resetUrl: url });
|
|
439
|
+
await sendPasswordResetEmail(ctx, { email: to, resetUrl: url }, cfg);
|
|
440
440
|
}
|
|
441
441
|
}
|
|
442
442
|
return render(ctx, 'forgot', {
|
|
@@ -21,6 +21,11 @@ type MailService = any;
|
|
|
21
21
|
* @internal
|
|
22
22
|
*/
|
|
23
23
|
export declare function __setMailLoaderForTests(fn: (() => Promise<MailService | null>) | undefined): void;
|
|
24
|
+
/**
|
|
25
|
+
* Permite rearmar o warning "config não resolvido" (usado em testes).
|
|
26
|
+
* @internal
|
|
27
|
+
*/
|
|
28
|
+
export declare function __resetMailConfigWarningForTests(): void;
|
|
24
29
|
/**
|
|
25
30
|
* Envia o e-mail de redefinição de senha pelo mailer default do host.
|
|
26
31
|
* Best-effort: no fallback (sem mail) loga o link; nunca lança.
|
|
@@ -28,7 +33,7 @@ export declare function __setMailLoaderForTests(fn: (() => Promise<MailService |
|
|
|
28
33
|
export declare function sendPasswordResetEmail(ctx: HttpContext, data: {
|
|
29
34
|
email: string;
|
|
30
35
|
resetUrl: string;
|
|
31
|
-
}): Promise<void>;
|
|
36
|
+
}, cfg?: ResolvedServerConfig): Promise<void>;
|
|
32
37
|
/**
|
|
33
38
|
* Envia o e-mail de confirmação de TROCA de e-mail para o NOVO endereço.
|
|
34
39
|
* Best-effort: no fallback (sem mail) loga o link; nunca lança.
|
|
@@ -36,7 +41,7 @@ export declare function sendPasswordResetEmail(ctx: HttpContext, data: {
|
|
|
36
41
|
export declare function sendEmailChangeConfirmationEmail(ctx: HttpContext, data: {
|
|
37
42
|
email: string;
|
|
38
43
|
confirmUrl: string;
|
|
39
|
-
}): Promise<void>;
|
|
44
|
+
}, cfg?: ResolvedServerConfig): Promise<void>;
|
|
40
45
|
/**
|
|
41
46
|
* Envia o e-mail de alerta de NOVO acesso à conta (login de um IP novo).
|
|
42
47
|
* Best-effort: no fallback (sem mail) loga o evento; nunca lança.
|
|
@@ -65,7 +70,7 @@ export declare function sendMagicLinkEmail(ctx: HttpContext, data: {
|
|
|
65
70
|
magicUrl: string;
|
|
66
71
|
code?: string;
|
|
67
72
|
channel?: 'code' | 'link';
|
|
68
|
-
}): Promise<void>;
|
|
73
|
+
}, cfg?: ResolvedServerConfig): Promise<void>;
|
|
69
74
|
/**
|
|
70
75
|
* Envia um e-mail só com um código (sem link: quem digita é a pessoa, em outro lugar) pelo mailer
|
|
71
76
|
* default do host, com o branding e o i18n do authkit. Os textos saem do catálogo pelas chaves
|
|
@@ -81,7 +86,7 @@ export declare function sendAuthkitCodeEmail(ctx: HttpContext, data: {
|
|
|
81
86
|
/** Prefixo das chaves no catálogo (`'mail.poppy_sign_in'`). */
|
|
82
87
|
messages: string;
|
|
83
88
|
params?: Record<string, string | number>;
|
|
84
|
-
}): Promise<void>;
|
|
89
|
+
}, cfg?: ResolvedServerConfig): Promise<void>;
|
|
85
90
|
/**
|
|
86
91
|
* Envia o link de CONFIRMAÇÃO DE IDENTIDADE (sudo) pelo mailer default do host.
|
|
87
92
|
*
|
|
@@ -111,7 +116,7 @@ export declare function sendAuthkitCodeEmail(ctx: HttpContext, data: {
|
|
|
111
116
|
export declare function sendSudoLinkEmail(ctx: HttpContext, data: {
|
|
112
117
|
email: string;
|
|
113
118
|
sudoUrl: string;
|
|
114
|
-
}): Promise<boolean>;
|
|
119
|
+
}, cfg?: ResolvedServerConfig): Promise<boolean>;
|
|
115
120
|
/**
|
|
116
121
|
* Envia o e-mail de aviso de segurança ao e-mail ATUAL quando uma troca de
|
|
117
122
|
* e-mail é solicitada ("Alguém pediu troca para X — se não foi você...").
|
|
@@ -149,7 +154,7 @@ export declare function sendSecurityNoticeEmail(ctx: HttpContext, cfg: ResolvedS
|
|
|
149
154
|
export declare function sendOtpUnlockEmail(ctx: HttpContext, data: {
|
|
150
155
|
email: string;
|
|
151
156
|
unlockUrl: string;
|
|
152
|
-
}): Promise<void>;
|
|
157
|
+
}, cfg?: ResolvedServerConfig): Promise<void>;
|
|
153
158
|
/**
|
|
154
159
|
* Sends the organization invitation email through the host default mailer.
|
|
155
160
|
*
|
|
@@ -170,7 +175,7 @@ export declare function sendOrgInvitationEmail(ctx: HttpContext, data: {
|
|
|
170
175
|
role: string;
|
|
171
176
|
acceptUrl: string;
|
|
172
177
|
token: string;
|
|
173
|
-
}): Promise<void>;
|
|
178
|
+
}, cfg?: ResolvedServerConfig): Promise<void>;
|
|
174
179
|
/**
|
|
175
180
|
* Envia o e-mail de verificação pelo mailer default do host.
|
|
176
181
|
* Best-effort: no fallback (sem mail) loga o link; nunca lança.
|
|
@@ -178,5 +183,5 @@ export declare function sendOrgInvitationEmail(ctx: HttpContext, data: {
|
|
|
178
183
|
export declare function sendEmailVerificationEmail(ctx: HttpContext, data: {
|
|
179
184
|
email: string;
|
|
180
185
|
verifyUrl: string;
|
|
181
|
-
}): Promise<void>;
|
|
186
|
+
}, cfg?: ResolvedServerConfig): Promise<void>;
|
|
182
187
|
export {};
|
|
@@ -6,6 +6,7 @@ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExte
|
|
|
6
6
|
}
|
|
7
7
|
return path;
|
|
8
8
|
};
|
|
9
|
+
import { getBootedApp } from '../../services/booted_app.js';
|
|
9
10
|
import { accountPath } from './account_paths.js';
|
|
10
11
|
import { renderTransactionalEmail } from './email_templates.js';
|
|
11
12
|
import { resolveMessages, translate } from './i18n.js';
|
|
@@ -38,76 +39,116 @@ export function __setMailLoaderForTests(fn) {
|
|
|
38
39
|
mailServicePromise = undefined;
|
|
39
40
|
}
|
|
40
41
|
}
|
|
42
|
+
let warnedUnresolved = false;
|
|
41
43
|
/**
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
+
* Permite rearmar o warning "config não resolvido" (usado em testes).
|
|
45
|
+
* @internal
|
|
44
46
|
*/
|
|
45
|
-
function
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
47
|
+
export function __resetMailConfigWarningForTests() {
|
|
48
|
+
warnedUnresolved = false;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Encontra o config RESOLVIDO do authkit (`ResolvedServerConfig`).
|
|
52
|
+
*
|
|
53
|
+
* Por que não `ctx.containerResolver.app.config.get('authkit')`, como antes: o
|
|
54
|
+
* `ContainerResolver` do `@adonisjs/fold` não tem `.app` — então numa request real
|
|
55
|
+
* esse caminho dava `undefined` SEMPRE e todo e-mail default saía em `en` com a marca
|
|
56
|
+
* "AuthKit". E mesmo onde há um `app` (o ctx do SDK embedded), `config.get('authkit')`
|
|
57
|
+
* devolve o `ConfigProvider` preguiçoso do `defineConfig`, não o config resolvido —
|
|
58
|
+
* `.i18n`/`.branding`/`.mail` nunca existem nele.
|
|
59
|
+
*
|
|
60
|
+
* Ordem: o `cfg` que o chamador já tem → o binding `authkit.server` pelo container da
|
|
61
|
+
* request → pelo `app.container` do ctx → pelo app bootado capturado pelo provider.
|
|
62
|
+
*/
|
|
63
|
+
async function resolveServerConfig(ctx, cfg) {
|
|
64
|
+
if (cfg)
|
|
65
|
+
return cfg;
|
|
66
|
+
const resolver = ctx?.containerResolver;
|
|
67
|
+
const containers = [
|
|
68
|
+
() => resolver,
|
|
69
|
+
() => resolver?.app?.container,
|
|
70
|
+
() => getBootedApp().container,
|
|
71
|
+
];
|
|
72
|
+
for (const container of containers) {
|
|
73
|
+
try {
|
|
74
|
+
const maker = container();
|
|
75
|
+
if (typeof maker?.make !== 'function')
|
|
76
|
+
continue;
|
|
77
|
+
const service = (await maker.make('authkit.server'));
|
|
78
|
+
if (service?.config)
|
|
79
|
+
return service.config;
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
// tenta o próximo; a falha final é avisada em `resolveMailSettings`.
|
|
83
|
+
}
|
|
65
84
|
}
|
|
66
85
|
return undefined;
|
|
67
86
|
}
|
|
68
87
|
/**
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
88
|
+
* O `from` global do `config/mail.ts` do host (um objeto simples, não um provider),
|
|
89
|
+
* lido do `app` do ctx (SDK embedded) ou do app bootado. Ausente → `undefined`, e o
|
|
90
|
+
* `@adonisjs/mail` decide.
|
|
72
91
|
*/
|
|
73
|
-
function
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
92
|
+
function hostMailFrom(ctx) {
|
|
93
|
+
const apps = [
|
|
94
|
+
() => ctx?.containerResolver?.app,
|
|
95
|
+
() => getBootedApp(),
|
|
96
|
+
];
|
|
97
|
+
for (const app of apps) {
|
|
98
|
+
try {
|
|
99
|
+
const from = app()?.config?.get?.('mail')?.from;
|
|
100
|
+
if (from)
|
|
101
|
+
return from;
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
// sem app/config de mail — tenta o próximo.
|
|
83
105
|
}
|
|
84
106
|
}
|
|
85
|
-
|
|
86
|
-
// sem config authkit resolvível — usa default neutro.
|
|
87
|
-
}
|
|
88
|
-
return { appName: 'AuthKit' };
|
|
107
|
+
return undefined;
|
|
89
108
|
}
|
|
90
109
|
/**
|
|
91
|
-
*
|
|
92
|
-
*
|
|
93
|
-
*
|
|
110
|
+
* Marca, i18n e `from` dos e-mails default, a partir do config resolvido.
|
|
111
|
+
*
|
|
112
|
+
* Sem config resolvível cai num default neutro (`en`, "AuthKit") — mas NUNCA em
|
|
113
|
+
* silêncio: avisa uma vez por processo, porque um e-mail no idioma/marca errados é
|
|
114
|
+
* exatamente o tipo de bug que só aparece na caixa de entrada de um usuário.
|
|
94
115
|
*/
|
|
95
|
-
function
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
116
|
+
async function resolveMailSettings(ctx, cfg) {
|
|
117
|
+
const resolved = await resolveServerConfig(ctx, cfg);
|
|
118
|
+
if (!resolved) {
|
|
119
|
+
if (!warnedUnresolved) {
|
|
120
|
+
warnedUnresolved = true;
|
|
121
|
+
const message = 'authkit: config do authkit não resolvido para os e-mails default — usando locale `en` e a marca "AuthKit". Registre o AuthkitServerProvider ou passe o config resolvido.';
|
|
122
|
+
if (typeof ctx?.logger?.warn === 'function')
|
|
123
|
+
ctx.logger.warn(message);
|
|
124
|
+
else
|
|
125
|
+
console.warn(message);
|
|
126
|
+
}
|
|
127
|
+
// `en` de propósito: aqui NÃO há config nenhum (nem o default `pt-BR` do `defineConfig`,
|
|
128
|
+
// que um host sem `i18n` recebe pelo `cfg.locale` acima). Sem saber de quem é o app,
|
|
129
|
+
// o catálogo base — o único com todas as chaves — é o fallback honesto.
|
|
130
|
+
return { brand: { appName: 'AuthKit' }, messages: resolveMessages(), locale: 'en' };
|
|
131
|
+
}
|
|
132
|
+
const branding = resolved.branding;
|
|
133
|
+
return {
|
|
134
|
+
brand: {
|
|
135
|
+
// `branding.default` é opcional na prática (hosts declaram só `company` + `clients`):
|
|
136
|
+
// sem ele, o nome do app é a `company`.
|
|
137
|
+
appName: branding?.default?.appName || branding?.company || 'AuthKit',
|
|
138
|
+
accent: branding?.default?.accent,
|
|
139
|
+
company: branding?.company,
|
|
140
|
+
},
|
|
141
|
+
messages: resolved.messages ?? resolveMessages(),
|
|
142
|
+
locale: resolved.locale ?? 'en',
|
|
143
|
+
// `from` próprio do authkit tem prioridade; senão o `from` global do `config/mail.ts`.
|
|
144
|
+
from: resolved.mail?.from ?? hostMailFrom(ctx),
|
|
145
|
+
};
|
|
105
146
|
}
|
|
106
|
-
async function sendEmail(
|
|
147
|
+
async function sendEmail(settings, to, content) {
|
|
107
148
|
const mail = await loadMail();
|
|
108
149
|
if (!mail)
|
|
109
150
|
return false;
|
|
110
|
-
const from =
|
|
151
|
+
const { from } = settings;
|
|
111
152
|
await mail.send((message) => {
|
|
112
153
|
if (from)
|
|
113
154
|
message.from(from);
|
|
@@ -119,10 +160,10 @@ async function sendEmail(ctx, to, content) {
|
|
|
119
160
|
* Envia o e-mail de redefinição de senha pelo mailer default do host.
|
|
120
161
|
* Best-effort: no fallback (sem mail) loga o link; nunca lança.
|
|
121
162
|
*/
|
|
122
|
-
export async function sendPasswordResetEmail(ctx, data) {
|
|
163
|
+
export async function sendPasswordResetEmail(ctx, data, cfg) {
|
|
123
164
|
try {
|
|
124
|
-
const
|
|
125
|
-
const { messages: t, locale } =
|
|
165
|
+
const settings = await resolveMailSettings(ctx, cfg);
|
|
166
|
+
const { brand, messages: t, locale } = settings;
|
|
126
167
|
const content = renderTransactionalEmail({
|
|
127
168
|
brand,
|
|
128
169
|
locale,
|
|
@@ -134,7 +175,7 @@ export async function sendPasswordResetEmail(ctx, data) {
|
|
|
134
175
|
ctaUrl: data.resetUrl,
|
|
135
176
|
footnote: translate(t, 'mail.reset.fallback'),
|
|
136
177
|
});
|
|
137
|
-
const sent = await sendEmail(
|
|
178
|
+
const sent = await sendEmail(settings, data.email, content);
|
|
138
179
|
if (!sent) {
|
|
139
180
|
ctx.logger.info({ resetUrl: data.resetUrl, email: data.email }, 'authkit: link de redefinição de senha (dev — @adonisjs/mail ausente)');
|
|
140
181
|
}
|
|
@@ -147,10 +188,10 @@ export async function sendPasswordResetEmail(ctx, data) {
|
|
|
147
188
|
* Envia o e-mail de confirmação de TROCA de e-mail para o NOVO endereço.
|
|
148
189
|
* Best-effort: no fallback (sem mail) loga o link; nunca lança.
|
|
149
190
|
*/
|
|
150
|
-
export async function sendEmailChangeConfirmationEmail(ctx, data) {
|
|
191
|
+
export async function sendEmailChangeConfirmationEmail(ctx, data, cfg) {
|
|
151
192
|
try {
|
|
152
|
-
const
|
|
153
|
-
const { messages: t, locale } =
|
|
193
|
+
const settings = await resolveMailSettings(ctx, cfg);
|
|
194
|
+
const { brand, messages: t, locale } = settings;
|
|
154
195
|
const content = renderTransactionalEmail({
|
|
155
196
|
brand,
|
|
156
197
|
locale,
|
|
@@ -162,7 +203,7 @@ export async function sendEmailChangeConfirmationEmail(ctx, data) {
|
|
|
162
203
|
ctaUrl: data.confirmUrl,
|
|
163
204
|
footnote: translate(t, 'mail.email_change.fallback'),
|
|
164
205
|
});
|
|
165
|
-
const sent = await sendEmail(
|
|
206
|
+
const sent = await sendEmail(settings, data.email, content);
|
|
166
207
|
if (!sent) {
|
|
167
208
|
ctx.logger.info({ confirmUrl: data.confirmUrl, email: data.email }, 'authkit: link de confirmação de troca de e-mail (dev — @adonisjs/mail ausente)');
|
|
168
209
|
}
|
|
@@ -177,8 +218,8 @@ export async function sendEmailChangeConfirmationEmail(ctx, data) {
|
|
|
177
218
|
*/
|
|
178
219
|
export async function sendNewLoginEmail(ctx, cfg, data) {
|
|
179
220
|
try {
|
|
180
|
-
const
|
|
181
|
-
const { messages: t, locale } =
|
|
221
|
+
const settings = await resolveMailSettings(ctx, cfg);
|
|
222
|
+
const { brand, messages: t, locale } = settings;
|
|
182
223
|
const origin = authkitOrigin(cfg);
|
|
183
224
|
const intro = [
|
|
184
225
|
translate(t, 'mail.new_login.intro'),
|
|
@@ -196,7 +237,7 @@ export async function sendNewLoginEmail(ctx, cfg, data) {
|
|
|
196
237
|
ctaUrl: `${origin}${accountPath('security')}`,
|
|
197
238
|
footnote: translate(t, 'mail.new_login.fallback'),
|
|
198
239
|
});
|
|
199
|
-
const sent = await sendEmail(
|
|
240
|
+
const sent = await sendEmail(settings, data.email, content);
|
|
200
241
|
if (!sent) {
|
|
201
242
|
ctx.logger.info({ ip: data.ip, email: data.email }, 'authkit: alerta de novo acesso (dev — @adonisjs/mail ausente)');
|
|
202
243
|
}
|
|
@@ -211,8 +252,8 @@ export async function sendNewLoginEmail(ctx, cfg, data) {
|
|
|
211
252
|
*/
|
|
212
253
|
export async function sendNewDeviceLoginEmail(ctx, cfg, data) {
|
|
213
254
|
try {
|
|
214
|
-
const
|
|
215
|
-
const { messages: t, locale } =
|
|
255
|
+
const settings = await resolveMailSettings(ctx, cfg);
|
|
256
|
+
const { brand, messages: t, locale } = settings;
|
|
216
257
|
const origin = authkitOrigin(cfg);
|
|
217
258
|
const lines = [
|
|
218
259
|
translate(t, 'mail.new_login.intro'),
|
|
@@ -233,7 +274,7 @@ export async function sendNewDeviceLoginEmail(ctx, cfg, data) {
|
|
|
233
274
|
ctaUrl: `${origin}${accountPath('security')}`,
|
|
234
275
|
footnote: translate(t, 'mail.new_login.fallback'),
|
|
235
276
|
});
|
|
236
|
-
const sent = await sendEmail(
|
|
277
|
+
const sent = await sendEmail(settings, data.email, content);
|
|
237
278
|
if (!sent) {
|
|
238
279
|
ctx.logger.info({ ip: data.ip, email: data.email, userAgent: data.userAgent }, 'authkit: alerta de novo dispositivo (dev — @adonisjs/mail ausente)');
|
|
239
280
|
}
|
|
@@ -246,10 +287,10 @@ export async function sendNewDeviceLoginEmail(ctx, cfg, data) {
|
|
|
246
287
|
* Envia o e-mail de magic link (login passwordless) pelo mailer default do host.
|
|
247
288
|
* Best-effort: no fallback (sem mail) loga o link; nunca lança.
|
|
248
289
|
*/
|
|
249
|
-
export async function sendMagicLinkEmail(ctx, data) {
|
|
290
|
+
export async function sendMagicLinkEmail(ctx, data, cfg) {
|
|
250
291
|
try {
|
|
251
|
-
const
|
|
252
|
-
const { messages: t, locale } =
|
|
292
|
+
const settings = await resolveMailSettings(ctx, cfg);
|
|
293
|
+
const { brand, messages: t, locale } = settings;
|
|
253
294
|
// Login choose-first: o `channel` decide o que o e-mail SURFA (os dois tokens
|
|
254
295
|
// continuam emitidos co-locados a montante — isto é só renderização).
|
|
255
296
|
// - 'code' → e-mail SÓ com o código (sem botão/link), quando há código;
|
|
@@ -285,7 +326,7 @@ export async function sendMagicLinkEmail(ctx, data) {
|
|
|
285
326
|
code: linkOnly ? undefined : data.code,
|
|
286
327
|
codeLabel: translate(t, 'mail.magic_link.code_label'),
|
|
287
328
|
});
|
|
288
|
-
const sent = await sendEmail(
|
|
329
|
+
const sent = await sendEmail(settings, data.email, content);
|
|
289
330
|
if (!sent) {
|
|
290
331
|
ctx.logger.info({ magicUrl: data.magicUrl, email: data.email }, 'authkit: magic link de login (dev — @adonisjs/mail ausente)');
|
|
291
332
|
}
|
|
@@ -303,10 +344,10 @@ export async function sendMagicLinkEmail(ctx, data) {
|
|
|
303
344
|
*
|
|
304
345
|
* Estável no 1.x (é o mailer das `personalAgents.extensions`).
|
|
305
346
|
*/
|
|
306
|
-
export async function sendAuthkitCodeEmail(ctx, data) {
|
|
347
|
+
export async function sendAuthkitCodeEmail(ctx, data, cfg) {
|
|
307
348
|
try {
|
|
308
|
-
const
|
|
309
|
-
const { messages: t, locale } =
|
|
349
|
+
const settings = await resolveMailSettings(ctx, cfg);
|
|
350
|
+
const { brand, messages: t, locale } = settings;
|
|
310
351
|
const key = (name) => `${data.messages}.${name}`;
|
|
311
352
|
const content = renderTransactionalEmail({
|
|
312
353
|
brand,
|
|
@@ -318,7 +359,7 @@ export async function sendAuthkitCodeEmail(ctx, data) {
|
|
|
318
359
|
code: data.code,
|
|
319
360
|
codeLabel: translate(t, key('code_label'), data.params),
|
|
320
361
|
});
|
|
321
|
-
const sent = await sendEmail(
|
|
362
|
+
const sent = await sendEmail(settings, data.email, content);
|
|
322
363
|
if (!sent) {
|
|
323
364
|
ctx.logger.info({ email: data.email, code: data.code, messages: data.messages, ...(data.params ?? {}) }, 'authkit: código por e-mail (dev — @adonisjs/mail ausente)');
|
|
324
365
|
}
|
|
@@ -353,10 +394,10 @@ export async function sendAuthkitCodeEmail(ctx, data) {
|
|
|
353
394
|
* apagar o pendente da sessão e recusar — flashar "link enviado" deixaria o
|
|
354
395
|
* usuário esperando um e-mail que nunca vem, na tela que já é o gargalo dele.
|
|
355
396
|
*/
|
|
356
|
-
export async function sendSudoLinkEmail(ctx, data) {
|
|
397
|
+
export async function sendSudoLinkEmail(ctx, data, cfg) {
|
|
357
398
|
try {
|
|
358
|
-
const
|
|
359
|
-
const { messages: t, locale } =
|
|
399
|
+
const settings = await resolveMailSettings(ctx, cfg);
|
|
400
|
+
const { brand, messages: t, locale } = settings;
|
|
360
401
|
const content = renderTransactionalEmail({
|
|
361
402
|
brand,
|
|
362
403
|
locale,
|
|
@@ -368,7 +409,7 @@ export async function sendSudoLinkEmail(ctx, data) {
|
|
|
368
409
|
ctaUrl: data.sudoUrl,
|
|
369
410
|
footnote: translate(t, 'mail.sudo_link.fallback'),
|
|
370
411
|
});
|
|
371
|
-
const sent = await sendEmail(
|
|
412
|
+
const sent = await sendEmail(settings, data.email, content);
|
|
372
413
|
if (!sent) {
|
|
373
414
|
ctx.logger?.info({ sudoUrl: data.sudoUrl, email: data.email }, 'authkit: link de confirmação de identidade (dev — @adonisjs/mail ausente)');
|
|
374
415
|
}
|
|
@@ -386,8 +427,8 @@ export async function sendSudoLinkEmail(ctx, data) {
|
|
|
386
427
|
*/
|
|
387
428
|
export async function sendEmailChangeNoticeEmail(ctx, cfg, data) {
|
|
388
429
|
try {
|
|
389
|
-
const
|
|
390
|
-
const { messages: t, locale } =
|
|
430
|
+
const settings = await resolveMailSettings(ctx, cfg);
|
|
431
|
+
const { brand, messages: t, locale } = settings;
|
|
391
432
|
const origin = authkitOrigin(cfg);
|
|
392
433
|
const content = renderTransactionalEmail({
|
|
393
434
|
brand,
|
|
@@ -400,7 +441,7 @@ export async function sendEmailChangeNoticeEmail(ctx, cfg, data) {
|
|
|
400
441
|
ctaUrl: `${origin}${accountPath('security')}`,
|
|
401
442
|
footnote: translate(t, 'mail.email_change_notice.fallback'),
|
|
402
443
|
});
|
|
403
|
-
const sent = await sendEmail(
|
|
444
|
+
const sent = await sendEmail(settings, data.email, content);
|
|
404
445
|
if (!sent) {
|
|
405
446
|
ctx.logger.info({ newEmail: data.newEmail, email: data.email }, 'authkit: aviso de troca de e-mail (dev — @adonisjs/mail ausente)');
|
|
406
447
|
}
|
|
@@ -416,8 +457,8 @@ export async function sendEmailChangeNoticeEmail(ctx, cfg, data) {
|
|
|
416
457
|
*/
|
|
417
458
|
export async function sendEmailChangedCompletedEmail(ctx, cfg, data) {
|
|
418
459
|
try {
|
|
419
|
-
const
|
|
420
|
-
const { messages: t, locale } =
|
|
460
|
+
const settings = await resolveMailSettings(ctx, cfg);
|
|
461
|
+
const { brand, messages: t, locale } = settings;
|
|
421
462
|
const origin = authkitOrigin(cfg);
|
|
422
463
|
const content = renderTransactionalEmail({
|
|
423
464
|
brand,
|
|
@@ -433,7 +474,7 @@ export async function sendEmailChangedCompletedEmail(ctx, cfg, data) {
|
|
|
433
474
|
ctaUrl: `${origin}${accountPath('security')}`,
|
|
434
475
|
footnote: translate(t, 'mail.email_changed_completed.fallback'),
|
|
435
476
|
});
|
|
436
|
-
const sent = await sendEmail(
|
|
477
|
+
const sent = await sendEmail(settings, data.oldEmail, content);
|
|
437
478
|
if (!sent) {
|
|
438
479
|
ctx.logger.info({ oldEmail: data.oldEmail, newEmail: data.newEmail }, 'authkit: confirmação de troca de e-mail concluída (dev — @adonisjs/mail ausente)');
|
|
439
480
|
}
|
|
@@ -449,8 +490,8 @@ export async function sendEmailChangedCompletedEmail(ctx, cfg, data) {
|
|
|
449
490
|
*/
|
|
450
491
|
export async function sendSecurityNoticeEmail(ctx, cfg, data) {
|
|
451
492
|
try {
|
|
452
|
-
const
|
|
453
|
-
const { messages: t, locale } =
|
|
493
|
+
const settings = await resolveMailSettings(ctx, cfg);
|
|
494
|
+
const { brand, messages: t, locale } = settings;
|
|
454
495
|
const origin = authkitOrigin(cfg);
|
|
455
496
|
const kindKey = `mail.security_notice.kind_${data.kind}`;
|
|
456
497
|
const kindLabel = translate(t, kindKey);
|
|
@@ -471,7 +512,7 @@ export async function sendSecurityNoticeEmail(ctx, cfg, data) {
|
|
|
471
512
|
ctaUrl: `${origin}${accountPath('security')}`,
|
|
472
513
|
footnote: translate(t, 'mail.security_notice.fallback'),
|
|
473
514
|
});
|
|
474
|
-
const sent = await sendEmail(
|
|
515
|
+
const sent = await sendEmail(settings, data.email, content);
|
|
475
516
|
if (!sent) {
|
|
476
517
|
ctx.logger.info({ kind: data.kind, email: data.email }, 'authkit: notificação de segurança (dev — @adonisjs/mail ausente)');
|
|
477
518
|
}
|
|
@@ -484,10 +525,10 @@ export async function sendSecurityNoticeEmail(ctx, cfg, data) {
|
|
|
484
525
|
* Envia o e-mail de desbloqueio do fator OTP (quando TOTP/recovery excede maxAttempts).
|
|
485
526
|
* Best-effort: no fallback (sem mail) loga o link; nunca lança.
|
|
486
527
|
*/
|
|
487
|
-
export async function sendOtpUnlockEmail(ctx, data) {
|
|
528
|
+
export async function sendOtpUnlockEmail(ctx, data, cfg) {
|
|
488
529
|
try {
|
|
489
|
-
const
|
|
490
|
-
const { messages: t, locale } =
|
|
530
|
+
const settings = await resolveMailSettings(ctx, cfg);
|
|
531
|
+
const { brand, messages: t, locale } = settings;
|
|
491
532
|
const content = renderTransactionalEmail({
|
|
492
533
|
brand,
|
|
493
534
|
locale,
|
|
@@ -499,7 +540,7 @@ export async function sendOtpUnlockEmail(ctx, data) {
|
|
|
499
540
|
ctaUrl: data.unlockUrl,
|
|
500
541
|
footnote: translate(t, 'mail.otp_unlock.fallback'),
|
|
501
542
|
});
|
|
502
|
-
const sent = await sendEmail(
|
|
543
|
+
const sent = await sendEmail(settings, data.email, content);
|
|
503
544
|
if (!sent) {
|
|
504
545
|
ctx.logger.info({ unlockUrl: data.unlockUrl, email: data.email }, 'authkit: link de desbloqueio OTP (dev — @adonisjs/mail ausente)');
|
|
505
546
|
}
|
|
@@ -520,10 +561,10 @@ export async function sendOtpUnlockEmail(ctx, data) {
|
|
|
520
561
|
*
|
|
521
562
|
* Best-effort: never throws — invitation creation must not depend on delivery.
|
|
522
563
|
*/
|
|
523
|
-
export async function sendOrgInvitationEmail(ctx, data) {
|
|
564
|
+
export async function sendOrgInvitationEmail(ctx, data, cfg) {
|
|
524
565
|
try {
|
|
525
|
-
const
|
|
526
|
-
const { messages: t, locale } =
|
|
566
|
+
const settings = await resolveMailSettings(ctx, cfg);
|
|
567
|
+
const { brand, messages: t, locale } = settings;
|
|
527
568
|
const content = renderTransactionalEmail({
|
|
528
569
|
brand,
|
|
529
570
|
locale,
|
|
@@ -535,7 +576,7 @@ export async function sendOrgInvitationEmail(ctx, data) {
|
|
|
535
576
|
ctaUrl: data.acceptUrl,
|
|
536
577
|
footnote: translate(t, 'mail.org_invitation.fallback'),
|
|
537
578
|
});
|
|
538
|
-
const sent = await sendEmail(
|
|
579
|
+
const sent = await sendEmail(settings, data.email, content);
|
|
539
580
|
if (!sent) {
|
|
540
581
|
ctx.logger?.info({
|
|
541
582
|
acceptUrl: data.acceptUrl,
|
|
@@ -553,10 +594,10 @@ export async function sendOrgInvitationEmail(ctx, data) {
|
|
|
553
594
|
* Envia o e-mail de verificação pelo mailer default do host.
|
|
554
595
|
* Best-effort: no fallback (sem mail) loga o link; nunca lança.
|
|
555
596
|
*/
|
|
556
|
-
export async function sendEmailVerificationEmail(ctx, data) {
|
|
597
|
+
export async function sendEmailVerificationEmail(ctx, data, cfg) {
|
|
557
598
|
try {
|
|
558
|
-
const
|
|
559
|
-
const { messages: t, locale } =
|
|
599
|
+
const settings = await resolveMailSettings(ctx, cfg);
|
|
600
|
+
const { brand, messages: t, locale } = settings;
|
|
560
601
|
const content = renderTransactionalEmail({
|
|
561
602
|
brand,
|
|
562
603
|
locale,
|
|
@@ -567,7 +608,7 @@ export async function sendEmailVerificationEmail(ctx, data) {
|
|
|
567
608
|
ctaLabel: translate(t, 'mail.verify.cta'),
|
|
568
609
|
ctaUrl: data.verifyUrl,
|
|
569
610
|
});
|
|
570
|
-
const sent = await sendEmail(
|
|
611
|
+
const sent = await sendEmail(settings, data.email, content);
|
|
571
612
|
if (!sent) {
|
|
572
613
|
ctx.logger.info({ verifyUrl: data.verifyUrl, email: data.email }, 'authkit: link de verificação de e-mail (dev — @adonisjs/mail ausente)');
|
|
573
614
|
}
|
|
@@ -154,7 +154,7 @@ export function magicLink() {
|
|
|
154
154
|
delivered = true;
|
|
155
155
|
}
|
|
156
156
|
else {
|
|
157
|
-
delivered = await sendSudoLinkEmail(ctx, { email: c.account.email, sudoUrl });
|
|
157
|
+
delivered = await sendSudoLinkEmail(ctx, { email: c.account.email, sudoUrl }, c.cfg);
|
|
158
158
|
}
|
|
159
159
|
}
|
|
160
160
|
catch {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adonis-agora/authkit-server",
|
|
3
|
-
"version": "1.0.0-rc.
|
|
3
|
+
"version": "1.0.0-rc.14",
|
|
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",
|