@adonis-agora/authkit-server 0.48.0 → 0.49.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/index.d.ts +15 -0
- package/build/index.js +13 -0
- package/build/src/host/account_screen_props.d.ts +163 -0
- package/build/src/host/account_screen_props.js +23 -0
- package/build/src/host/controllers/account_confirm_controller.js +3 -2
- package/build/src/host/controllers/account_mfa_controller.js +9 -6
- package/build/src/host/controllers/account_security_controller.js +3 -2
- package/build/src/host/controllers/account_session_controller.js +8 -3
- package/build/src/host/renderers/inertia_renderer.d.ts +23 -66
- package/build/src/host/renderers/inertia_renderer.js +23 -66
- package/package.json +2 -2
package/build/index.d.ts
CHANGED
|
@@ -46,6 +46,7 @@ export type { EventsConfigInput, ResolvedEventsConfig } from './src/events/dispa
|
|
|
46
46
|
export { inertiaRenderer } from './src/host/renderers/inertia_renderer.js';
|
|
47
47
|
export type { AuthkitScreen } from './src/host/renderers/inertia_renderer.js';
|
|
48
48
|
export type { InertiaRendererOptions } from './src/host/renderers/inertia_renderer.js';
|
|
49
|
+
export type { AccountLoginProps, AccountSecurityProps, AccountMfaProps, AccountConfirmProps, AccountConfirmMethod, AccountEmailConfirmedProps, } from './src/host/account_screen_props.js';
|
|
49
50
|
export { edgeRenderer } from './src/host/renderers/edge_renderer.js';
|
|
50
51
|
export { brandFor, isFirstParty } from './src/host/branding.js';
|
|
51
52
|
export type { BrandingConfig, ClientBrand } from './src/host/branding.js';
|
|
@@ -55,6 +56,20 @@ export type { AuthHostRenderer, AuthSocialConfig } from './src/define_config.js'
|
|
|
55
56
|
export { registerAuthHost } from './src/host/register_auth_host.js';
|
|
56
57
|
export type { AuthHostOptions } from './src/host/register_auth_host.js';
|
|
57
58
|
export { getAdminPrefix, setAdminPrefix, normalizeAdminPrefix, getAdminApiPrefix, setAdminApiPrefix, normalizeAdminApiPrefix, } from './src/host/admin_prefix.js';
|
|
59
|
+
/**
|
|
60
|
+
* Helpers de path do console de conta (`/account/*`). Um host que precisa casar
|
|
61
|
+
* um middleware ou link com uma rota do console (ex.: `GET
|
|
62
|
+
* {accountPath('security')}/export`) deriva o path daqui em vez de hardcodar,
|
|
63
|
+
* respeitando os overrides de `accountRoutes`.
|
|
64
|
+
*
|
|
65
|
+
* ⚠️ Estes helpers leem um singleton de processo que só reflete os overrides
|
|
66
|
+
* DEPOIS que `registerAuthHost` roda (é ele quem chama `setAccountPaths` com a
|
|
67
|
+
* opção `accountRoutes`, no boot). Chamados antes disso, devolvem os defaults
|
|
68
|
+
* (`/account/*`). Componha URLs em runtime (dentro de handlers/factories de
|
|
69
|
+
* middleware), não em tempo de import de módulo.
|
|
70
|
+
*/
|
|
71
|
+
export { accountPath, joinAccountPath, accountPrefix, } from './src/host/account_paths.js';
|
|
72
|
+
export type { AccountPathsOptions, AccountPathKey } from './src/host/account_paths.js';
|
|
58
73
|
export { resolveRateLimit, resolveNotifications } from './src/define_config.js';
|
|
59
74
|
export type { ResolvedNotificationsConfig } from './src/define_config.js';
|
|
60
75
|
export type { RateLimitConfigInput, RateLimitBucket, ResolvedRateLimitConfig, } from './src/define_config.js';
|
package/build/index.js
CHANGED
|
@@ -32,6 +32,19 @@ export { brandFor, isFirstParty } from './src/host/branding.js';
|
|
|
32
32
|
export { resolveMessages, translate, DEFAULT_MESSAGES, PT_BR_MESSAGES, BUILTIN_MESSAGES, DEFAULT_LOCALE, } from './src/host/i18n.js';
|
|
33
33
|
export { registerAuthHost } from './src/host/register_auth_host.js';
|
|
34
34
|
export { getAdminPrefix, setAdminPrefix, normalizeAdminPrefix, getAdminApiPrefix, setAdminApiPrefix, normalizeAdminApiPrefix, } from './src/host/admin_prefix.js';
|
|
35
|
+
/**
|
|
36
|
+
* Helpers de path do console de conta (`/account/*`). Um host que precisa casar
|
|
37
|
+
* um middleware ou link com uma rota do console (ex.: `GET
|
|
38
|
+
* {accountPath('security')}/export`) deriva o path daqui em vez de hardcodar,
|
|
39
|
+
* respeitando os overrides de `accountRoutes`.
|
|
40
|
+
*
|
|
41
|
+
* ⚠️ Estes helpers leem um singleton de processo que só reflete os overrides
|
|
42
|
+
* DEPOIS que `registerAuthHost` roda (é ele quem chama `setAccountPaths` com a
|
|
43
|
+
* opção `accountRoutes`, no boot). Chamados antes disso, devolvem os defaults
|
|
44
|
+
* (`/account/*`). Componha URLs em runtime (dentro de handlers/factories de
|
|
45
|
+
* middleware), não em tempo de import de módulo.
|
|
46
|
+
*/
|
|
47
|
+
export { accountPath, joinAccountPath, accountPrefix, } from './src/host/account_paths.js';
|
|
35
48
|
export { resolveRateLimit, resolveNotifications } from './src/define_config.js';
|
|
36
49
|
export { createAuthThrottles } from './src/host/rate_limit.js';
|
|
37
50
|
/**
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tipos de props das telas do console de conta (`/account/*`) — a FONTE ÚNICA da
|
|
3
|
+
* verdade sobre o shape que cada página React recebe.
|
|
4
|
+
*
|
|
5
|
+
* ── Por que esses tipos existem ──────────────────────────────────────────────
|
|
6
|
+
* Um host que cria as telas do console em React próprio (via `inertiaRenderer`,
|
|
7
|
+
* em vez das views Edge built-in) precisa tipar o componente da página. Antes
|
|
8
|
+
* disso, o único "contrato" era o DOCBLOCK do `inertiaRenderer`, copiado à mão —
|
|
9
|
+
* frágil: um docblock desatualizado já enganou um host. Agora o shape vem daqui,
|
|
10
|
+
* e os CONTROLLERS REAIS (`account_session_controller`, `account_security_-
|
|
11
|
+
* controller`, `account_mfa_controller`, `account_confirm_controller`) satisfazem
|
|
12
|
+
* (`satisfies Omit<…, 'messages'>`) exatamente estes tipos ao chamar `render()`.
|
|
13
|
+
* Se o payload de um controller divergir do tipo — campo a mais, a menos, tipo
|
|
14
|
+
* trocado — o `tsc` do pacote quebra. Esse é o objetivo: um único ponto muda, e
|
|
15
|
+
* o compilador força o outro a acompanhar.
|
|
16
|
+
*
|
|
17
|
+
* ── Sobre a prop `messages` ──────────────────────────────────────────────────
|
|
18
|
+
* `messages` (catálogo i18n) é injetada pelo `inertiaRenderer` como shared prop,
|
|
19
|
+
* NÃO pelos controllers. Por isso ela faz parte destes tipos (é o que a página
|
|
20
|
+
* React recebe), mas os controllers satisfazem `Omit<…, 'messages'>` — eles nunca
|
|
21
|
+
* passam `messages` no literal do `render()`.
|
|
22
|
+
*/
|
|
23
|
+
import type { PasskeySummary } from '../accounts/account_store.js';
|
|
24
|
+
import type { AuthMessages } from './i18n.js';
|
|
25
|
+
import type { SudoMethodDescriptor } from './sudo/types.js';
|
|
26
|
+
/**
|
|
27
|
+
* Props da tela `account/login` (tela de login do console de conta).
|
|
28
|
+
*
|
|
29
|
+
* - `csrfToken`: token para o campo `_csrf` do formulário.
|
|
30
|
+
* - `returnTo`: caminho interno de destino pós-login (já validado pelo servidor —
|
|
31
|
+
* só caminhos internos) ou `null`. Quando presente, o formulário deve incluir
|
|
32
|
+
* `<input type="hidden" name="return_to" value={returnTo} />`; o servidor
|
|
33
|
+
* revalida no POST.
|
|
34
|
+
* - `error`: mensagem de erro de autenticação localizada (credenciais inválidas,
|
|
35
|
+
* conta bloqueada/desabilitada). Ausente quando não há erro.
|
|
36
|
+
* - `messages`: catálogo i18n (injetado pelo renderer).
|
|
37
|
+
*/
|
|
38
|
+
export interface AccountLoginProps {
|
|
39
|
+
csrfToken: string;
|
|
40
|
+
returnTo: string | null;
|
|
41
|
+
error?: string;
|
|
42
|
+
messages: AuthMessages;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Props da tela `account/security` (perfil, senha, e-mail, sessões, export,
|
|
46
|
+
* danger-zone). Todas as flags de `*Supported` degradam a UI quando o store não
|
|
47
|
+
* suporta a capacidade correspondente.
|
|
48
|
+
*
|
|
49
|
+
* - `supported`: `false` quando o store não suporta o self-service de segurança.
|
|
50
|
+
* - `profileSupported`: `true` quando dá para editar nome/avatar (`updateProfile`).
|
|
51
|
+
* - `avatarUploadSupported`: `true` quando algum backend (drive OU media) armazena o upload.
|
|
52
|
+
* - `email` / `name` / `avatarUrl`: valores atuais da conta (`''` se ausentes).
|
|
53
|
+
* - `passwordChanged` / `emailChangeRequested` / `emailChanged` / `profileUpdated`
|
|
54
|
+
* / `error` / `trustedDevicesRevoked` / `deleteError`: flashes localizados ou `null`.
|
|
55
|
+
* - `trustedDevicesEnabled`: recurso de dispositivos confiáveis ligado.
|
|
56
|
+
* - `sessionsSupported`: `true` quando o adapter OIDC enumera as sessões ativas.
|
|
57
|
+
* - `sessions`: sessões ativas da própria conta (vazio quando não suportado).
|
|
58
|
+
* `loginTs` é ISO ou `''`.
|
|
59
|
+
* - `exportSupported`: sempre `true` (portabilidade/LGPD para a conta logada).
|
|
60
|
+
* - `deletionSupported`: `true` quando o store suporta hard delete.
|
|
61
|
+
* - `messages`: catálogo i18n (injetado pelo renderer).
|
|
62
|
+
*/
|
|
63
|
+
export interface AccountSecurityProps {
|
|
64
|
+
csrfToken: string;
|
|
65
|
+
supported: boolean;
|
|
66
|
+
profileSupported: boolean;
|
|
67
|
+
avatarUploadSupported: boolean;
|
|
68
|
+
email: string;
|
|
69
|
+
name: string;
|
|
70
|
+
avatarUrl: string;
|
|
71
|
+
passwordChanged: string | null;
|
|
72
|
+
emailChangeRequested: string | null;
|
|
73
|
+
emailChanged: string | null;
|
|
74
|
+
profileUpdated: string | null;
|
|
75
|
+
error: string | null;
|
|
76
|
+
trustedDevicesEnabled: boolean;
|
|
77
|
+
trustedDevicesRevoked: string | null;
|
|
78
|
+
sessionsSupported: boolean;
|
|
79
|
+
sessions: Array<{
|
|
80
|
+
loginTs: string;
|
|
81
|
+
browser: string;
|
|
82
|
+
os: string;
|
|
83
|
+
ip: string;
|
|
84
|
+
location: string;
|
|
85
|
+
}>;
|
|
86
|
+
exportSupported: boolean;
|
|
87
|
+
deletionSupported: boolean;
|
|
88
|
+
deleteError: string | null;
|
|
89
|
+
messages: AuthMessages;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Props da tela `account/mfa` (TOTP + passkeys). As props VARIAM por action, e é
|
|
93
|
+
* por isso que as específicas de passo são opcionais:
|
|
94
|
+
*
|
|
95
|
+
* - `index` manda o estado base + a lista de passkeys (`passkeysSupported` /
|
|
96
|
+
* `passkeys`).
|
|
97
|
+
* - `enroll` (após `POST /mfa/enroll`) acrescenta o passo do QR: `enrolling: true`,
|
|
98
|
+
* `secret` (base32 para entrada manual) e `qrDataUrl` (data-URL do `otpauth://`).
|
|
99
|
+
* - `confirm` com código inválido reexibe `enrolling: true` + `error`, com
|
|
100
|
+
* `secret`/`qrDataUrl` `null` (o segredo pendente NÃO é regenerado).
|
|
101
|
+
*
|
|
102
|
+
* - `enabled`: `true` quando o TOTP já está confirmado.
|
|
103
|
+
* - `recoveryCodes`: códigos recém-gerados (exibidos UMA vez) ou `null`.
|
|
104
|
+
* - `messages`: catálogo i18n (injetado pelo renderer).
|
|
105
|
+
*/
|
|
106
|
+
export interface AccountMfaProps {
|
|
107
|
+
csrfToken: string;
|
|
108
|
+
enabled: boolean;
|
|
109
|
+
recoveryCodes: string[] | null;
|
|
110
|
+
/** Presente em `index`: `true` quando o store persiste credenciais WebAuthn. */
|
|
111
|
+
passkeysSupported?: boolean;
|
|
112
|
+
/** Presente em `index`: passkeys cadastradas (vazio quando não suportado). */
|
|
113
|
+
passkeys?: PasskeySummary[];
|
|
114
|
+
/** Passo de enroll/confirm: `true` mostra QR/segredo + campo de código. */
|
|
115
|
+
enrolling?: boolean;
|
|
116
|
+
/** Segredo TOTP (base32) no passo de enroll; `null` na reexibição do confirm. */
|
|
117
|
+
secret?: string | null;
|
|
118
|
+
/** QR do `otpauth://` como data-URL no passo de enroll; `null` na reexibição. */
|
|
119
|
+
qrDataUrl?: string | null;
|
|
120
|
+
/** Erro localizado (ex.: código TOTP inválido no confirm). */
|
|
121
|
+
error?: string;
|
|
122
|
+
messages: AuthMessages;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Um método de sudo, como a tela `account/confirm` o recebe: o descritor do SPI
|
|
126
|
+
* (`SudoMethodDescriptor`) acrescido do `id` estável do método. A tela renderiza
|
|
127
|
+
* por `kind` (`form`/`action`/`redirect`/`webauthn`); `endpoint` é o POST de
|
|
128
|
+
* verificação (para `webauthn`, as options ficam em `${endpoint}/options`).
|
|
129
|
+
*/
|
|
130
|
+
export type AccountConfirmMethod = {
|
|
131
|
+
id: string;
|
|
132
|
+
} & SudoMethodDescriptor;
|
|
133
|
+
/**
|
|
134
|
+
* Props da tela `account/confirm` (sudo — confirmar identidade).
|
|
135
|
+
*
|
|
136
|
+
* - `csrfToken`: token para o POST de cada método.
|
|
137
|
+
* - `returnTo`: caminho interno de destino após confirmar (validado) ou `null`.
|
|
138
|
+
* - `error`: flash de erro da última tentativa ou `null`.
|
|
139
|
+
* - `notice`: flash informativo (ex.: "link de confirmação enviado") ou `null`.
|
|
140
|
+
* - `methods`: métodos de sudo disponíveis para a conta (ver {@link AccountConfirmMethod}).
|
|
141
|
+
* - `preferredId`: `id` do último método usado (destaque na UI) ou `null`.
|
|
142
|
+
* - `messages`: catálogo i18n (injetado pelo renderer).
|
|
143
|
+
*/
|
|
144
|
+
export interface AccountConfirmProps {
|
|
145
|
+
csrfToken: string;
|
|
146
|
+
returnTo: string | null;
|
|
147
|
+
error: string | null;
|
|
148
|
+
notice: string | null;
|
|
149
|
+
methods: AccountConfirmMethod[];
|
|
150
|
+
preferredId: string | null;
|
|
151
|
+
messages: AuthMessages;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Props da tela `account/email-confirmed` (terminal do link de troca de e-mail).
|
|
155
|
+
*
|
|
156
|
+
* - `ok`: `true` quando o token era válido e o novo e-mail foi aplicado; `false`
|
|
157
|
+
* para token inválido/expirado ou store sem suporte.
|
|
158
|
+
* - `messages`: catálogo i18n (injetado pelo renderer).
|
|
159
|
+
*/
|
|
160
|
+
export interface AccountEmailConfirmedProps {
|
|
161
|
+
ok: boolean;
|
|
162
|
+
messages: AuthMessages;
|
|
163
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tipos de props das telas do console de conta (`/account/*`) — a FONTE ÚNICA da
|
|
3
|
+
* verdade sobre o shape que cada página React recebe.
|
|
4
|
+
*
|
|
5
|
+
* ── Por que esses tipos existem ──────────────────────────────────────────────
|
|
6
|
+
* Um host que cria as telas do console em React próprio (via `inertiaRenderer`,
|
|
7
|
+
* em vez das views Edge built-in) precisa tipar o componente da página. Antes
|
|
8
|
+
* disso, o único "contrato" era o DOCBLOCK do `inertiaRenderer`, copiado à mão —
|
|
9
|
+
* frágil: um docblock desatualizado já enganou um host. Agora o shape vem daqui,
|
|
10
|
+
* e os CONTROLLERS REAIS (`account_session_controller`, `account_security_-
|
|
11
|
+
* controller`, `account_mfa_controller`, `account_confirm_controller`) satisfazem
|
|
12
|
+
* (`satisfies Omit<…, 'messages'>`) exatamente estes tipos ao chamar `render()`.
|
|
13
|
+
* Se o payload de um controller divergir do tipo — campo a mais, a menos, tipo
|
|
14
|
+
* trocado — o `tsc` do pacote quebra. Esse é o objetivo: um único ponto muda, e
|
|
15
|
+
* o compilador força o outro a acompanhar.
|
|
16
|
+
*
|
|
17
|
+
* ── Sobre a prop `messages` ──────────────────────────────────────────────────
|
|
18
|
+
* `messages` (catálogo i18n) é injetada pelo `inertiaRenderer` como shared prop,
|
|
19
|
+
* NÃO pelos controllers. Por isso ela faz parte destes tipos (é o que a página
|
|
20
|
+
* React recebe), mas os controllers satisfazem `Omit<…, 'messages'>` — eles nunca
|
|
21
|
+
* passam `messages` no literal do `render()`.
|
|
22
|
+
*/
|
|
23
|
+
export {};
|
|
@@ -37,7 +37,7 @@ export default class AccountConfirmController {
|
|
|
37
37
|
ctx.logger?.warn({ method: m.id }, `authkit: método de sudo "${m.id}" está em config.sudo.methods mas não teve rotas montadas por registerAuthHost — a tela vai oferecer uma opção cujo endpoint não existe`);
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
|
-
|
|
40
|
+
const props = {
|
|
41
41
|
csrfToken: ctx.request.csrfToken,
|
|
42
42
|
returnTo: c.returnTo,
|
|
43
43
|
error: ctx.session.flashMessages.get('confirmError') ?? null,
|
|
@@ -47,6 +47,7 @@ export default class AccountConfirmController {
|
|
|
47
47
|
notice: ctx.session.flashMessages.get('confirmNotice') ?? null,
|
|
48
48
|
methods,
|
|
49
49
|
preferredId: ctx.session.get(LAST_METHOD_SESSION_KEY) ?? null,
|
|
50
|
-
}
|
|
50
|
+
};
|
|
51
|
+
return c.cfg.render(ctx, 'account/confirm', props);
|
|
51
52
|
}
|
|
52
53
|
}
|
|
@@ -40,13 +40,14 @@ export default class AccountMfaController {
|
|
|
40
40
|
// Passkeys disponíveis quando o store as suporta (model de credenciais wired).
|
|
41
41
|
const passkeysSupported = supportsPasskeys(cfg.accountStore);
|
|
42
42
|
const passkeys = passkeysSupported ? await cfg.accountStore.listPasskeys(userId) : [];
|
|
43
|
-
|
|
43
|
+
const props = {
|
|
44
44
|
csrfToken: ctx.request.csrfToken,
|
|
45
45
|
enabled: state.enabled,
|
|
46
46
|
recoveryCodes: recoveryCodes ?? null,
|
|
47
47
|
passkeysSupported,
|
|
48
48
|
passkeys,
|
|
49
|
-
}
|
|
49
|
+
};
|
|
50
|
+
return render(ctx, 'account/mfa', props);
|
|
50
51
|
}
|
|
51
52
|
/**
|
|
52
53
|
* POST /account/mfa/passkeys/options — gera as opções de registro de passkey
|
|
@@ -178,14 +179,15 @@ export default class AccountMfaController {
|
|
|
178
179
|
}
|
|
179
180
|
// QR renderizado server-side como data-URL e passado como prop.
|
|
180
181
|
const qrDataUrl = await QRCode.toDataURL(started.otpauthUri);
|
|
181
|
-
|
|
182
|
+
const props = {
|
|
182
183
|
csrfToken: ctx.request.csrfToken,
|
|
183
184
|
enabled: false,
|
|
184
185
|
enrolling: true,
|
|
185
186
|
secret: started.secret,
|
|
186
187
|
qrDataUrl,
|
|
187
188
|
recoveryCodes: null,
|
|
188
|
-
}
|
|
189
|
+
};
|
|
190
|
+
return render(ctx, 'account/mfa', props);
|
|
189
191
|
}
|
|
190
192
|
/** POST /account/mfa/confirm — confirma o código; sucesso = ativa e mostra recovery codes. */
|
|
191
193
|
async confirm(ctx) {
|
|
@@ -199,7 +201,7 @@ export default class AccountMfaController {
|
|
|
199
201
|
// Reenvia o passo de confirmação com erro SEM regenerar o segredo pendente
|
|
200
202
|
// (o usuário já escaneou o QR; um novo segredo invalidaria o app autenticador).
|
|
201
203
|
// Mostra só o campo de código para nova tentativa.
|
|
202
|
-
|
|
204
|
+
const props = {
|
|
203
205
|
csrfToken: ctx.request.csrfToken,
|
|
204
206
|
enabled: false,
|
|
205
207
|
enrolling: true,
|
|
@@ -207,7 +209,8 @@ export default class AccountMfaController {
|
|
|
207
209
|
qrDataUrl: null,
|
|
208
210
|
error: translate(cfg.messages, 'errors.invalid_code'),
|
|
209
211
|
recoveryCodes: null,
|
|
210
|
-
}
|
|
212
|
+
};
|
|
213
|
+
return render(ctx, 'account/mfa', props);
|
|
211
214
|
}
|
|
212
215
|
await cfg.audit?.record({
|
|
213
216
|
type: 'mfa.enabled',
|
|
@@ -65,7 +65,7 @@ export default class AccountSecurityController {
|
|
|
65
65
|
const ownSessions = sessionsSupported
|
|
66
66
|
? await enrichSessionsWithContext(cfg, userId, await adminSessions.listSessions(userId))
|
|
67
67
|
: [];
|
|
68
|
-
|
|
68
|
+
const props = {
|
|
69
69
|
csrfToken: ctx.request.csrfToken,
|
|
70
70
|
supported: supportsAccountSecurity(cfg.accountStore),
|
|
71
71
|
profileSupported: supportsProfile(cfg.accountStore),
|
|
@@ -94,7 +94,8 @@ export default class AccountSecurityController {
|
|
|
94
94
|
// Deleção de conta (LGPD): só quando o store suporta hard delete.
|
|
95
95
|
deletionSupported: supportsAccountDeletion(cfg.accountStore),
|
|
96
96
|
deleteError: ctx.session.flashMessages.get('deleteError') ?? null,
|
|
97
|
-
}
|
|
97
|
+
};
|
|
98
|
+
return render(ctx, 'account/security', props);
|
|
98
99
|
}
|
|
99
100
|
/**
|
|
100
101
|
* GET /account/security/export — baixa um JSON com os dados da conta logada
|
|
@@ -48,7 +48,11 @@ export default class AccountSessionController {
|
|
|
48
48
|
// Lê e valida o return_to da query-string — descarta valores inválidos (open-redirect).
|
|
49
49
|
const rawReturnTo = ctx.request.qs?.()?.return_to ?? ctx.request.input?.('return_to');
|
|
50
50
|
const returnTo = validateReturnTo(rawReturnTo);
|
|
51
|
-
|
|
51
|
+
const props = {
|
|
52
|
+
csrfToken: ctx.request.csrfToken,
|
|
53
|
+
returnTo,
|
|
54
|
+
};
|
|
55
|
+
return render(ctx, 'account/login', props);
|
|
52
56
|
}
|
|
53
57
|
async login(ctx) {
|
|
54
58
|
const service = await ctx.containerResolver.make('authkit.server');
|
|
@@ -74,7 +78,7 @@ export default class AccountSessionController {
|
|
|
74
78
|
settings: settings ?? undefined,
|
|
75
79
|
});
|
|
76
80
|
if (!result.ok) {
|
|
77
|
-
|
|
81
|
+
const props = {
|
|
78
82
|
csrfToken: ctx.request.csrfToken,
|
|
79
83
|
returnTo,
|
|
80
84
|
error: result.locked
|
|
@@ -84,7 +88,8 @@ export default class AccountSessionController {
|
|
|
84
88
|
: result.disabled
|
|
85
89
|
? translate(cfg.messages, 'errors.account_disabled')
|
|
86
90
|
: translate(cfg.messages, 'errors.invalid_credentials'),
|
|
87
|
-
}
|
|
91
|
+
};
|
|
92
|
+
return render(ctx, 'account/login', props);
|
|
88
93
|
}
|
|
89
94
|
const acc = result.account;
|
|
90
95
|
// M5 (session fixation): regenera a sessão IMEDIATAMENTE após autenticar e
|
|
@@ -58,76 +58,33 @@ export type AuthkitScreen = 'login' | 'signup' | 'consent' | 'forgot' | 'reset'
|
|
|
58
58
|
*
|
|
59
59
|
* ---
|
|
60
60
|
*
|
|
61
|
-
* ### Props
|
|
61
|
+
* ### Props das telas de conta — tipos exportados (fonte única)
|
|
62
62
|
*
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
63
|
+
* Um host que escreve as telas do console em React tipa cada página com os tipos
|
|
64
|
+
* de props exportados do pacote, em vez de copiar o shape à mão deste docblock —
|
|
65
|
+
* que já ficou desatualizado no passado. Cada tipo é a FONTE ÚNICA da verdade: os
|
|
66
|
+
* controllers satisfazem (`satisfies Omit<…, 'messages'>`) exatamente o mesmo
|
|
67
|
+
* tipo ao chamar `render()`, então divergência quebra o `tsc` do pacote. Ver
|
|
68
|
+
* `src/host/account_screen_props.ts`.
|
|
69
69
|
*
|
|
70
|
-
*
|
|
70
|
+
* | Tela | Tipo exportado |
|
|
71
|
+
* |---------------------------|----------------------------|
|
|
72
|
+
* | `account/login` | {@link AccountLoginProps} |
|
|
73
|
+
* | `account/security` | {@link AccountSecurityProps} |
|
|
74
|
+
* | `account/mfa` | {@link AccountMfaProps} |
|
|
75
|
+
* | `account/confirm` | {@link AccountConfirmProps} |
|
|
76
|
+
* | `account/email-confirmed` | {@link AccountEmailConfirmedProps} |
|
|
71
77
|
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
* | `supported` | `boolean` | `false` quando o store não suporta o self-service de segurança (troca de senha/e-mail) — a tela deve degradar. |
|
|
76
|
-
* | `profileSupported` | `boolean` | `true` quando o store suporta editar nome/avatar (`updateProfile`). |
|
|
77
|
-
* | `avatarUploadSupported` | `boolean` | `true` quando algum backend (drive OU media) pode armazenar o upload de avatar. |
|
|
78
|
-
* | `email` | `string` | E-mail atual da conta (`''` se ausente). |
|
|
79
|
-
* | `name` | `string` | Nome atual da conta (`''` se ausente). |
|
|
80
|
-
* | `avatarUrl` | `string` | URL do avatar atual (`''` se ausente). |
|
|
81
|
-
* | `passwordChanged` | `string \| null` | Flash de sucesso da troca de senha (mensagem localizada) ou `null`. |
|
|
82
|
-
* | `emailChangeRequested` | `string \| null` | Flash: link de confirmação de troca de e-mail enviado (ou cancelamento) ou `null`. |
|
|
83
|
-
* | `emailChanged` | `string \| null` | Flash: troca de e-mail concluída ou `null`. |
|
|
84
|
-
* | `profileUpdated` | `string \| null` | Flash: perfil atualizado ou `null`. |
|
|
85
|
-
* | `error` | `string \| null` | Flash de erro de segurança (senha inválida, e-mail em uso, política violada) ou `null`. |
|
|
86
|
-
* | `trustedDevicesEnabled` | `boolean` | `true` quando o recurso de dispositivos confiáveis está ligado. |
|
|
87
|
-
* | `trustedDevicesRevoked` | `string \| null` | Flash: confiança deste navegador revogada ou `null`. |
|
|
88
|
-
* | `sessionsSupported` | `boolean` | `true` quando o adapter OIDC enumera as sessões ativas da conta. |
|
|
89
|
-
* | `sessions` | `Array<{ loginTs: string; browser: string; os: string; ip: string; location: string }>` | Sessões ativas da própria conta (vazio quando não suportado). `loginTs` é ISO ou `''`. |
|
|
90
|
-
* | `exportSupported` | `boolean` | Sempre `true` — export de dados (portabilidade/LGPD) disponível para a conta logada. |
|
|
91
|
-
* | `deletionSupported` | `boolean` | `true` quando o store suporta hard delete (danger zone). |
|
|
92
|
-
* | `deleteError` | `string \| null` | Flash de erro da confirmação de deleção ou `null`. |
|
|
93
|
-
* | `messages` | `AuthMessages` | Catálogo de mensagens i18n. |
|
|
78
|
+
* A prop `messages` (catálogo i18n {@link AuthMessages}) é injetada por este
|
|
79
|
+
* renderer como shared prop e faz parte de todos esses tipos — os controllers,
|
|
80
|
+
* que não a passam, satisfazem `Omit<…, 'messages'>`.
|
|
94
81
|
*
|
|
95
|
-
*
|
|
82
|
+
* ```tsx
|
|
83
|
+
* import type { AccountSecurityProps } from '@adonis-agora/authkit-server'
|
|
96
84
|
*
|
|
97
|
-
*
|
|
98
|
-
*
|
|
99
|
-
*
|
|
100
|
-
*
|
|
101
|
-
* | Prop | Tipo | Descrição |
|
|
102
|
-
* |---------------------|---------------------|-----------|
|
|
103
|
-
* | `csrfToken` | `string` | Token CSRF para os formulários de enroll/confirm/disable e passkeys. |
|
|
104
|
-
* | `enabled` | `boolean` | `true` quando o TOTP já está confirmado (habilitado) para a conta. |
|
|
105
|
-
* | `recoveryCodes` | `string[] \| null` | Códigos de recuperação recém-gerados (exibidos UMA vez após enroll/confirm) ou `null`. |
|
|
106
|
-
* | `passkeysSupported` | `boolean` | `true` quando o store persiste credenciais WebAuthn (passkeys). |
|
|
107
|
-
* | `passkeys` | `Array<{ id: string; label?: string; createdAt: string }>` | Passkeys cadastradas (vazio quando não suportado). `id` é base64url; `createdAt` é ISO. Presente em `index`. |
|
|
108
|
-
* | `enrolling` | `boolean \| undefined` | `true` no passo de enrollment (após `POST /mfa/enroll` e na reexibição do `confirm` com código inválido) — a tela mostra o QR/segredo e o campo de código. Ausente em `index`. |
|
|
109
|
-
* | `secret` | `string \| null \| undefined` | Segredo TOTP em texto (base32) para entrada manual, exibido no passo de enroll. `null` na reexibição do `confirm` (o segredo pendente NÃO é regenerado). Ausente em `index`. |
|
|
110
|
-
* | `qrDataUrl` | `string \| null \| undefined` | QR code do `otpauth://` como data-URL (`<img src>`), no passo de enroll. `null` na reexibição do `confirm`. Ausente em `index`. |
|
|
111
|
-
* | `error` | `string \| undefined` | Mensagem de erro localizada (ex.: código TOTP inválido no `confirm`). Ausente quando não há erro. |
|
|
112
|
-
* | `messages` | `AuthMessages` | Catálogo de mensagens i18n. |
|
|
113
|
-
*
|
|
114
|
-
* ### Props da tela `account/confirm` (sudo — confirmar identidade)
|
|
115
|
-
*
|
|
116
|
-
* | Prop | Tipo | Descrição |
|
|
117
|
-
* |---------------|---------------------|-----------|
|
|
118
|
-
* | `csrfToken` | `string` | Token CSRF para o POST de cada método. |
|
|
119
|
-
* | `returnTo` | `string \| null` | Caminho interno de destino após confirmar (validado pelo servidor) ou `null`. |
|
|
120
|
-
* | `error` | `string \| null` | Flash de erro da última tentativa de confirmação ou `null`. |
|
|
121
|
-
* | `notice` | `string \| null` | Flash informativo (ex.: "link de confirmação enviado") ou `null`. |
|
|
122
|
-
* | `methods` | `Array<{ id: string; labelKey: string; kind: 'form' \| 'action' \| 'redirect' \| 'webauthn'; endpoint: string; fields?: Array<{ name: string; type: 'password' \| 'text'; labelKey: string }> }>` | Métodos de sudo disponíveis para a conta. A tela renderiza por `kind`; `endpoint` é o POST de verificação (`webauthn` pede options em `${endpoint}/options`). |
|
|
123
|
-
* | `preferredId` | `string \| null` | `id` do último método usado (destaque na UI) ou `null`. |
|
|
124
|
-
* | `messages` | `AuthMessages` | Catálogo de mensagens i18n. |
|
|
125
|
-
*
|
|
126
|
-
* ### Props da tela `account/email-confirmed` (terminal do link de troca de e-mail)
|
|
127
|
-
*
|
|
128
|
-
* | Prop | Tipo | Descrição |
|
|
129
|
-
* |------------|----------------|-----------|
|
|
130
|
-
* | `ok` | `boolean` | `true` quando o token era válido e o novo e-mail foi aplicado; `false` para token inválido/expirado ou store sem suporte. A tela mostra sucesso ou falha conforme o valor. |
|
|
131
|
-
* | `messages` | `AuthMessages` | Catálogo de mensagens i18n. |
|
|
85
|
+
* export default function Security(props: AccountSecurityProps) {
|
|
86
|
+
* return <form action="/account/security/password" method="post">…</form>
|
|
87
|
+
* }
|
|
88
|
+
* ```
|
|
132
89
|
*/
|
|
133
90
|
export declare function inertiaRenderer(opts: InertiaRendererOptions): (ctx: HttpContext, view: string, props: Record<string, unknown>) => Promise<any>;
|
|
@@ -29,77 +29,34 @@ async function resolveMessagesFromCtx(ctx) {
|
|
|
29
29
|
*
|
|
30
30
|
* ---
|
|
31
31
|
*
|
|
32
|
-
* ### Props
|
|
32
|
+
* ### Props das telas de conta — tipos exportados (fonte única)
|
|
33
33
|
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
34
|
+
* Um host que escreve as telas do console em React tipa cada página com os tipos
|
|
35
|
+
* de props exportados do pacote, em vez de copiar o shape à mão deste docblock —
|
|
36
|
+
* que já ficou desatualizado no passado. Cada tipo é a FONTE ÚNICA da verdade: os
|
|
37
|
+
* controllers satisfazem (`satisfies Omit<…, 'messages'>`) exatamente o mesmo
|
|
38
|
+
* tipo ao chamar `render()`, então divergência quebra o `tsc` do pacote. Ver
|
|
39
|
+
* `src/host/account_screen_props.ts`.
|
|
40
40
|
*
|
|
41
|
-
*
|
|
41
|
+
* | Tela | Tipo exportado |
|
|
42
|
+
* |---------------------------|----------------------------|
|
|
43
|
+
* | `account/login` | {@link AccountLoginProps} |
|
|
44
|
+
* | `account/security` | {@link AccountSecurityProps} |
|
|
45
|
+
* | `account/mfa` | {@link AccountMfaProps} |
|
|
46
|
+
* | `account/confirm` | {@link AccountConfirmProps} |
|
|
47
|
+
* | `account/email-confirmed` | {@link AccountEmailConfirmedProps} |
|
|
42
48
|
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
* | `supported` | `boolean` | `false` quando o store não suporta o self-service de segurança (troca de senha/e-mail) — a tela deve degradar. |
|
|
47
|
-
* | `profileSupported` | `boolean` | `true` quando o store suporta editar nome/avatar (`updateProfile`). |
|
|
48
|
-
* | `avatarUploadSupported` | `boolean` | `true` quando algum backend (drive OU media) pode armazenar o upload de avatar. |
|
|
49
|
-
* | `email` | `string` | E-mail atual da conta (`''` se ausente). |
|
|
50
|
-
* | `name` | `string` | Nome atual da conta (`''` se ausente). |
|
|
51
|
-
* | `avatarUrl` | `string` | URL do avatar atual (`''` se ausente). |
|
|
52
|
-
* | `passwordChanged` | `string \| null` | Flash de sucesso da troca de senha (mensagem localizada) ou `null`. |
|
|
53
|
-
* | `emailChangeRequested` | `string \| null` | Flash: link de confirmação de troca de e-mail enviado (ou cancelamento) ou `null`. |
|
|
54
|
-
* | `emailChanged` | `string \| null` | Flash: troca de e-mail concluída ou `null`. |
|
|
55
|
-
* | `profileUpdated` | `string \| null` | Flash: perfil atualizado ou `null`. |
|
|
56
|
-
* | `error` | `string \| null` | Flash de erro de segurança (senha inválida, e-mail em uso, política violada) ou `null`. |
|
|
57
|
-
* | `trustedDevicesEnabled` | `boolean` | `true` quando o recurso de dispositivos confiáveis está ligado. |
|
|
58
|
-
* | `trustedDevicesRevoked` | `string \| null` | Flash: confiança deste navegador revogada ou `null`. |
|
|
59
|
-
* | `sessionsSupported` | `boolean` | `true` quando o adapter OIDC enumera as sessões ativas da conta. |
|
|
60
|
-
* | `sessions` | `Array<{ loginTs: string; browser: string; os: string; ip: string; location: string }>` | Sessões ativas da própria conta (vazio quando não suportado). `loginTs` é ISO ou `''`. |
|
|
61
|
-
* | `exportSupported` | `boolean` | Sempre `true` — export de dados (portabilidade/LGPD) disponível para a conta logada. |
|
|
62
|
-
* | `deletionSupported` | `boolean` | `true` quando o store suporta hard delete (danger zone). |
|
|
63
|
-
* | `deleteError` | `string \| null` | Flash de erro da confirmação de deleção ou `null`. |
|
|
64
|
-
* | `messages` | `AuthMessages` | Catálogo de mensagens i18n. |
|
|
49
|
+
* A prop `messages` (catálogo i18n {@link AuthMessages}) é injetada por este
|
|
50
|
+
* renderer como shared prop e faz parte de todos esses tipos — os controllers,
|
|
51
|
+
* que não a passam, satisfazem `Omit<…, 'messages'>`.
|
|
65
52
|
*
|
|
66
|
-
*
|
|
53
|
+
* ```tsx
|
|
54
|
+
* import type { AccountSecurityProps } from '@adonis-agora/authkit-server'
|
|
67
55
|
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
* | Prop | Tipo | Descrição |
|
|
73
|
-
* |---------------------|---------------------|-----------|
|
|
74
|
-
* | `csrfToken` | `string` | Token CSRF para os formulários de enroll/confirm/disable e passkeys. |
|
|
75
|
-
* | `enabled` | `boolean` | `true` quando o TOTP já está confirmado (habilitado) para a conta. |
|
|
76
|
-
* | `recoveryCodes` | `string[] \| null` | Códigos de recuperação recém-gerados (exibidos UMA vez após enroll/confirm) ou `null`. |
|
|
77
|
-
* | `passkeysSupported` | `boolean` | `true` quando o store persiste credenciais WebAuthn (passkeys). |
|
|
78
|
-
* | `passkeys` | `Array<{ id: string; label?: string; createdAt: string }>` | Passkeys cadastradas (vazio quando não suportado). `id` é base64url; `createdAt` é ISO. Presente em `index`. |
|
|
79
|
-
* | `enrolling` | `boolean \| undefined` | `true` no passo de enrollment (após `POST /mfa/enroll` e na reexibição do `confirm` com código inválido) — a tela mostra o QR/segredo e o campo de código. Ausente em `index`. |
|
|
80
|
-
* | `secret` | `string \| null \| undefined` | Segredo TOTP em texto (base32) para entrada manual, exibido no passo de enroll. `null` na reexibição do `confirm` (o segredo pendente NÃO é regenerado). Ausente em `index`. |
|
|
81
|
-
* | `qrDataUrl` | `string \| null \| undefined` | QR code do `otpauth://` como data-URL (`<img src>`), no passo de enroll. `null` na reexibição do `confirm`. Ausente em `index`. |
|
|
82
|
-
* | `error` | `string \| undefined` | Mensagem de erro localizada (ex.: código TOTP inválido no `confirm`). Ausente quando não há erro. |
|
|
83
|
-
* | `messages` | `AuthMessages` | Catálogo de mensagens i18n. |
|
|
84
|
-
*
|
|
85
|
-
* ### Props da tela `account/confirm` (sudo — confirmar identidade)
|
|
86
|
-
*
|
|
87
|
-
* | Prop | Tipo | Descrição |
|
|
88
|
-
* |---------------|---------------------|-----------|
|
|
89
|
-
* | `csrfToken` | `string` | Token CSRF para o POST de cada método. |
|
|
90
|
-
* | `returnTo` | `string \| null` | Caminho interno de destino após confirmar (validado pelo servidor) ou `null`. |
|
|
91
|
-
* | `error` | `string \| null` | Flash de erro da última tentativa de confirmação ou `null`. |
|
|
92
|
-
* | `notice` | `string \| null` | Flash informativo (ex.: "link de confirmação enviado") ou `null`. |
|
|
93
|
-
* | `methods` | `Array<{ id: string; labelKey: string; kind: 'form' \| 'action' \| 'redirect' \| 'webauthn'; endpoint: string; fields?: Array<{ name: string; type: 'password' \| 'text'; labelKey: string }> }>` | Métodos de sudo disponíveis para a conta. A tela renderiza por `kind`; `endpoint` é o POST de verificação (`webauthn` pede options em `${endpoint}/options`). |
|
|
94
|
-
* | `preferredId` | `string \| null` | `id` do último método usado (destaque na UI) ou `null`. |
|
|
95
|
-
* | `messages` | `AuthMessages` | Catálogo de mensagens i18n. |
|
|
96
|
-
*
|
|
97
|
-
* ### Props da tela `account/email-confirmed` (terminal do link de troca de e-mail)
|
|
98
|
-
*
|
|
99
|
-
* | Prop | Tipo | Descrição |
|
|
100
|
-
* |------------|----------------|-----------|
|
|
101
|
-
* | `ok` | `boolean` | `true` quando o token era válido e o novo e-mail foi aplicado; `false` para token inválido/expirado ou store sem suporte. A tela mostra sucesso ou falha conforme o valor. |
|
|
102
|
-
* | `messages` | `AuthMessages` | Catálogo de mensagens i18n. |
|
|
56
|
+
* export default function Security(props: AccountSecurityProps) {
|
|
57
|
+
* return <form action="/account/security/password" method="post">…</form>
|
|
58
|
+
* }
|
|
59
|
+
* ```
|
|
103
60
|
*/
|
|
104
61
|
export function inertiaRenderer(opts) {
|
|
105
62
|
const allowed = opts.views ? new Set(opts.views) : null;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adonis-agora/authkit-server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.49.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",
|
|
@@ -148,7 +148,7 @@
|
|
|
148
148
|
"react-error-boundary": "6.1.2",
|
|
149
149
|
"nuqs": "2.8.9",
|
|
150
150
|
"recharts": "3.8.1",
|
|
151
|
-
"@adonis-agora/authkit-react": "0.
|
|
151
|
+
"@adonis-agora/authkit-react": "0.17.0"
|
|
152
152
|
},
|
|
153
153
|
"scripts": {
|
|
154
154
|
"build": "node scripts/build_host_css.mjs && node scripts/build_webauthn.mjs && node scripts/build_ui.mjs && node -e \"const fs=require('node:fs');for(const d of ['build/stubs','build/host/views'])fs.rmSync(d,{recursive:true,force:true})\" && tsc && node -e \"require('node:fs').cpSync('src/host/assets','build/src/host/assets',{recursive:true})\" && node -e \"require('node:fs').cpSync('stubs','build/stubs',{recursive:true,filter:(s)=>!s.endsWith('.ts')})\" && node -e \"const fs=require('node:fs');if(fs.existsSync('assets'))fs.cpSync('assets','build/assets',{recursive:true})\" && node -e \"require('node:fs').cpSync('src/host/views','build/host/views',{recursive:true})\" && node -e \"const fs=require('node:fs');fs.mkdirSync('build/host/ui',{recursive:true});fs.readdirSync('src/host/ui').filter(f=>f.endsWith('.html')).forEach(f=>fs.copyFileSync('src/host/ui/'+f,'build/host/ui/'+f))\" && node -e \"require('node:fs').copyFileSync('commands/commands.json','build/commands/commands.json')\" && node -e \"const fs=require('node:fs');fs.mkdirSync('build/password',{recursive:true});fs.copyFileSync('src/password/common_passwords.txt','build/password/common_passwords.txt')\"",
|