@adonis-agora/authkit-server 0.90.2 → 1.0.0-rc.1
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 +3654 -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 +1 -1
- package/build/index.d.ts +5 -3
- package/build/index.js +4 -5
- package/build/providers/authkit_server_provider.js +8 -0
- 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/console_authorize.d.ts +56 -0
- package/build/src/console_authorize.js +85 -0
- package/build/src/define_config.d.ts +26 -14
- package/build/src/define_config.js +5 -3
- package/build/src/doctor/checks.d.ts +10 -5
- package/build/src/doctor/checks.js +52 -8
- 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 +28 -6
- 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_console_warning.d.ts +8 -0
- package/build/src/host/admin_console_warning.js +18 -0
- package/build/src/host/admin_validators.d.ts +15 -11
- package/build/src/host/admin_validators.js +16 -9
- package/build/src/host/auth_host_config.d.ts +5 -0
- 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/console_denied_page.d.ts +6 -0
- package/build/src/host/console_denied_page.js +18 -0
- package/build/src/host/console_sso.d.ts +24 -0
- package/build/src/host/console_sso.js +70 -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/account_session_controller.js +10 -1
- package/build/src/host/controllers/agent_consent_controller.js +23 -5
- package/build/src/host/controllers/console_sso_controller.d.ts +12 -0
- package/build/src/host/controllers/console_sso_controller.js +61 -0
- package/build/src/host/controllers/interaction_controller.js +9 -3
- 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 +8 -0
- package/build/src/host/register_auth_host.js +116 -11
- 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 +6 -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 +12 -11
- 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-DUVBDAyh.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
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-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:2147483647px}.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>
|
|
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
|
@@ -30,6 +30,8 @@ export type { BuiltinProtocolId, PactOptions, PersonalAgentProtocol, } from './s
|
|
|
30
30
|
export { pact, pactProtocol } from './src/agents/protocol.js';
|
|
31
31
|
export type { AuditEvent, AuditEventType, AuditPage, AuditSink, ListAuditParams, StoredAuditEvent, } from './src/audit/audit_sink.js';
|
|
32
32
|
export { lucidAuditSink } from './src/audit/lucid_audit_sink.js';
|
|
33
|
+
export type { ConsoleAuthorize, ConsoleAuthorizeResult, ConsoleAuthorizer, ConsoleAuthorizerClass, } from './src/console_authorize.js';
|
|
34
|
+
export { authorizeByToken } from './src/console_authorize.js';
|
|
33
35
|
export type { AdminApiConfigInput, AdminConfigInput, AuthHostRenderer, AuthMethodsConfigInput, AuthServerConfigInput, AuthSocialConfig, DynamicRegistrationConfigInput, LoginConfigInput, OrganizationsConfigInput, PasswordlessConfigInput, RateLimitBucket, RateLimitConfigInput, RegistrationConfigInput, ResolvedAdminApiConfig, ResolvedAdminConfig, ResolvedAuthMethodsConfig, ResolvedDynamicRegistrationConfig, ResolvedLoginConfig, ResolvedNotificationsConfig, ResolvedOrganizationsConfig, ResolvedPasswordlessConfig, ResolvedRateLimitConfig, ResolvedRegistrationConfig, ResolvedServerConfig, ResolvedWebauthnConfig, WebauthnConfigInput, } from './src/define_config.js';
|
|
34
36
|
export { adapters, defineConfig, resolveAdmin, resolveAdminApi, resolveAuthMethodsConfig, resolveDynamicRegistration, resolveLogin, resolveNotifications, resolveOrganizations, resolvePasswordless, resolveRateLimit, resolveRegistration, resolveWebauthn, toSeconds, } from './src/define_config.js';
|
|
35
37
|
export type { EventsConfigInput, ResolvedEventsConfig } from './src/events/dispatcher.js';
|
|
@@ -115,18 +117,19 @@ export { createAuthThrottles } from './src/host/rate_limit.js';
|
|
|
115
117
|
export type { AccountScreensOptions, AuthHostOptions, AuthHostRouteMap, } from './src/host/register_auth_host.js';
|
|
116
118
|
export { registerAuthHost } from './src/host/register_auth_host.js';
|
|
117
119
|
export { edgeRenderer } from './src/host/renderers/edge_renderer.js';
|
|
118
|
-
export type {
|
|
120
|
+
export type { InertiaRendererOptions } from './src/host/renderers/inertia_renderer.js';
|
|
119
121
|
export { inertiaRenderer } from './src/host/renderers/inertia_renderer.js';
|
|
120
122
|
export type { RuntimeSettingsOptions, SettingRow, SettingsCapability, } from './src/host/runtime_settings.js';
|
|
121
123
|
export { RuntimeSettings, supportsSettings } from './src/host/runtime_settings.js';
|
|
122
124
|
export type { AuthMethodsCapabilities, AuthMethodsConfigOverride, AuthMethodsSetting, MaintenanceModeSetting, RegistrationSetting, RequireVerifiedEmailSetting, ResolvedAuthMethods, ResolvedMaintenanceMode, SettingKey, } from './src/host/runtime_toggles.js';
|
|
123
125
|
export { configLockedAuthMethods, resolveEffectiveAuthMethods, resolveEffectiveMaintenanceMode, resolveEffectiveRegistration, resolveEffectiveRequireVerifiedEmail, SETTING_KEYS, } from './src/host/runtime_toggles.js';
|
|
126
|
+
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
127
|
export { enrichSessionsWithContext } from './src/host/session_context.js';
|
|
125
128
|
export { sudoMethods } from './src/host/sudo/index.js';
|
|
126
129
|
export { completeSudo, fail as failSudo, LAST_METHOD_SESSION_KEY, sudoContextFrom, } from './src/host/sudo/runtime.js';
|
|
127
130
|
export type { SudoContext, SudoMethod, SudoMethodDescriptor, SudoRouteHelpers, } from './src/host/sudo/types.js';
|
|
128
131
|
export type { ResolvedSudoModeSetting, SudoModeSetting, } from './src/host/sudo_mode.js';
|
|
129
|
-
export { isSudoActive, isSudoSatisfied,
|
|
132
|
+
export { isSudoActive, isSudoSatisfied, requireSudo, resolveEffectiveSudoMode, SUDO_ACCOUNT_SESSION_KEY, SUDO_MODE_DEFAULTS, SUDO_SESSION_KEY, } from './src/host/sudo_mode.js';
|
|
130
133
|
export { barChartSvg } from './src/host/svg_chart.js';
|
|
131
134
|
export type { ResolvedTrustedDevicesConfig, TrustedDevicePayload, TrustedDevicesConfigInput, } from './src/host/trusted_device.js';
|
|
132
135
|
export { buildTrustedDevicePayload, isTrustedDeviceValid, resolveTrustedDevices, TRUSTED_DEVICE_COOKIE, } from './src/host/trusted_device.js';
|
|
@@ -140,7 +143,6 @@ export { MCP_CLIENT_REDIRECTS, MCP_RESOURCE_SCOPES, type McpOAuthConfigInput, ty
|
|
|
140
143
|
export { withAuditLog } from './src/mixins/with_audit_log.js';
|
|
141
144
|
export { withAuthUser } from './src/mixins/with_auth_user.js';
|
|
142
145
|
export { withCredentials } from './src/mixins/with_credentials.js';
|
|
143
|
-
export { withMfa } from './src/mixins/with_mfa.js';
|
|
144
146
|
export { withPersonalAccessToken } from './src/mixins/with_personal_access_token.js';
|
|
145
147
|
export type { ProviderIdentityClass, ProviderIdentityRow, } from './src/mixins/with_provider_identity.js';
|
|
146
148
|
export { withProviderIdentity } from './src/mixins/with_provider_identity.js';
|
package/build/index.js
CHANGED
|
@@ -19,6 +19,7 @@ export { isBlockedAddress, SafeFetchError, safeFetchJson, } from './src/agents/p
|
|
|
19
19
|
export { poppyWebSession, poppyWebSessionOf, } from './src/agents/poppy/web_session.js';
|
|
20
20
|
export { pact, pactProtocol } from './src/agents/protocol.js';
|
|
21
21
|
export { lucidAuditSink } from './src/audit/lucid_audit_sink.js';
|
|
22
|
+
export { authorizeByToken } from './src/console_authorize.js';
|
|
22
23
|
export { adapters, defineConfig, resolveAdmin, resolveAdminApi, resolveAuthMethodsConfig, resolveDynamicRegistration, resolveLogin, resolveNotifications, resolveOrganizations, resolvePasswordless, resolveRateLimit, resolveRegistration, resolveWebauthn, toSeconds, } from './src/define_config.js';
|
|
23
24
|
export { buildWebhookBody, composeAuditSink, resolveEvents, signWebhookBody, } from './src/events/dispatcher.js';
|
|
24
25
|
export { inProcessAccessTokenVerifier, remoteAccessTokenVerifier, } from './src/host/access_token_verifier.js';
|
|
@@ -103,9 +104,8 @@ export { enrichSessionsWithContext } from './src/host/session_context.js';
|
|
|
103
104
|
//
|
|
104
105
|
// `completeSudo` é público porque o host PRECISA chamá-lo: o `oidcStepUp` não
|
|
105
106
|
// registra rotas — quem valida o grant é o callback do host, e é lá que a
|
|
106
|
-
// concessão acontece
|
|
107
|
-
//
|
|
108
|
-
// o `return_to`.
|
|
107
|
+
// concessão acontece, com o audit `sudo.confirmed`, a preferência de método e o
|
|
108
|
+
// redirect para o `return_to`.
|
|
109
109
|
export { sudoMethods } from './src/host/sudo/index.js';
|
|
110
110
|
// Montador do `SudoContext` que `completeSudo`/`failSudo` recebem. Exportado
|
|
111
111
|
// junto porque sem ele o host teria de montar o contexto na mão (resolver o
|
|
@@ -116,7 +116,7 @@ export { completeSudo, fail as failSudo, LAST_METHOD_SESSION_KEY, sudoContextFro
|
|
|
116
116
|
export { isSudoActive,
|
|
117
117
|
// A DECISÃO de sudo sem efeito na resposta — o que o host chama quando quer
|
|
118
118
|
// recusar em JSON em vez de redirecionar para `/account/confirm`.
|
|
119
|
-
isSudoSatisfied,
|
|
119
|
+
isSudoSatisfied, requireSudo, resolveEffectiveSudoMode, SUDO_ACCOUNT_SESSION_KEY, SUDO_MODE_DEFAULTS, SUDO_SESSION_KEY, } from './src/host/sudo_mode.js';
|
|
120
120
|
export { barChartSvg } from './src/host/svg_chart.js';
|
|
121
121
|
export { buildTrustedDevicePayload, isTrustedDeviceValid, resolveTrustedDevices, TRUSTED_DEVICE_COOKIE, } from './src/host/trusted_device.js';
|
|
122
122
|
export { parseUserAgent } from './src/host/user_agent.js';
|
|
@@ -127,7 +127,6 @@ export { MCP_CLIENT_REDIRECTS, MCP_RESOURCE_SCOPES, registeredOAuthResources, re
|
|
|
127
127
|
export { withAuditLog } from './src/mixins/with_audit_log.js';
|
|
128
128
|
export { withAuthUser } from './src/mixins/with_auth_user.js';
|
|
129
129
|
export { withCredentials } from './src/mixins/with_credentials.js';
|
|
130
|
-
export { withMfa } from './src/mixins/with_mfa.js';
|
|
131
130
|
export { withPersonalAccessToken } from './src/mixins/with_personal_access_token.js';
|
|
132
131
|
export { withProviderIdentity } from './src/mixins/with_provider_identity.js';
|
|
133
132
|
export { withWebauthnCredential } from './src/mixins/with_webauthn_credential.js';
|
|
@@ -130,6 +130,7 @@ export default class AuthkitServerProvider {
|
|
|
130
130
|
// Defaults estruturais de `config.routes` (o argumento ainda vence).
|
|
131
131
|
routes: typeof config.routes === 'object' ? config.routes : undefined,
|
|
132
132
|
lockedRouteOptions: config.lockedRouteOptions,
|
|
133
|
+
consoleNeedsLoginUrl: config.accountSession?.acceptIdpSession === false && config.authMethods?.password === false,
|
|
133
134
|
personalAgents: config.personalAgents
|
|
134
135
|
? {
|
|
135
136
|
prefix: config.personalAgents.prefix,
|
|
@@ -146,6 +147,13 @@ export default class AuthkitServerProvider {
|
|
|
146
147
|
}
|
|
147
148
|
: undefined,
|
|
148
149
|
});
|
|
150
|
+
// Admin console without `admin.authorize`: open outside production, 403 in production.
|
|
151
|
+
// Said once, at boot.
|
|
152
|
+
if (config.admin.enabled && !config.admin.authorize) {
|
|
153
|
+
const { warnAdminConsoleUnauthorized } = await import('../src/host/admin_console_warning.js');
|
|
154
|
+
const logger = await this.app.container.make('logger').catch(() => null);
|
|
155
|
+
warnAdminConsoleUnauthorized(logger);
|
|
156
|
+
}
|
|
149
157
|
// Poppy: o slot global que o `@adonis-agora/agent` usa para autenticar o endpoint de
|
|
150
158
|
// conversas (e o MCP) sem importar este pacote — o contrato é o símbolo.
|
|
151
159
|
if (config.personalAgents?.poppy) {
|
|
@@ -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
|
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { HttpContext } from '@adonisjs/core/http';
|
|
2
|
+
/**
|
|
3
|
+
* What a console `authorize` returns. Same shape in every `@adonis-agora` console.
|
|
4
|
+
*
|
|
5
|
+
* - `true` / `{ allowed: true }` → allowed
|
|
6
|
+
* - `false` / `{ allowed: false }` → 403
|
|
7
|
+
* - `{ allowed: false, reason: 'unauthenticated' }` → 401
|
|
8
|
+
* - `{ redirectTo }` → 302 to that path on a page navigation, 401 JSON on an API call
|
|
9
|
+
*/
|
|
10
|
+
export type ConsoleAuthorizeResult = boolean | {
|
|
11
|
+
allowed: true;
|
|
12
|
+
} | {
|
|
13
|
+
allowed: false;
|
|
14
|
+
reason?: 'unauthenticated' | 'forbidden';
|
|
15
|
+
} | {
|
|
16
|
+
redirectTo: string;
|
|
17
|
+
};
|
|
18
|
+
/** A class form, for an authorizer in its own file (`@inject()` works). */
|
|
19
|
+
export interface ConsoleAuthorizer {
|
|
20
|
+
authorize(ctx: HttpContext): ConsoleAuthorizeResult | Promise<ConsoleAuthorizeResult>;
|
|
21
|
+
}
|
|
22
|
+
export type ConsoleAuthorizerClass = new (...args: any[]) => ConsoleAuthorizer;
|
|
23
|
+
/**
|
|
24
|
+
* Who may open a console: an inline function, an authorizer class, or a lazy
|
|
25
|
+
* import of a module whose default export is an authorizer class.
|
|
26
|
+
*/
|
|
27
|
+
export type ConsoleAuthorize = ((ctx: HttpContext) => ConsoleAuthorizeResult | Promise<ConsoleAuthorizeResult>) | ConsoleAuthorizerClass | (() => Promise<{
|
|
28
|
+
default: ConsoleAuthorizerClass;
|
|
29
|
+
}>);
|
|
30
|
+
/** The normalized outcome of a `ConsoleAuthorize` call. */
|
|
31
|
+
export type ConsoleAuthorizeDecision = {
|
|
32
|
+
allowed: true;
|
|
33
|
+
} | {
|
|
34
|
+
allowed: false;
|
|
35
|
+
status: 401 | 403;
|
|
36
|
+
redirectTo?: string;
|
|
37
|
+
};
|
|
38
|
+
export declare function normalizeConsoleAuthorizeResult(result: unknown): ConsoleAuthorizeDecision;
|
|
39
|
+
/**
|
|
40
|
+
* Turns a `ConsoleAuthorize` into a checker returning a normalized decision.
|
|
41
|
+
* A class is built through the container (so `@inject()` works); a lazy import
|
|
42
|
+
* runs once and its class is remembered. A thrown error is a denial (403).
|
|
43
|
+
*/
|
|
44
|
+
export declare function resolveConsoleAuthorize(authorize: ConsoleAuthorize): (ctx: HttpContext) => Promise<ConsoleAuthorizeDecision>;
|
|
45
|
+
/**
|
|
46
|
+
* A `ConsoleAuthorize` that lets in requests carrying `Authorization: Bearer <token>`.
|
|
47
|
+
* The comparison is timing-safe. Anything else is `{ allowed: false, reason: 'unauthenticated' }`.
|
|
48
|
+
* Throws when `token` is empty, so a missing env var fails at config time.
|
|
49
|
+
*
|
|
50
|
+
* ```ts
|
|
51
|
+
* authorize: authorizeByToken({ token: env.get('CONSOLE_TOKEN') })
|
|
52
|
+
* ```
|
|
53
|
+
*/
|
|
54
|
+
export declare function authorizeByToken(options: {
|
|
55
|
+
token: string | undefined | null;
|
|
56
|
+
}): (ctx: HttpContext) => ConsoleAuthorizeResult;
|