@adonis-agora/authkit-server 0.88.0 → 0.89.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.
|
@@ -122,6 +122,22 @@ export interface MailHooks {
|
|
|
122
122
|
agentName: string;
|
|
123
123
|
expiresInMinutes: number;
|
|
124
124
|
}) => Promise<void>;
|
|
125
|
+
/**
|
|
126
|
+
* Disparado num login bem-sucedido a partir de um IP NOVO para a conta (nenhum
|
|
127
|
+
* `login.success` anterior desse IP no audit sink), quando `notifications.newLoginEmail`
|
|
128
|
+
* está ligado. Best-effort, fire-and-forget: uma falha aqui NUNCA quebra o login.
|
|
129
|
+
* Quando ausente mas o mail estiver configurado, o host-kit envia o e-mail default de
|
|
130
|
+
* "novo login". O `login.new_ip_notified` é auditado nos dois casos.
|
|
131
|
+
*/
|
|
132
|
+
onNewLogin?: (data: {
|
|
133
|
+
account: {
|
|
134
|
+
id: string;
|
|
135
|
+
email: string;
|
|
136
|
+
};
|
|
137
|
+
ip: string;
|
|
138
|
+
userAgent?: string | null;
|
|
139
|
+
timestamp: string;
|
|
140
|
+
}) => Promise<void>;
|
|
125
141
|
/**
|
|
126
142
|
* Disparado num login bem-sucedido a partir de um dispositivo NOVO (sem cookie
|
|
127
143
|
* de dispositivo confiável válido para a conta). Best-effort, fire-and-forget:
|
|
@@ -51,7 +51,12 @@ export async function notifyLoginSuccess(ctx, cfg, input) {
|
|
|
51
51
|
resolvedEmail = (await cfg.accountStore.findById(accountId))?.email ?? null;
|
|
52
52
|
}
|
|
53
53
|
if (cfg.notifications.newLoginEmail) {
|
|
54
|
-
await maybeNotifyNewLogin(ctx, cfg, {
|
|
54
|
+
await maybeNotifyNewLogin(ctx, cfg, {
|
|
55
|
+
accountId,
|
|
56
|
+
email: resolvedEmail,
|
|
57
|
+
ip: ip ?? null,
|
|
58
|
+
userAgent,
|
|
59
|
+
});
|
|
55
60
|
}
|
|
56
61
|
if (onNewDevice && cfg.notifications.newDeviceEmail && resolvedEmail) {
|
|
57
62
|
await notifyNewDevice(ctx, cfg, {
|
|
@@ -108,12 +113,12 @@ async function notifyNewDevice(ctx, cfg, data) {
|
|
|
108
113
|
}
|
|
109
114
|
/**
|
|
110
115
|
* Verifica se o IP é novo para a conta (consultando o audit sink por
|
|
111
|
-
* `login.success` do subject) e, se for, envia o
|
|
112
|
-
* `login.new_ip_notified`. Degrada para no-op quando: sem IP, sem e-mail, sem
|
|
116
|
+
* `login.success` do subject) e, se for, envia o alerta (hook `mail.onNewLogin`,
|
|
117
|
+
* override do host, ou o mailer default) + audita `login.new_ip_notified`. Degrada para no-op quando: sem IP, sem e-mail, sem
|
|
113
118
|
* sink consultável (`list`), ou já houve um login.success deste IP antes.
|
|
114
119
|
*/
|
|
115
120
|
async function maybeNotifyNewLogin(ctx, cfg, data) {
|
|
116
|
-
const { accountId, email, ip } = data;
|
|
121
|
+
const { accountId, email, ip, userAgent } = data;
|
|
117
122
|
if (!ip || !email)
|
|
118
123
|
return;
|
|
119
124
|
// Sem consulta do histórico não dá pra decidir se o IP é novo → no-op.
|
|
@@ -133,7 +138,25 @@ async function maybeNotifyNewLogin(ctx, cfg, data) {
|
|
|
133
138
|
if (sameIpCount > 1)
|
|
134
139
|
return;
|
|
135
140
|
const when = new Date().toISOString();
|
|
136
|
-
|
|
141
|
+
if (cfg.mail?.onNewLogin) {
|
|
142
|
+
// Isolado: o mailer default engole os próprios erros, o hook do host não. Sem
|
|
143
|
+
// este try, um hook que lança cortaria o audit abaixo e o alerta de novo
|
|
144
|
+
// dispositivo, que roda depois deste na mesma tarefa.
|
|
145
|
+
try {
|
|
146
|
+
await cfg.mail.onNewLogin({
|
|
147
|
+
account: { id: accountId, email },
|
|
148
|
+
ip,
|
|
149
|
+
userAgent,
|
|
150
|
+
timestamp: when,
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
catch (error) {
|
|
154
|
+
ctx.logger?.error?.({ err: error, accountId }, 'authkit: falha no hook mail.onNewLogin');
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
await sendNewLoginEmail(ctx, cfg, { email, ip, when });
|
|
159
|
+
}
|
|
137
160
|
await cfg.audit?.record({
|
|
138
161
|
type: 'login.new_ip_notified',
|
|
139
162
|
accountId,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adonis-agora/authkit-server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.89.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",
|
|
@@ -108,7 +108,7 @@
|
|
|
108
108
|
"@adonis-agora/authkit-core": "0.10.1",
|
|
109
109
|
"@simplewebauthn/browser": "14.0.0",
|
|
110
110
|
"@simplewebauthn/server": "14.0.3",
|
|
111
|
-
"jose": "6.2.
|
|
111
|
+
"jose": "6.2.14",
|
|
112
112
|
"koa": "3.2.1",
|
|
113
113
|
"koa-mount": "4.2.0",
|
|
114
114
|
"oidc-provider": "9.12.2",
|
|
@@ -117,8 +117,8 @@
|
|
|
117
117
|
},
|
|
118
118
|
"devDependencies": {
|
|
119
119
|
"@adonis-agora/authkit-react": "0.26.0",
|
|
120
|
-
"@adonis-agora/durable": "0.
|
|
121
|
-
"@adonis-agora/telescope": "0.
|
|
120
|
+
"@adonis-agora/durable": "0.58.2",
|
|
121
|
+
"@adonis-agora/telescope": "0.27.0",
|
|
122
122
|
"@adonisjs/ally": "6.3.2",
|
|
123
123
|
"@adonisjs/auth": "10.1.0",
|
|
124
124
|
"@adonisjs/core": "7.6.0",
|