@adonis-agora/authkit-server 0.90.1 → 1.0.0-rc.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/CHANGELOG.md +3637 -0
- package/build/commands/clients_create.d.ts +1 -0
- package/build/commands/clients_create.js +15 -2
- package/build/commands/commands.json +7 -0
- package/build/host/ui/admin.html +1 -1
- package/build/host/views/account/apps.edge +8 -3
- package/build/host/views/partials/styles.edge +2 -2
- package/build/index.d.ts +3 -3
- package/build/index.js +3 -5
- package/build/src/accounts/lucid_account_store.d.ts +0 -18
- package/build/src/accounts/lucid_account_store.js +7 -48
- package/build/src/accounts/lucid_store/mfa.js +1 -1
- package/build/src/accounts/lucid_store/organizations.d.ts +1 -1
- package/build/src/accounts/lucid_store/password_hygiene.d.ts +2 -3
- package/build/src/accounts/lucid_store/password_hygiene.js +2 -3
- package/build/src/accounts/lucid_store/shared.d.ts +0 -7
- package/build/src/accounts/lucid_store/shared.js +0 -14
- package/build/src/accounts/lucid_stores.d.ts +1 -1
- package/build/src/adapters/redis_adapter.js +12 -2
- package/build/src/define_config.d.ts +6 -12
- package/build/src/define_config.js +3 -2
- package/build/src/doctor/checks.d.ts +3 -4
- package/build/src/doctor/checks.js +5 -7
- package/build/src/host/account_api/account_api_controller.d.ts +2 -1
- package/build/src/host/account_api/account_api_controller.js +5 -11
- package/build/src/host/admin_api/api_clients_controller.d.ts +9 -3
- package/build/src/host/admin_api/dto.d.ts +3 -1
- package/build/src/host/admin_api/dto.js +3 -1
- package/build/src/host/admin_clients_service.d.ts +13 -5
- package/build/src/host/admin_clients_service.js +18 -5
- package/build/src/host/admin_console/admin_shell_controller.d.ts +16 -1
- package/build/src/host/admin_console/admin_shell_controller.js +21 -7
- package/build/src/host/admin_console/console_clients_controller.d.ts +21 -2
- package/build/src/host/admin_console/console_clients_controller.js +9 -0
- package/build/src/host/admin_console/console_impersonation_controller.js +3 -8
- package/build/src/host/admin_console/console_overview_controller.d.ts +2 -2
- package/build/src/host/admin_console/console_overview_controller.js +4 -2
- package/build/src/host/admin_validators.d.ts +15 -11
- package/build/src/host/admin_validators.js +16 -9
- package/build/src/host/client_names.d.ts +9 -2
- package/build/src/host/client_names.js +11 -3
- package/build/src/host/consent_params.d.ts +7 -0
- package/build/src/host/consent_params.js +27 -0
- package/build/src/host/controllers/account_apps_controller.js +4 -3
- package/build/src/host/controllers/account_confirm_controller.d.ts +0 -7
- package/build/src/host/controllers/account_confirm_controller.js +0 -6
- package/build/src/host/controllers/account_orgs_controller.d.ts +0 -50
- package/build/src/host/controllers/account_orgs_controller.js +7 -113
- package/build/src/host/controllers/account_security_controller.js +7 -11
- package/build/src/host/controllers/agent_consent_controller.js +23 -5
- package/build/src/host/controllers/interaction_controller.js +6 -2
- package/build/src/host/controllers/poppy_consent_controller.js +33 -7
- package/build/src/host/controllers/registration_controller.js +7 -2
- package/build/src/host/i18n.d.ts +0 -4
- package/build/src/host/i18n.js +0 -6
- package/build/src/host/impersonation.d.ts +7 -15
- package/build/src/host/impersonation.js +7 -16
- package/build/src/host/interaction_recovery.js +4 -1
- package/build/src/host/login_attempt.js +5 -1
- package/build/src/host/middleware/account_auth.js +6 -0
- package/build/src/host/rate_limit.js +5 -1
- package/build/src/host/register_auth_host.d.ts +6 -0
- package/build/src/host/register_auth_host.js +32 -8
- package/build/src/host/renderers/inertia_renderer.d.ts +9 -21
- package/build/src/host/renderers/inertia_renderer.js +5 -6
- package/build/src/host/screen_props.d.ts +309 -0
- package/build/src/host/screen_props.js +11 -0
- package/build/src/host/sudo_mode.d.ts +5 -11
- package/build/src/host/sudo_mode.js +5 -11
- package/build/src/host/ui-dist/assets/index-D0EIeyKK.js +67 -0
- package/build/src/host/ui-dist/index.html +1 -1
- package/build/src/password/password_manager.js +5 -0
- package/build/src/provider/build_provider.js +0 -34
- package/build/src/provider/oidc_service.d.ts +0 -2
- package/build/src/provider/oidc_service.js +1 -12
- package/build/src/provider/token_exchange.d.ts +1 -3
- package/build/src/provider/token_exchange.js +1 -1
- package/build/stubs/config/authkit_react.stub +3 -3
- package/package.json +18 -17
- package/skills/authkit-interactions/SKILL.md +32 -5
- package/stubs/config/authkit_react.stub +3 -3
- package/build/src/commands/import_clients.d.ts +0 -40
- package/build/src/commands/import_clients.js +0 -81
- package/build/src/host/ui-dist/assets/index-C180q-la.js +0 -67
- package/build/src/mixins/with_mfa.d.ts +0 -35
- package/build/src/mixins/with_mfa.js +0 -21
|
@@ -58,10 +58,15 @@ export default class AuthkitClientsCreate extends BaseCommand {
|
|
|
58
58
|
const isPublic = !!this.public || !!this.native;
|
|
59
59
|
const applicationType = this.native ? 'native' : 'web';
|
|
60
60
|
const tokenEndpointAuthMethod = isPublic ? 'none' : 'client_secret_basic';
|
|
61
|
+
if (isPublic && this.clientSecret) {
|
|
62
|
+
this.logger.logError('❌ --client-secret não se aplica a um client público (--public/--native).');
|
|
63
|
+
this.exitCode = 1;
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
61
66
|
const { ClientMetadataError } = await import('../src/host/client_metadata.js');
|
|
62
67
|
let created;
|
|
63
68
|
try {
|
|
64
|
-
|
|
69
|
+
const input = {
|
|
65
70
|
clientId: this.clientId,
|
|
66
71
|
applicationType,
|
|
67
72
|
redirectUris,
|
|
@@ -69,7 +74,10 @@ export default class AuthkitClientsCreate extends BaseCommand {
|
|
|
69
74
|
grantTypes,
|
|
70
75
|
tokenEndpointAuthMethod,
|
|
71
76
|
backchannelLogoutUri: this.backchannelLogoutUri,
|
|
72
|
-
}
|
|
77
|
+
};
|
|
78
|
+
created = this.clientSecret
|
|
79
|
+
? await svc.createWithSecret(input, this.clientSecret)
|
|
80
|
+
: await svc.create(input);
|
|
73
81
|
}
|
|
74
82
|
catch (err) {
|
|
75
83
|
if (err instanceof ClientMetadataError) {
|
|
@@ -142,6 +150,11 @@ __decorate([
|
|
|
142
150
|
description: 'Endpoint de OIDC Back-Channel Logout do RP (POST de logout_token).',
|
|
143
151
|
})
|
|
144
152
|
], AuthkitClientsCreate.prototype, "backchannelLogoutUri", void 0);
|
|
153
|
+
__decorate([
|
|
154
|
+
flags.string({
|
|
155
|
+
description: 'Usa este client_secret em vez de gerar um (client confidencial). Útil para manter o secret que os RPs já usam.',
|
|
156
|
+
})
|
|
157
|
+
], AuthkitClientsCreate.prototype, "clientSecret", void 0);
|
|
145
158
|
__decorate([
|
|
146
159
|
flags.boolean({
|
|
147
160
|
description: 'Output em JSON machine-readable (inclui clientId e clientSecret).',
|
|
@@ -123,6 +123,13 @@
|
|
|
123
123
|
"type": "string",
|
|
124
124
|
"description": "Endpoint de OIDC Back-Channel Logout do RP."
|
|
125
125
|
},
|
|
126
|
+
{
|
|
127
|
+
"name": "clientSecret",
|
|
128
|
+
"flagName": "client-secret",
|
|
129
|
+
"required": false,
|
|
130
|
+
"type": "string",
|
|
131
|
+
"description": "Usa este client_secret em vez de gerar um (client confidencial)."
|
|
132
|
+
},
|
|
126
133
|
{
|
|
127
134
|
"name": "json",
|
|
128
135
|
"flagName": "json",
|
package/build/host/ui/admin.html
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
<!--
|
|
18
18
|
AuthKit Admin Console — React SPA shell.
|
|
19
19
|
Mission B will replace this placeholder with the full bundled React SPA.
|
|
20
|
-
The server
|
|
20
|
+
The server embeds the #authkit-admin-config JSON data block before this comment (see admin_shell_controller.ts).
|
|
21
21
|
-->
|
|
22
22
|
<div id="app">
|
|
23
23
|
<div class="loading">
|
|
@@ -40,9 +40,14 @@
|
|
|
40
40
|
@else
|
|
41
41
|
@each(app in apps)
|
|
42
42
|
<div class="flex items-center justify-between border-b border-gray-100 p-4 last:border-0">
|
|
43
|
-
<div>
|
|
44
|
-
|
|
45
|
-
|
|
43
|
+
<div class="flex items-center gap-3">
|
|
44
|
+
@if(app.logoUrl)
|
|
45
|
+
<img src="{{ app.logoUrl }}" alt="" class="h-8 w-8 rounded-md object-contain">
|
|
46
|
+
@end
|
|
47
|
+
<div>
|
|
48
|
+
<p class="text-sm font-medium text-gray-900">{{ app.name }}</p>
|
|
49
|
+
<p class="text-xs text-gray-500">{{ t('account.apps.tokens', { accessTokens: app.accessTokens, refreshTokens: app.refreshTokens }) }}</p>
|
|
50
|
+
</div>
|
|
46
51
|
</div>
|
|
47
52
|
<form method="POST" action="{{ accountPaths?.apps ?? '/account/apps' }}/{{ app.clientId }}/revoke"
|
|
48
53
|
onsubmit="return confirm('{{ t('account.apps.revoke_confirm') }}')">
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
{{-- Gerado por scripts/build_host_css.mjs — não editar à mão. --}}
|
|
2
|
-
<style>/*! tailwindcss v4.3.
|
|
3
|
-
@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-space-y-reverse:0;--tw-divide-y-reverse:0;--tw-border-style:solid;--tw-font-weight:initial;--tw-tracking:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000}}}@layer theme{:root,:host{--font-sans:-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-red-50:oklch(97.1% .013 17.38);--color-red-100:oklch(93.6% .032 17.717);--color-red-200:oklch(88.5% .062 18.334);--color-red-300:oklch(80.8% .114 19.571);--color-red-600:oklch(57.7% .245 27.325);--color-red-700:oklch(50.5% .213 27.518);--color-red-800:oklch(44.4% .177 26.899);--color-red-900:oklch(39.6% .141 25.723);--color-amber-50:oklch(98.7% .022 95.277);--color-amber-100:oklch(96.2% .059 95.617);--color-amber-200:oklch(92.4% .12 95.746);--color-amber-600:oklch(66.6% .179 58.318);--color-amber-800:oklch(47.3% .137 46.201);--color-green-50:oklch(98.2% .018 155.826);--color-green-700:oklch(52.7% .154 150.069);--color-emerald-50:oklch(97.9% .021 166.113);--color-emerald-100:oklch(95% .052 163.051);--color-emerald-200:oklch(90.5% .093 164.15);--color-emerald-300:oklch(84.5% .143 164.978);--color-emerald-600:oklch(59.6% .145 163.225);--color-emerald-700:oklch(50.8% .118 165.612);--color-emerald-800:oklch(43.2% .095 166.913);--color-emerald-900:oklch(37.8% .077 168.94);--color-blue-50:oklch(97% .014 254.604);--color-blue-200:oklch(88.2% .059 254.128);--color-blue-300:oklch(80.9% .105 251.813);--color-blue-800:oklch(42.4% .199 265.638);--color-blue-900:oklch(37.9% .146 265.522);--color-gray-50:oklch(98.5% .002 247.839);--color-gray-100:oklch(96.7% .003 264.542);--color-gray-200:oklch(92.8% .006 264.531);--color-gray-300:oklch(87.2% .01 258.338);--color-gray-400:oklch(70.7% .022 261.325);--color-gray-500:oklch(55.1% .027 264.364);--color-gray-600:oklch(44.6% .03 256.802);--color-gray-700:oklch(37.3% .034 259.733);--color-gray-800:oklch(27.8% .033 256.848);--color-gray-900:oklch(21% .034 264.665);--color-black:#000;--color-white:#fff;--spacing:.25rem;--container-sm:24rem;--container-md:28rem;--container-2xl:42rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-base:1rem;--text-base--line-height:calc(1.5 / 1);--text-lg:1.125rem;--text-lg--line-height:calc(1.75 / 1.125);--text-xl:1.25rem;--text-xl--line-height:calc(1.75 / 1.25);--font-weight-medium:500;--font-weight-semibold:600;--tracking-wide:.025em;--tracking-widest:.1em;--radius-lg:.5rem;--radius-xl:.75rem;--radius-2xl:1rem;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring:where(:not(iframe)){outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}button:not(:disabled),[role=button]:not(:disabled){cursor:pointer}}@layer components;@layer utilities{.pointer-events-none{pointer-events:none}.absolute{position:absolute}.relative{position:relative}.top-1\/2{top:50%}.right-2{right:calc(var(--spacing) * 2)}.container{width:100%}@media (min-width:40rem){.container{max-width:40rem}}@media (min-width:48rem){.container{max-width:48rem}}@media (min-width:64rem){.container{max-width:64rem}}@media (min-width:80rem){.container{max-width:80rem}}@media (min-width:96rem){.container{max-width:96rem}}.mx-auto{margin-inline:auto}.my-4{margin-block:calc(var(--spacing) * 4)}.my-6{margin-block:calc(var(--spacing) * 6)}.mt-0\.5{margin-top:calc(var(--spacing) * .5)}.mt-1{margin-top:var(--spacing)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-3{margin-top:calc(var(--spacing) * 3)}.mt-4{margin-top:calc(var(--spacing) * 4)}.mt-6{margin-top:calc(var(--spacing) * 6)}.mt-8{margin-top:calc(var(--spacing) * 8)}.mb-1{margin-bottom:var(--spacing)}.mb-2{margin-bottom:calc(var(--spacing) * 2)}.mb-3{margin-bottom:calc(var(--spacing) * 3)}.mb-4{margin-bottom:calc(var(--spacing) * 4)}.mb-6{margin-bottom:calc(var(--spacing) * 6)}.block{display:block}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline{display:inline}.inline-block{display:inline-block}.inline-flex{display:inline-flex}.h-4{height:calc(var(--spacing) * 4)}.h-6{height:calc(var(--spacing) * 6)}.h-12{height:calc(var(--spacing) * 12)}.h-16{height:calc(var(--spacing) * 16)}.h-48{height:calc(var(--spacing) * 48)}.h-px{height:1px}.min-h-screen{min-height:100vh}.w-4{width:calc(var(--spacing) * 4)}.w-6{width:calc(var(--spacing) * 6)}.w-12{width:calc(var(--spacing) * 12)}.w-16{width:calc(var(--spacing) * 16)}.w-48{width:calc(var(--spacing) * 48)}.w-fit{width:fit-content}.w-full{width:100%}.max-w-2xl{max-width:var(--container-2xl)}.max-w-md{max-width:var(--container-md)}.max-w-sm{max-width:var(--container-sm)}.flex-1{flex:1}.-translate-y-1\/2{--tw-translate-y:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.cursor-pointer{cursor:pointer}.list-inside{list-style-position:inside}.list-disc{list-style-type:disc}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.items-center{align-items:center}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.gap-2{gap:calc(var(--spacing) * 2)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-4{gap:calc(var(--spacing) * 4)}:where(.space-y-1>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(var(--spacing) * var(--tw-space-y-reverse));margin-block-end:calc(var(--spacing) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-2>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 2) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 2) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-3>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 3) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 3) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-4>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 4) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 4) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-6>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 6) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 6) * calc(1 - var(--tw-space-y-reverse)))}:where(.divide-y>:not(:last-child)){--tw-divide-y-reverse:0;border-bottom-style:var(--tw-border-style);border-top-style:var(--tw-border-style);border-top-width:calc(1px * var(--tw-divide-y-reverse));border-bottom-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)))}:where(.divide-gray-100>:not(:last-child)){border-color:var(--color-gray-100)}.overflow-hidden{overflow:hidden}.rounded{border-radius:.25rem}.rounded-2xl{border-radius:var(--radius-2xl)}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-xl{border-radius:var(--radius-xl)}.border{border-style:var(--tw-border-style);border-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-blue-300{border-color:var(--color-blue-300)}.border-emerald-300{border-color:var(--color-emerald-300)}.border-gray-100{border-color:var(--color-gray-100)}.border-gray-200{border-color:var(--color-gray-200)}.border-gray-300{border-color:var(--color-gray-300)}.border-gray-900{border-color:var(--color-gray-900)}.border-red-200{border-color:var(--color-red-200)}.border-red-300{border-color:var(--color-red-300)}.bg-amber-50{background-color:var(--color-amber-50)}.bg-amber-100{background-color:var(--color-amber-100)}.bg-blue-50{background-color:var(--color-blue-50)}.bg-emerald-50{background-color:var(--color-emerald-50)}.bg-emerald-100{background-color:var(--color-emerald-100)}.bg-gray-50{background-color:var(--color-gray-50)}.bg-gray-100{background-color:var(--color-gray-100)}.bg-gray-200{background-color:var(--color-gray-200)}.bg-gray-800{background-color:var(--color-gray-800)}.bg-gray-900{background-color:var(--color-gray-900)}.bg-green-50{background-color:var(--color-green-50)}.bg-red-50{background-color:var(--color-red-50)}.bg-red-100{background-color:var(--color-red-100)}.bg-red-600{background-color:var(--color-red-600)}.bg-white{background-color:var(--color-white)}.object-cover{object-fit:cover}.p-3{padding:calc(var(--spacing) * 3)}.p-4{padding:calc(var(--spacing) * 4)}.p-6{padding:calc(var(--spacing) * 6)}.p-8{padding:calc(var(--spacing) * 8)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-1\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-2\.5{padding-block:calc(var(--spacing) * 2.5)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-6{padding-block:calc(var(--spacing) * 6)}.text-center{text-align:center}.text-left{text-align:left}.font-mono{font-family:var(--font-mono)}.text-base{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}.text-lg{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xl{font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\[11px\]{font-size:11px}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-\[0\.4em\]{--tw-tracking:.4em;letter-spacing:.4em}.tracking-wide{--tw-tracking:var(--tracking-wide);letter-spacing:var(--tracking-wide)}.tracking-widest{--tw-tracking:var(--tracking-widest);letter-spacing:var(--tracking-widest)}.break-all{word-break:break-all}.text-amber-600{color:var(--color-amber-600)}.text-amber-800{color:var(--color-amber-800)}.text-blue-800{color:var(--color-blue-800)}.text-blue-900{color:var(--color-blue-900)}.text-emerald-600{color:var(--color-emerald-600)}.text-emerald-700{color:var(--color-emerald-700)}.text-emerald-800{color:var(--color-emerald-800)}.text-emerald-900{color:var(--color-emerald-900)}.text-gray-400{color:var(--color-gray-400)}.text-gray-500{color:var(--color-gray-500)}.text-gray-600{color:var(--color-gray-600)}.text-gray-700{color:var(--color-gray-700)}.text-gray-800{color:var(--color-gray-800)}.text-gray-900{color:var(--color-gray-900)}.text-green-700{color:var(--color-green-700)}.text-red-600{color:var(--color-red-600)}.text-red-700{color:var(--color-red-700)}.text-red-800{color:var(--color-red-800)}.text-red-900{color:var(--color-red-900)}.text-white{color:var(--color-white)}.uppercase{text-transform:uppercase}.underline{text-decoration-line:underline}.shadow-xl{--tw-shadow:0 20px 25px -5px var(--tw-shadow-color,#0000001a), 0 8px 10px -6px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-xs{--tw-shadow:0 1px 2px 0 var(--tw-shadow-color,#0000000d);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ring-1{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ring-amber-200{--tw-ring-color:var(--color-amber-200)}.ring-black\/5{--tw-ring-color:#0000000d}@supports (color:color-mix(in lab, red, red)){.ring-black\/5{--tw-ring-color:color-mix(in oklab, var(--color-black) 5%, transparent)}}.ring-blue-200{--tw-ring-color:var(--color-blue-200)}.ring-emerald-200{--tw-ring-color:var(--color-emerald-200)}.ring-gray-900{--tw-ring-color:var(--color-gray-900)}.ring-red-200{--tw-ring-color:var(--color-red-200)}.outline-hidden{--tw-outline-style:none;outline-style:none}@media (forced-colors:active){.outline-hidden{outline-offset:2px;outline:2px solid #0000}}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.select-none{-webkit-user-select:none;user-select:none}.last\:border-0:last-child{border-style:var(--tw-border-style);border-width:0}@media (hover:hover){.hover\:bg-gray-50:hover{background-color:var(--color-gray-50)}.hover\:bg-gray-700:hover{background-color:var(--color-gray-700)}.hover\:bg-red-50:hover{background-color:var(--color-red-50)}.hover\:bg-red-700:hover{background-color:var(--color-red-700)}.hover\:text-gray-600:hover{color:var(--color-gray-600)}.hover\:underline:hover{text-decoration-line:underline}.hover\:opacity-90:hover{opacity:.9}}.focus\:border-gray-900:focus{border-color:var(--color-gray-900)}.focus\:border-red-600:focus{border-color:var(--color-red-600)}.focus\:ring-2:focus{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.focus\:ring-gray-900:focus{--tw-ring-color:var(--color-gray-900)}}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-divide-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}</style>
|
|
2
|
+
<style>/*! tailwindcss v4.3.5 | MIT License | https://tailwindcss.com */
|
|
3
|
+
@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:block))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-space-y-reverse:0;--tw-divide-y-reverse:0;--tw-border-style:solid;--tw-font-weight:initial;--tw-tracking:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000}}}@layer theme{:root,:host{--font-sans:-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-red-50:oklch(97.1% .013 17.38);--color-red-100:oklch(93.6% .032 17.717);--color-red-200:oklch(88.5% .062 18.334);--color-red-300:oklch(80.8% .114 19.571);--color-red-600:oklch(57.7% .245 27.325);--color-red-700:oklch(50.5% .213 27.518);--color-red-800:oklch(44.4% .177 26.899);--color-red-900:oklch(39.6% .141 25.723);--color-amber-50:oklch(98.7% .022 95.277);--color-amber-100:oklch(96.2% .059 95.617);--color-amber-200:oklch(92.4% .12 95.746);--color-amber-600:oklch(66.6% .179 58.318);--color-amber-800:oklch(47.3% .137 46.201);--color-green-50:oklch(98.2% .018 155.826);--color-green-700:oklch(52.7% .154 150.069);--color-emerald-50:oklch(97.9% .021 166.113);--color-emerald-100:oklch(95% .052 163.051);--color-emerald-200:oklch(90.5% .093 164.15);--color-emerald-300:oklch(84.5% .143 164.978);--color-emerald-600:oklch(59.6% .145 163.225);--color-emerald-700:oklch(50.8% .118 165.612);--color-emerald-800:oklch(43.2% .095 166.913);--color-emerald-900:oklch(37.8% .077 168.94);--color-blue-50:oklch(97% .014 254.604);--color-blue-200:oklch(88.2% .059 254.128);--color-blue-300:oklch(80.9% .105 251.813);--color-blue-800:oklch(42.4% .199 265.638);--color-blue-900:oklch(37.9% .146 265.522);--color-gray-50:oklch(98.5% .002 247.839);--color-gray-100:oklch(96.7% .003 264.542);--color-gray-200:oklch(92.8% .006 264.531);--color-gray-300:oklch(87.2% .01 258.338);--color-gray-400:oklch(70.7% .022 261.325);--color-gray-500:oklch(55.1% .027 264.364);--color-gray-600:oklch(44.6% .03 256.802);--color-gray-700:oklch(37.3% .034 259.733);--color-gray-800:oklch(27.8% .033 256.848);--color-gray-900:oklch(21% .034 264.665);--color-black:#000;--color-white:#fff;--spacing:.25rem;--container-sm:24rem;--container-md:28rem;--container-2xl:42rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-base:1rem;--text-base--line-height:calc(1.5 / 1);--text-lg:1.125rem;--text-lg--line-height:calc(1.75 / 1.125);--text-xl:1.25rem;--text-xl--line-height:calc(1.75 / 1.25);--font-weight-medium:500;--font-weight-semibold:600;--tracking-wide:.025em;--tracking-widest:.1em;--radius-md:.375rem;--radius-lg:.5rem;--radius-xl:.75rem;--radius-2xl:1rem;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring:where(:not(iframe)){outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}button:not(:disabled),[role=button]:not(:disabled){cursor:pointer}}@layer components;@layer utilities{.pointer-events-none{pointer-events:none}.absolute{position:absolute}.relative{position:relative}.top-1\/2{top:50%}.right-2{right:calc(var(--spacing) * 2)}.container{width:100%}@media (min-width:40rem){.container{max-width:40rem}}@media (min-width:48rem){.container{max-width:48rem}}@media (min-width:64rem){.container{max-width:64rem}}@media (min-width:80rem){.container{max-width:80rem}}@media (min-width:96rem){.container{max-width:96rem}}.mx-auto{margin-inline:auto}.my-4{margin-block:calc(var(--spacing) * 4)}.my-6{margin-block:calc(var(--spacing) * 6)}.mt-0\.5{margin-top:calc(var(--spacing) * .5)}.mt-1{margin-top:var(--spacing)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-3{margin-top:calc(var(--spacing) * 3)}.mt-4{margin-top:calc(var(--spacing) * 4)}.mt-6{margin-top:calc(var(--spacing) * 6)}.mt-8{margin-top:calc(var(--spacing) * 8)}.mb-1{margin-bottom:var(--spacing)}.mb-2{margin-bottom:calc(var(--spacing) * 2)}.mb-3{margin-bottom:calc(var(--spacing) * 3)}.mb-4{margin-bottom:calc(var(--spacing) * 4)}.mb-6{margin-bottom:calc(var(--spacing) * 6)}.block{display:block}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline{display:inline}.inline-block{display:inline-block}.inline-flex{display:inline-flex}.h-4{height:calc(var(--spacing) * 4)}.h-6{height:calc(var(--spacing) * 6)}.h-8{height:calc(var(--spacing) * 8)}.h-12{height:calc(var(--spacing) * 12)}.h-16{height:calc(var(--spacing) * 16)}.h-48{height:calc(var(--spacing) * 48)}.h-px{height:1px}.min-h-screen{min-height:100vh}.w-4{width:calc(var(--spacing) * 4)}.w-6{width:calc(var(--spacing) * 6)}.w-8{width:calc(var(--spacing) * 8)}.w-12{width:calc(var(--spacing) * 12)}.w-16{width:calc(var(--spacing) * 16)}.w-48{width:calc(var(--spacing) * 48)}.w-fit{width:fit-content}.w-full{width:100%}.max-w-2xl{max-width:var(--container-2xl)}.max-w-md{max-width:var(--container-md)}.max-w-sm{max-width:var(--container-sm)}.flex-1{flex:1}.-translate-y-1\/2{--tw-translate-y:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.cursor-pointer{cursor:pointer}.list-inside{list-style-position:inside}.list-disc{list-style-type:disc}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.items-center{align-items:center}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.gap-2{gap:calc(var(--spacing) * 2)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-4{gap:calc(var(--spacing) * 4)}:where(.space-y-1>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(var(--spacing) * var(--tw-space-y-reverse));margin-block-end:calc(var(--spacing) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-2>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 2) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 2) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-3>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 3) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 3) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-4>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 4) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 4) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-6>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 6) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 6) * calc(1 - var(--tw-space-y-reverse)))}:where(.divide-y>:not(:last-child)){--tw-divide-y-reverse:0;border-bottom-style:var(--tw-border-style);border-top-style:var(--tw-border-style);border-top-width:calc(1px * var(--tw-divide-y-reverse));border-bottom-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)))}:where(.divide-gray-100>:not(:last-child)){border-color:var(--color-gray-100)}.overflow-hidden{overflow:hidden}.rounded{border-radius:.25rem}.rounded-2xl{border-radius:var(--radius-2xl)}.rounded-full{border-radius:2147483647px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.rounded-xl{border-radius:var(--radius-xl)}.border{border-style:var(--tw-border-style);border-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-blue-300{border-color:var(--color-blue-300)}.border-emerald-300{border-color:var(--color-emerald-300)}.border-gray-100{border-color:var(--color-gray-100)}.border-gray-200{border-color:var(--color-gray-200)}.border-gray-300{border-color:var(--color-gray-300)}.border-gray-900{border-color:var(--color-gray-900)}.border-red-200{border-color:var(--color-red-200)}.border-red-300{border-color:var(--color-red-300)}.bg-amber-50{background-color:var(--color-amber-50)}.bg-amber-100{background-color:var(--color-amber-100)}.bg-blue-50{background-color:var(--color-blue-50)}.bg-emerald-50{background-color:var(--color-emerald-50)}.bg-emerald-100{background-color:var(--color-emerald-100)}.bg-gray-50{background-color:var(--color-gray-50)}.bg-gray-100{background-color:var(--color-gray-100)}.bg-gray-200{background-color:var(--color-gray-200)}.bg-gray-800{background-color:var(--color-gray-800)}.bg-gray-900{background-color:var(--color-gray-900)}.bg-green-50{background-color:var(--color-green-50)}.bg-red-50{background-color:var(--color-red-50)}.bg-red-100{background-color:var(--color-red-100)}.bg-red-600{background-color:var(--color-red-600)}.bg-white{background-color:var(--color-white)}.object-contain{object-fit:contain}.object-cover{object-fit:cover}.p-3{padding:calc(var(--spacing) * 3)}.p-4{padding:calc(var(--spacing) * 4)}.p-6{padding:calc(var(--spacing) * 6)}.p-8{padding:calc(var(--spacing) * 8)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-1\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-2\.5{padding-block:calc(var(--spacing) * 2.5)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-6{padding-block:calc(var(--spacing) * 6)}.text-center{text-align:center}.text-left{text-align:left}.font-mono{font-family:var(--font-mono)}.text-base{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}.text-lg{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xl{font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\[11px\]{font-size:11px}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-\[0\.4em\]{--tw-tracking:.4em;letter-spacing:.4em}.tracking-wide{--tw-tracking:var(--tracking-wide);letter-spacing:var(--tracking-wide)}.tracking-widest{--tw-tracking:var(--tracking-widest);letter-spacing:var(--tracking-widest)}.break-all{word-break:break-all}.text-amber-600{color:var(--color-amber-600)}.text-amber-800{color:var(--color-amber-800)}.text-blue-800{color:var(--color-blue-800)}.text-blue-900{color:var(--color-blue-900)}.text-emerald-600{color:var(--color-emerald-600)}.text-emerald-700{color:var(--color-emerald-700)}.text-emerald-800{color:var(--color-emerald-800)}.text-emerald-900{color:var(--color-emerald-900)}.text-gray-400{color:var(--color-gray-400)}.text-gray-500{color:var(--color-gray-500)}.text-gray-600{color:var(--color-gray-600)}.text-gray-700{color:var(--color-gray-700)}.text-gray-800{color:var(--color-gray-800)}.text-gray-900{color:var(--color-gray-900)}.text-green-700{color:var(--color-green-700)}.text-red-600{color:var(--color-red-600)}.text-red-700{color:var(--color-red-700)}.text-red-800{color:var(--color-red-800)}.text-red-900{color:var(--color-red-900)}.text-white{color:var(--color-white)}.uppercase{text-transform:uppercase}.underline{text-decoration-line:underline}.shadow-xl{--tw-shadow:0 20px 25px -5px var(--tw-shadow-color,#0000001a), 0 8px 10px -6px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-xs{--tw-shadow:0 1px 2px 0 var(--tw-shadow-color,#0000000d);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ring-1{--tw-ring-shadow:var(--tw-ring-inset, ) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ring-amber-200{--tw-ring-color:var(--color-amber-200)}.ring-black\/5{--tw-ring-color:#0000000d}@supports (color:color-mix(in lab, red, red)){.ring-black\/5{--tw-ring-color:color-mix(in oklab, var(--color-black) 5%, transparent)}}.ring-blue-200{--tw-ring-color:var(--color-blue-200)}.ring-emerald-200{--tw-ring-color:var(--color-emerald-200)}.ring-gray-900{--tw-ring-color:var(--color-gray-900)}.ring-red-200{--tw-ring-color:var(--color-red-200)}.outline-hidden{--tw-outline-style:none;outline-style:none}@media (forced-colors:active){.outline-hidden{outline-offset:2px;outline:2px solid #0000}}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.select-none{-webkit-user-select:none;user-select:none}.last\:border-0:last-child{border-style:var(--tw-border-style);border-width:0}@media (hover:hover){.hover\:bg-gray-50:hover{background-color:var(--color-gray-50)}.hover\:bg-gray-700:hover{background-color:var(--color-gray-700)}.hover\:bg-red-50:hover{background-color:var(--color-red-50)}.hover\:bg-red-700:hover{background-color:var(--color-red-700)}.hover\:text-gray-600:hover{color:var(--color-gray-600)}.hover\:underline:hover{text-decoration-line:underline}.hover\:opacity-90:hover{opacity:.9}}.focus\:border-gray-900:focus{border-color:var(--color-gray-900)}.focus\:border-red-600:focus{border-color:var(--color-red-600)}.focus\:ring-2:focus{--tw-ring-shadow:var(--tw-ring-inset, ) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.focus\:ring-gray-900:focus{--tw-ring-color:var(--color-gray-900)}}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-divide-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}</style>
|
package/build/index.d.ts
CHANGED
|
@@ -115,18 +115,19 @@ export { createAuthThrottles } from './src/host/rate_limit.js';
|
|
|
115
115
|
export type { AccountScreensOptions, AuthHostOptions, AuthHostRouteMap, } from './src/host/register_auth_host.js';
|
|
116
116
|
export { registerAuthHost } from './src/host/register_auth_host.js';
|
|
117
117
|
export { edgeRenderer } from './src/host/renderers/edge_renderer.js';
|
|
118
|
-
export type {
|
|
118
|
+
export type { InertiaRendererOptions } from './src/host/renderers/inertia_renderer.js';
|
|
119
119
|
export { inertiaRenderer } from './src/host/renderers/inertia_renderer.js';
|
|
120
120
|
export type { RuntimeSettingsOptions, SettingRow, SettingsCapability, } from './src/host/runtime_settings.js';
|
|
121
121
|
export { RuntimeSettings, supportsSettings } from './src/host/runtime_settings.js';
|
|
122
122
|
export type { AuthMethodsCapabilities, AuthMethodsConfigOverride, AuthMethodsSetting, MaintenanceModeSetting, RegistrationSetting, RequireVerifiedEmailSetting, ResolvedAuthMethods, ResolvedMaintenanceMode, SettingKey, } from './src/host/runtime_toggles.js';
|
|
123
123
|
export { configLockedAuthMethods, resolveEffectiveAuthMethods, resolveEffectiveMaintenanceMode, resolveEffectiveRegistration, resolveEffectiveRequireVerifiedEmail, SETTING_KEYS, } from './src/host/runtime_toggles.js';
|
|
124
|
+
export type { AccountAppsProps, AccountOrg, AccountOrgsProps, AccountTokensProps, AgentConsentRequest, AgentsConsentProps, AgentsDoneProps, AuthkitScreen, AuthkitScreenProps, AuthkitScreenRenderer, ConsentProps, ConsentRequestParams, ConsentScope, ForgotProps, LoginAccount, LoginProps, MaintenanceProps, MfaChallengeCustomMethod, MfaChallengeProps, OtpUnlockProps, ResetProps, ScreenRenderProps, SessionExpiredProps, SignupProps, ThrottledProps, VerifyEmailProps, } from './src/host/screen_props.js';
|
|
124
125
|
export { enrichSessionsWithContext } from './src/host/session_context.js';
|
|
125
126
|
export { sudoMethods } from './src/host/sudo/index.js';
|
|
126
127
|
export { completeSudo, fail as failSudo, LAST_METHOD_SESSION_KEY, sudoContextFrom, } from './src/host/sudo/runtime.js';
|
|
127
128
|
export type { SudoContext, SudoMethod, SudoMethodDescriptor, SudoRouteHelpers, } from './src/host/sudo/types.js';
|
|
128
129
|
export type { ResolvedSudoModeSetting, SudoModeSetting, } from './src/host/sudo_mode.js';
|
|
129
|
-
export { isSudoActive, isSudoSatisfied,
|
|
130
|
+
export { isSudoActive, isSudoSatisfied, requireSudo, resolveEffectiveSudoMode, SUDO_ACCOUNT_SESSION_KEY, SUDO_MODE_DEFAULTS, SUDO_SESSION_KEY, } from './src/host/sudo_mode.js';
|
|
130
131
|
export { barChartSvg } from './src/host/svg_chart.js';
|
|
131
132
|
export type { ResolvedTrustedDevicesConfig, TrustedDevicePayload, TrustedDevicesConfigInput, } from './src/host/trusted_device.js';
|
|
132
133
|
export { buildTrustedDevicePayload, isTrustedDeviceValid, resolveTrustedDevices, TRUSTED_DEVICE_COOKIE, } from './src/host/trusted_device.js';
|
|
@@ -140,7 +141,6 @@ export { MCP_CLIENT_REDIRECTS, MCP_RESOURCE_SCOPES, type McpOAuthConfigInput, ty
|
|
|
140
141
|
export { withAuditLog } from './src/mixins/with_audit_log.js';
|
|
141
142
|
export { withAuthUser } from './src/mixins/with_auth_user.js';
|
|
142
143
|
export { withCredentials } from './src/mixins/with_credentials.js';
|
|
143
|
-
export { withMfa } from './src/mixins/with_mfa.js';
|
|
144
144
|
export { withPersonalAccessToken } from './src/mixins/with_personal_access_token.js';
|
|
145
145
|
export type { ProviderIdentityClass, ProviderIdentityRow, } from './src/mixins/with_provider_identity.js';
|
|
146
146
|
export { withProviderIdentity } from './src/mixins/with_provider_identity.js';
|
package/build/index.js
CHANGED
|
@@ -103,9 +103,8 @@ export { enrichSessionsWithContext } from './src/host/session_context.js';
|
|
|
103
103
|
//
|
|
104
104
|
// `completeSudo` é público porque o host PRECISA chamá-lo: o `oidcStepUp` não
|
|
105
105
|
// registra rotas — quem valida o grant é o callback do host, e é lá que a
|
|
106
|
-
// concessão acontece
|
|
107
|
-
//
|
|
108
|
-
// o `return_to`.
|
|
106
|
+
// concessão acontece, com o audit `sudo.confirmed`, a preferência de método e o
|
|
107
|
+
// redirect para o `return_to`.
|
|
109
108
|
export { sudoMethods } from './src/host/sudo/index.js';
|
|
110
109
|
// Montador do `SudoContext` que `completeSudo`/`failSudo` recebem. Exportado
|
|
111
110
|
// junto porque sem ele o host teria de montar o contexto na mão (resolver o
|
|
@@ -116,7 +115,7 @@ export { completeSudo, fail as failSudo, LAST_METHOD_SESSION_KEY, sudoContextFro
|
|
|
116
115
|
export { isSudoActive,
|
|
117
116
|
// A DECISÃO de sudo sem efeito na resposta — o que o host chama quando quer
|
|
118
117
|
// recusar em JSON em vez de redirecionar para `/account/confirm`.
|
|
119
|
-
isSudoSatisfied,
|
|
118
|
+
isSudoSatisfied, requireSudo, resolveEffectiveSudoMode, SUDO_ACCOUNT_SESSION_KEY, SUDO_MODE_DEFAULTS, SUDO_SESSION_KEY, } from './src/host/sudo_mode.js';
|
|
120
119
|
export { barChartSvg } from './src/host/svg_chart.js';
|
|
121
120
|
export { buildTrustedDevicePayload, isTrustedDeviceValid, resolveTrustedDevices, TRUSTED_DEVICE_COOKIE, } from './src/host/trusted_device.js';
|
|
122
121
|
export { parseUserAgent } from './src/host/user_agent.js';
|
|
@@ -127,7 +126,6 @@ export { MCP_CLIENT_REDIRECTS, MCP_RESOURCE_SCOPES, registeredOAuthResources, re
|
|
|
127
126
|
export { withAuditLog } from './src/mixins/with_audit_log.js';
|
|
128
127
|
export { withAuthUser } from './src/mixins/with_auth_user.js';
|
|
129
128
|
export { withCredentials } from './src/mixins/with_credentials.js';
|
|
130
|
-
export { withMfa } from './src/mixins/with_mfa.js';
|
|
131
129
|
export { withPersonalAccessToken } from './src/mixins/with_personal_access_token.js';
|
|
132
130
|
export { withProviderIdentity } from './src/mixins/with_provider_identity.js';
|
|
133
131
|
export { withWebauthnCredential } from './src/mixins/with_webauthn_credential.js';
|
|
@@ -171,21 +171,3 @@ export interface LucidAccountStoreOptions {
|
|
|
171
171
|
emailTokens?: EmailTokensConfigInput;
|
|
172
172
|
}
|
|
173
173
|
export declare function lucidAccountStore(Model: any, options?: LucidAccountStoreOptions): AccountStore;
|
|
174
|
-
/**
|
|
175
|
-
* Options estendidas para uso em testes ou quando o DB é injetado diretamente
|
|
176
|
-
* para o probe de histórico de senhas. Uso interno/avançado.
|
|
177
|
-
*/
|
|
178
|
-
export interface LucidAccountStoreAsyncOptions extends LucidAccountStoreOptions {
|
|
179
|
-
/**
|
|
180
|
-
* Instância de DB Lucid. Quando fornecida, o factory faz o probe da tabela
|
|
181
|
-
* `auth_password_history` e monta a capability automaticamente.
|
|
182
|
-
*/
|
|
183
|
-
db?: any;
|
|
184
|
-
}
|
|
185
|
-
/**
|
|
186
|
-
* Versão assíncrona do {@link lucidAccountStore} que faz o probe de DB para
|
|
187
|
-
* detectar tabelas opcionais (`auth_password_history`) e monta as capabilities
|
|
188
|
-
* correspondentes. Use esta versão quando o `db` está disponível no momento do
|
|
189
|
-
* boot (ex.: no `register_auth_host.ts` ou no `app/providers/auth_provider.ts`).
|
|
190
|
-
*/
|
|
191
|
-
export declare function lucidAccountStoreAsync(Model: any, options?: LucidAccountStoreAsyncOptions): Promise<AccountStore>;
|
|
@@ -6,7 +6,7 @@ import { defaultOrganizationModels } from './lucid_store/organization_models.js'
|
|
|
6
6
|
import { buildOrganizations } from './lucid_store/organizations.js';
|
|
7
7
|
import { buildPasswordExpiration, buildPasswordHistory } from './lucid_store/password_hygiene.js';
|
|
8
8
|
import { buildProviderIdentity } from './lucid_store/provider_identity.js';
|
|
9
|
-
import { defaultWebauthnCeremonies,
|
|
9
|
+
import { defaultWebauthnCeremonies, } from './lucid_store/shared.js';
|
|
10
10
|
import { buildDeletion, buildEmailVerificationStatus, buildProfile, buildStatus, hasColumn, } from './lucid_store/status_profile.js';
|
|
11
11
|
import { buildWebauthn } from './lucid_store/webauthn.js';
|
|
12
12
|
export function resolveEmailTokens(input) {
|
|
@@ -317,52 +317,11 @@ export function lucidAccountStore(Model, options = {}) {
|
|
|
317
317
|
*/
|
|
318
318
|
__model: Model,
|
|
319
319
|
};
|
|
320
|
-
// Histórico de senhas:
|
|
321
|
-
//
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
Object.assign(store, buildPasswordHistory(ctx, passwordHistoryDb));
|
|
327
|
-
}
|
|
320
|
+
// Histórico de senhas: tabela lib-owned `auth_password_history`, pela conexão
|
|
321
|
+
// do model (resolvida a cada uso, como no MFA).
|
|
322
|
+
Object.assign(store, buildPasswordHistory(ctx, {
|
|
323
|
+
query: () => Model.query().client.query(),
|
|
324
|
+
table: (name) => Model.query().client.table(name),
|
|
325
|
+
}));
|
|
328
326
|
return store;
|
|
329
327
|
}
|
|
330
|
-
/**
|
|
331
|
-
* Versão assíncrona do {@link lucidAccountStore} que faz o probe de DB para
|
|
332
|
-
* detectar tabelas opcionais (`auth_password_history`) e monta as capabilities
|
|
333
|
-
* correspondentes. Use esta versão quando o `db` está disponível no momento do
|
|
334
|
-
* boot (ex.: no `register_auth_host.ts` ou no `app/providers/auth_provider.ts`).
|
|
335
|
-
*/
|
|
336
|
-
export async function lucidAccountStoreAsync(Model, options = {}) {
|
|
337
|
-
const { db, ...rest } = options;
|
|
338
|
-
const base = lucidAccountStore(Model, rest);
|
|
339
|
-
if (db) {
|
|
340
|
-
// Probe da tabela auth_password_history.
|
|
341
|
-
const historyPresent = await hasTable(db, 'auth_password_history');
|
|
342
|
-
if (historyPresent) {
|
|
343
|
-
const ctx = {
|
|
344
|
-
Model,
|
|
345
|
-
mfaIssuer: options.mfaIssuer ?? 'AuthKit',
|
|
346
|
-
recoveryCodeCount: options.recoveryCodeCount ?? 8,
|
|
347
|
-
passwords: new PasswordManager(options.password, {
|
|
348
|
-
logger: options.logger,
|
|
349
|
-
fetchImpl: options.pwnedFetch,
|
|
350
|
-
}),
|
|
351
|
-
audit: options.audit,
|
|
352
|
-
sealSecret: (s) => s,
|
|
353
|
-
openSecret: (s) => s ?? null,
|
|
354
|
-
toAccount: (row) => ({
|
|
355
|
-
// Ver a nota em `toAccount` acima: `sub` precisa ser string.
|
|
356
|
-
id: String(row.id),
|
|
357
|
-
email: row.email,
|
|
358
|
-
...(row.phone && row.phoneVerifiedAt ? { phone: row.phone } : {}),
|
|
359
|
-
globalRoles: row.globalRoles ?? [],
|
|
360
|
-
name: row.fullName ?? undefined,
|
|
361
|
-
avatarUrl: row.avatarUrl ?? undefined,
|
|
362
|
-
}),
|
|
363
|
-
};
|
|
364
|
-
Object.assign(base, buildPasswordHistory(ctx, db));
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
return base;
|
|
368
|
-
}
|
|
@@ -6,7 +6,7 @@ import { buildMfaStateRepo, generateRecoveryCode, hashesEqual, sha256, } from '.
|
|
|
6
6
|
* O estado de MFA (`totp_secret`, `mfa_enabled_at`, `recovery_codes`,
|
|
7
7
|
* `last_totp_step`) vive numa tabela PRÓPRIA auto-gerida `auth_mfa` (criada pelo
|
|
8
8
|
* {@link ensureAuthkitSchema}), keyed por `account_id`. O host NÃO precisa migrar
|
|
9
|
-
* nada
|
|
9
|
+
* nada e o model não declara colunas de MFA.
|
|
10
10
|
*
|
|
11
11
|
* Acesso ao banco via a CONEXÃO do próprio model (`Model.query().client`), a mesma
|
|
12
12
|
* usada pelo restante do store. O `email` (para o keyuri/QR) continua vindo do
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { OrganizationsCapability } from '../account_store.js';
|
|
2
2
|
/**
|
|
3
3
|
* Contexto mínimo para o builder de organizations. Recebe os três models direto
|
|
4
|
-
* (já construídos pelo lucidAccountStore
|
|
4
|
+
* (já construídos pelo lucidAccountStore).
|
|
5
5
|
*/
|
|
6
6
|
export interface OrgStoreContext {
|
|
7
7
|
OrgModel: any;
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import type { PasswordExpirationCapability, PasswordHistoryCapability } from '../account_store.js';
|
|
2
2
|
import type { LucidStoreContext } from './shared.js';
|
|
3
3
|
/**
|
|
4
|
-
* Histórico de senhas (disallow_password_reuse)
|
|
5
|
-
*
|
|
6
|
-
* {@link hasTable} no `lucidAccountStore`).
|
|
4
|
+
* Histórico de senhas (disallow_password_reuse), sobre a tabela lib-owned
|
|
5
|
+
* `auth_password_history` (criada pelo `ensureAuthkitSchema`).
|
|
7
6
|
*
|
|
8
7
|
* Tabela: `auth_password_history`
|
|
9
8
|
* id UUID/SERIAL PK
|
|
@@ -2,9 +2,8 @@ import { DateTime } from 'luxon';
|
|
|
2
2
|
/** Stub de noop para quando não há verify disponível (fail-safe: não bloqueia). */
|
|
3
3
|
const _noopVerify = async (_hash, _plain) => false;
|
|
4
4
|
/**
|
|
5
|
-
* Histórico de senhas (disallow_password_reuse)
|
|
6
|
-
*
|
|
7
|
-
* {@link hasTable} no `lucidAccountStore`).
|
|
5
|
+
* Histórico de senhas (disallow_password_reuse), sobre a tabela lib-owned
|
|
6
|
+
* `auth_password_history` (criada pelo `ensureAuthkitSchema`).
|
|
8
7
|
*
|
|
9
8
|
* Tabela: `auth_password_history`
|
|
10
9
|
* id UUID/SERIAL PK
|
|
@@ -84,13 +84,6 @@ export declare const sha256: (value: string) => string;
|
|
|
84
84
|
export declare function generateRecoveryCode(): string;
|
|
85
85
|
/** Comparação de hashes hex resistente a timing. */
|
|
86
86
|
export declare function hashesEqual(a: string, b: string): boolean;
|
|
87
|
-
/**
|
|
88
|
-
* Indica se o model Lucid tem sua tabela registrada no adapter do DB (runtime probe).
|
|
89
|
-
* Usado para detectar tabelas opcionais como auth_organizations/members/invitations.
|
|
90
|
-
* Mais robusto do que checar colunas: detecta a presença da tabela inteira.
|
|
91
|
-
* Em testes, as tabelas existem se foram criadas na migration do teste.
|
|
92
|
-
*/
|
|
93
|
-
export declare function hasTable(db: any, tableName: string): Promise<boolean>;
|
|
94
87
|
/**
|
|
95
88
|
* Estado de MFA (lido de `auth_mfa`). Forma normalizada usada pela {@link MfaCapability}:
|
|
96
89
|
* - `mfaEnabledAt` em EPOCH MS (ou null) — o trusted-device compara contra isso.
|
|
@@ -37,20 +37,6 @@ export function hashesEqual(a, b) {
|
|
|
37
37
|
return false;
|
|
38
38
|
return timingSafeEqual(ba, bb);
|
|
39
39
|
}
|
|
40
|
-
/**
|
|
41
|
-
* Indica se o model Lucid tem sua tabela registrada no adapter do DB (runtime probe).
|
|
42
|
-
* Usado para detectar tabelas opcionais como auth_organizations/members/invitations.
|
|
43
|
-
* Mais robusto do que checar colunas: detecta a presença da tabela inteira.
|
|
44
|
-
* Em testes, as tabelas existem se foram criadas na migration do teste.
|
|
45
|
-
*/
|
|
46
|
-
export async function hasTable(db, tableName) {
|
|
47
|
-
try {
|
|
48
|
-
return await db.connection().schema.hasTable(tableName);
|
|
49
|
-
}
|
|
50
|
-
catch {
|
|
51
|
-
return false;
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
40
|
/**
|
|
55
41
|
* Repositório do estado de MFA na tabela LIB-OWNED `auth_mfa`, keyed por
|
|
56
42
|
* `account_id`. Acessa o banco pela CONEXÃO do próprio model (`Model.query().client`),
|
|
@@ -4,7 +4,7 @@ import type { AccountStore } from './account_store.js';
|
|
|
4
4
|
import { type LucidAccountStoreOptions } from './lucid_account_store.js';
|
|
5
5
|
/** Models Lucid (compostos dos mixins do authkit) para montar os stores de uma vez. */
|
|
6
6
|
export interface LucidStoresModels {
|
|
7
|
-
/** Model de `withAuthUser()` (+withCredentials
|
|
7
|
+
/** Model de `withAuthUser()` (+withCredentials). Obrigatório. */
|
|
8
8
|
account: any;
|
|
9
9
|
/** Model de `withPersonalAccessToken()` — habilita o patStore. */
|
|
10
10
|
pat?: any;
|
|
@@ -140,13 +140,18 @@ export class RedisAdapter {
|
|
|
140
140
|
*/
|
|
141
141
|
async list() {
|
|
142
142
|
const prefix = `${this.prefix}:${this.name}:`;
|
|
143
|
+
// A connection `keyPrefix` (ioredis) is added to every key a command takes,
|
|
144
|
+
// but NOT to a SCAN `MATCH` pattern, and SCAN returns the stored (prefixed)
|
|
145
|
+
// keys. So match with it and strip it before `MGET`, which adds it again.
|
|
146
|
+
const keyPrefix = this.#connectionKeyPrefix();
|
|
143
147
|
const result = [];
|
|
144
148
|
let cursor = '0';
|
|
145
149
|
do {
|
|
146
|
-
const [next,
|
|
150
|
+
const [next, stored] = await this.redis.scan(cursor, 'MATCH', `${keyPrefix}${prefix}*`, 'COUNT', 1000);
|
|
147
151
|
cursor = next;
|
|
148
|
-
if (
|
|
152
|
+
if (stored.length === 0)
|
|
149
153
|
continue;
|
|
154
|
+
const keys = stored.map((key) => key.slice(keyPrefix.length));
|
|
150
155
|
const values = await this.redis.mget(...keys);
|
|
151
156
|
keys.forEach((key, i) => {
|
|
152
157
|
const data = values[i];
|
|
@@ -161,4 +166,9 @@ export class RedisAdapter {
|
|
|
161
166
|
result.sort((a, b) => a.id.localeCompare(b.id));
|
|
162
167
|
return result;
|
|
163
168
|
}
|
|
169
|
+
/** The `keyPrefix` of the ioredis connection (or of the AdonisJS connection wrapping it). */
|
|
170
|
+
#connectionKeyPrefix() {
|
|
171
|
+
const client = this.redis;
|
|
172
|
+
return client.options?.keyPrefix ?? client.ioConnection?.options?.keyPrefix ?? '';
|
|
173
|
+
}
|
|
164
174
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AccessTokenFormat, AccessTokensConfig,
|
|
1
|
+
import type { AccessTokenFormat, AccessTokensConfig, JwksConfig, KeystoreStoreConfig, ObservabilityConfig, TtlConfig } from '@adonis-agora/authkit-core';
|
|
2
2
|
import type { HttpContext } from '@adonisjs/core/http';
|
|
3
3
|
import type { AccountStore, AuthAccount } from './accounts/account_store.js';
|
|
4
4
|
import { type AdapterFactory, adapters, type OidcAdapterClass } from './adapters/factory.js';
|
|
@@ -14,6 +14,7 @@ import type { ResolveGeo } from './host/geo.js';
|
|
|
14
14
|
import { type AuthMessages, type I18nConfig } from './host/i18n.js';
|
|
15
15
|
import { type OtpLoginConfigInput, type ResolvedOtpLoginConfig } from './host/otp_login.js';
|
|
16
16
|
import type { AuthHostOptions } from './host/register_auth_host.js';
|
|
17
|
+
import type { AuthkitScreenRenderer } from './host/screen_props.js';
|
|
17
18
|
import type { SudoMethod } from './host/sudo/types.js';
|
|
18
19
|
import { type ResolvedTrustedDevicesConfig, type TrustedDevicesConfigInput } from './host/trusted_device.js';
|
|
19
20
|
import type { WhatsappCodeSenderBinding } from './host/whatsapp_code_sender.js';
|
|
@@ -354,8 +355,8 @@ export declare function resolveNotifications(): ResolvedNotificationsConfig;
|
|
|
354
355
|
*
|
|
355
356
|
* Quando habilitado, o oidc-provider expõe o endpoint de registro (`/reg`) e os
|
|
356
357
|
* clients criados ali são PERSISTIDOS pelo MESMO adapter usado para os demais
|
|
357
|
-
* artefatos OIDC
|
|
358
|
-
*
|
|
358
|
+
* artefatos OIDC, junto dos clients criados pelo console admin, pela Admin API e
|
|
359
|
+
* pelo `node ace authkit:clients:create`.
|
|
359
360
|
*/
|
|
360
361
|
export interface DynamicRegistrationConfigInput {
|
|
361
362
|
/** Liga o endpoint de registro dinâmico. Default: false (comportamento atual). */
|
|
@@ -872,13 +873,6 @@ export interface AuthServerConfigInput {
|
|
|
872
873
|
session?: {
|
|
873
874
|
adapter?: AdapterFactory;
|
|
874
875
|
};
|
|
875
|
-
/**
|
|
876
|
-
* Clientes OIDC pré-carregados no provider ao subir. Útil para testes e
|
|
877
|
-
* migrações pontuais. Para uso em produção, gerencie clients via console admin
|
|
878
|
-
* ou Admin API (`node ace authkit:clients:create`).
|
|
879
|
-
* @internal
|
|
880
|
-
*/
|
|
881
|
-
clients?: ClientConfig[];
|
|
882
876
|
/**
|
|
883
877
|
* Config de JWKS, ou `'auto'` (recomendado p/ deploys efêmeros): se a env
|
|
884
878
|
* `AUTHKIT_JWKS` (JSON `{"keys":[...]}`) estiver presente, usa-a inline
|
|
@@ -1256,7 +1250,6 @@ export interface ResolvedServerConfig {
|
|
|
1256
1250
|
* `session.adapter` no input é a MESMA classe do `AdapterClass`.
|
|
1257
1251
|
*/
|
|
1258
1252
|
SessionAdapterClass: OidcAdapterClass;
|
|
1259
|
-
clients: ClientConfig[];
|
|
1260
1253
|
jwks: {
|
|
1261
1254
|
keys: Record<string, any>[];
|
|
1262
1255
|
};
|
|
@@ -1296,7 +1289,8 @@ export interface ResolvedServerConfig {
|
|
|
1296
1289
|
mountPath: string;
|
|
1297
1290
|
/** Destino default pós-confirmação do console (sudo mode) e demais fallbacks de conta. Default: '/account/security'. */
|
|
1298
1291
|
accountHome?: string;
|
|
1299
|
-
|
|
1292
|
+
/** O renderer das telas, tipado por view (ver `AuthkitScreenProps`). */
|
|
1293
|
+
render?: AuthkitScreenRenderer;
|
|
1300
1294
|
/** Recuperação de sessão de interaction perdida resolvida (default `{ mode: 'screen' }`). */
|
|
1301
1295
|
interactionRecovery: ResolvedInteractionRecoveryConfig;
|
|
1302
1296
|
/** Branding resolvido: sempre presente (default neutro quando o host não declara `branding`). */
|
|
@@ -387,7 +387,6 @@ export function defineConfig(config) {
|
|
|
387
387
|
issuer: config.issuer,
|
|
388
388
|
AdapterClass,
|
|
389
389
|
SessionAdapterClass,
|
|
390
|
-
clients: config.clients ?? [],
|
|
391
390
|
jwks: jwks,
|
|
392
391
|
jwksConfig,
|
|
393
392
|
ttl: {
|
|
@@ -419,7 +418,9 @@ export function defineConfig(config) {
|
|
|
419
418
|
// importa `edge.js` eagerly, então é seguro construir mesmo em hosts
|
|
420
419
|
// sem o peer opcional instalado (só quebraria se a request realmente
|
|
421
420
|
// chegasse sem Edge configurado, exatamente como hoje).
|
|
422
|
-
|
|
421
|
+
// O renderer do host recebe `(ctx, view, props)`; aqui ele é tipado por view para que
|
|
422
|
+
// os controllers não possam divergir de `AuthkitScreenProps`.
|
|
423
|
+
render: (config.render ?? edgeRenderer()),
|
|
423
424
|
// Recuperação de sessão de interaction perdida: default gracioso 'screen'
|
|
424
425
|
// (tela themeável `session-expired`); 'redirect' opt-in para 302 ao login.
|
|
425
426
|
interactionRecovery: {
|
|
@@ -41,13 +41,12 @@ export declare function checkConfigResolves(input: DoctorInput): Finding;
|
|
|
41
41
|
/** issuer é uma URL válida e seu pathname casa com o mountPath. */
|
|
42
42
|
export declare function checkIssuer(input: DoctorInput): Finding[];
|
|
43
43
|
/**
|
|
44
|
-
* Clients:
|
|
45
|
-
*
|
|
44
|
+
* Clients: vivem no adapter, gerenciados pelo console admin / Admin API /
|
|
45
|
+
* `node ace authkit:clients:create`.
|
|
46
46
|
*/
|
|
47
47
|
export declare function checkClients(input: DoctorInput): Finding;
|
|
48
48
|
/**
|
|
49
|
-
* Aviso de adapter volátil. Como clients
|
|
50
|
-
* um adapter volátil (Redis sem persistência, in-memory) pode perder os clients
|
|
49
|
+
* Aviso de adapter volátil. Como os clients vivem no adapter, um adapter volátil (Redis sem persistência, in-memory) pode perder os clients
|
|
51
50
|
* num restart sem aviso prévio.
|
|
52
51
|
*
|
|
53
52
|
* Detecção de volatilidade: o `AdapterClass` é inspecionado estruturalmente:
|
|
@@ -48,22 +48,20 @@ export function checkIssuer(input) {
|
|
|
48
48
|
return findings;
|
|
49
49
|
}
|
|
50
50
|
/**
|
|
51
|
-
* Clients:
|
|
52
|
-
*
|
|
51
|
+
* Clients: vivem no adapter, gerenciados pelo console admin / Admin API /
|
|
52
|
+
* `node ace authkit:clients:create`.
|
|
53
53
|
*/
|
|
54
54
|
export function checkClients(input) {
|
|
55
55
|
const cfg = input.authkitConfig;
|
|
56
56
|
if (!cfg)
|
|
57
57
|
return { level: 'error', message: 'no config to validate clients.' };
|
|
58
|
-
// clients sempre é [] no config resolvido — info apenas.
|
|
59
58
|
return {
|
|
60
59
|
level: 'ok',
|
|
61
60
|
message: 'clients are managed at runtime via admin console / Admin API — use `node ace authkit:clients:create` to add clients.',
|
|
62
61
|
};
|
|
63
62
|
}
|
|
64
63
|
/**
|
|
65
|
-
* Aviso de adapter volátil. Como clients
|
|
66
|
-
* um adapter volátil (Redis sem persistência, in-memory) pode perder os clients
|
|
64
|
+
* Aviso de adapter volátil. Como os clients vivem no adapter, um adapter volátil (Redis sem persistência, in-memory) pode perder os clients
|
|
67
65
|
* num restart sem aviso prévio.
|
|
68
66
|
*
|
|
69
67
|
* Detecção de volatilidade: o `AdapterClass` é inspecionado estruturalmente:
|
|
@@ -98,9 +96,9 @@ export function checkAdapterVolatility(input) {
|
|
|
98
96
|
// Adapter desconhecido ou volátil (Redis, memory, custom) — warn informativo.
|
|
99
97
|
return {
|
|
100
98
|
level: 'warn',
|
|
101
|
-
message: '
|
|
99
|
+
message: 'Clients live in the OIDC adapter: if it is volatile (Redis without AOF/RDB, in-memory, etc.), ' +
|
|
102
100
|
'clients managed via console/API will be lost on restart. ' +
|
|
103
|
-
'Use a persistent adapter (DatabaseAdapter)
|
|
101
|
+
'Use a persistent adapter (DatabaseAdapter).',
|
|
104
102
|
};
|
|
105
103
|
}
|
|
106
104
|
/** accountStore presente + quais capacidades implementa. */
|