@adonis-agora/authkit-server 1.0.0-rc.1 → 1.0.0-rc.11
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 +107 -0
- package/README.md +4 -5
- package/build/commands/agora_doctor.d.ts +22 -0
- package/build/commands/agora_doctor.js +109 -0
- package/build/commands/clients_create.d.ts +4 -0
- package/build/commands/clients_create.js +97 -0
- package/build/commands/commands.json +78 -0
- package/build/commands/doctor.js +8 -74
- package/build/host/views/account/apps.edge +1 -5
- package/build/host/views/account/extension.edge +77 -0
- package/build/host/views/account/mfa.edge +2 -0
- package/build/host/views/account/partials/extension_actions.edge +14 -0
- package/build/host/views/account/partials/extension_block.edge +197 -0
- package/build/host/views/account/partials/extension_value.edge +8 -0
- package/build/host/views/account/partials/nav.edge +14 -0
- package/build/host/views/account/security.edge +1 -5
- package/build/host/views/account/tokens.edge +2 -2
- package/build/host/views/agents/consent.edge +11 -2
- package/build/host/views/agents/done.edge +1 -1
- package/build/host/views/partials/styles.edge +1 -1
- package/build/index.d.ts +12 -12
- package/build/index.js +7 -9
- package/build/providers/authkit_server_provider.js +29 -8
- package/build/src/account/extension.d.ts +10 -0
- package/build/src/account/extension.js +9 -0
- package/build/src/account/http.d.ts +77 -0
- package/build/src/account/http.js +381 -0
- package/build/src/account/mount.d.ts +40 -0
- package/build/src/account/mount.js +171 -0
- package/build/src/account/registry.d.ts +41 -0
- package/build/src/account/registry.js +81 -0
- package/build/src/account/remote.d.ts +72 -0
- package/build/src/account/remote.js +406 -0
- package/build/src/account/runtime.d.ts +289 -0
- package/build/src/account/runtime.js +641 -0
- package/build/src/accounts/account_store.d.ts +13 -7
- package/build/src/accounts/lucid_account_store.d.ts +3 -3
- package/build/src/accounts/lucid_account_store.js +42 -17
- package/build/src/accounts/lucid_store/mfa.js +3 -3
- package/build/src/accounts/lucid_store/organization_models.d.ts +14 -3
- package/build/src/accounts/lucid_store/organization_models.js +31 -3
- package/build/src/accounts/lucid_store/organizations.d.ts +2 -2
- package/build/src/accounts/lucid_store/organizations.js +40 -31
- package/build/src/accounts/lucid_store/shared.d.ts +11 -3
- package/build/src/accounts/lucid_store/shared.js +7 -5
- package/build/src/accounts/lucid_store/webauthn.js +1 -1
- package/build/src/adapters/factory.d.ts +13 -2
- package/build/src/adapters/factory.js +2 -2
- package/build/src/agents/config.d.ts +9 -13
- package/build/src/agents/config.js +17 -11
- package/build/src/agents/delegation_service.js +3 -3
- package/build/src/agents/delegation_store.d.ts +3 -2
- package/build/src/agents/delegation_store.js +6 -5
- package/build/src/agents/extension.d.ts +261 -0
- package/build/src/agents/extension.js +40 -0
- package/build/src/agents/middleware.js +1 -1
- package/build/src/agents/protocol.d.ts +4 -4
- package/build/src/agents/registry_store.d.ts +3 -2
- package/build/src/agents/registry_store.js +1 -1
- package/build/src/agents/runtime.d.ts +26 -7
- package/build/src/agents/runtime.js +110 -75
- package/build/src/audit/audit_sink.d.ts +1 -1
- package/build/src/audit/audit_sink.js +10 -1
- package/build/src/commands/expire_scan_command.js +1 -1
- package/build/src/commands/settings_commands.js +2 -2
- package/build/src/console_switcher.d.ts +132 -0
- package/build/src/console_switcher.js +206 -0
- package/build/src/define_config.d.ts +38 -13
- package/build/src/define_config.js +32 -10
- package/build/src/dev_tools/contract.d.ts +72 -0
- package/build/src/dev_tools/contract.js +10 -0
- package/build/src/dev_tools/gate.d.ts +17 -0
- package/build/src/dev_tools/gate.js +69 -0
- package/build/src/dev_tools/register.d.ts +11 -0
- package/build/src/dev_tools/register.js +25 -0
- package/build/src/dev_tools/tools.d.ts +24 -0
- package/build/src/dev_tools/tools.js +384 -0
- package/build/src/doctor/agora_checks.d.ts +15 -0
- package/build/src/doctor/agora_checks.js +150 -0
- package/build/src/doctor/agora_doctor.d.ts +115 -0
- package/build/src/doctor/agora_doctor.js +692 -0
- package/build/src/doctor/checks.js +2 -2
- package/build/src/doctor/doctor_input.d.ts +27 -0
- package/build/src/doctor/doctor_input.js +86 -0
- package/build/src/doctor/index.d.ts +5 -0
- package/build/src/doctor/index.js +4 -0
- package/build/src/host/access_token_verifier.js +7 -0
- package/build/src/host/account_api/account_api_controller.js +8 -6
- package/build/src/host/account_session_sign_in.d.ts +12 -0
- package/build/src/host/account_session_sign_in.js +19 -0
- package/build/src/host/admin_api/admin_users_service.d.ts +5 -2
- package/build/src/host/admin_api/api_clients_controller.d.ts +37 -0
- package/build/src/host/admin_api/api_clients_controller.js +31 -1
- package/build/src/host/admin_api/dto.d.ts +3 -1
- package/build/src/host/admin_api/dto.js +2 -0
- package/build/src/host/admin_authorize.d.ts +8 -0
- package/build/src/host/admin_authorize.js +25 -0
- package/build/src/host/admin_clients_service.d.ts +20 -0
- package/build/src/host/admin_clients_service.js +55 -0
- package/build/src/host/admin_console/admin_console_entry.d.ts +14 -0
- package/build/src/host/admin_console/admin_console_entry.js +80 -0
- package/build/src/host/admin_console/admin_shell_controller.js +8 -0
- package/build/src/host/admin_console/console_clients_controller.d.ts +41 -0
- package/build/src/host/admin_console/console_clients_controller.js +34 -1
- package/build/src/host/admin_console/console_personal_agents_controller.d.ts +1 -6
- package/build/src/host/admin_console/console_personal_agents_controller.js +50 -30
- package/build/src/host/admin_console/console_switcher_controller.d.ts +11 -0
- package/build/src/host/admin_console/console_switcher_controller.js +23 -0
- package/build/src/host/admin_sessions_service.js +8 -5
- package/build/src/host/admin_validators.d.ts +29 -0
- package/build/src/host/admin_validators.js +30 -0
- package/build/src/host/auth_host_config.d.ts +9 -2
- package/build/src/host/controllers/account_apps_controller.js +15 -11
- package/build/src/host/csrf.d.ts +3 -3
- package/build/src/host/csrf.js +3 -13
- package/build/src/host/default_mailer.d.ts +11 -6
- package/build/src/host/default_mailer.js +16 -12
- package/build/src/host/i18n.d.ts +41 -14
- package/build/src/host/i18n.js +55 -13
- package/build/src/host/rate_limit.d.ts +8 -0
- package/build/src/host/rate_limit.js +9 -0
- package/build/src/host/register_auth_host.d.ts +14 -0
- package/build/src/host/register_auth_host.js +167 -106
- package/build/src/host/renderers/edge_renderer.js +5 -0
- package/build/src/host/renderers/inertia_renderer.js +7 -1
- package/build/src/host/runtime_settings.d.ts +6 -6
- package/build/src/host/runtime_settings.js +4 -3
- package/build/src/host/screen_props.d.ts +39 -8
- package/build/src/host/ui-dist/assets/index-Dq3dJVBv.js +67 -0
- package/build/src/host/ui-dist/assets/{index-DTSmD4RU.css → index-WNIyCEPA.css} +1 -1
- package/build/src/host/ui-dist/index.html +2 -2
- package/build/src/provider/build_provider.js +37 -6
- package/build/src/provider/oidc_service.d.ts +1 -1
- package/build/src/provider/oidc_service.js +1 -1
- package/build/src/schema/ensure.d.ts +24 -1
- package/build/src/schema/ensure.js +44 -154
- package/build/src/schema/tables_location.d.ts +27 -0
- package/build/src/schema/tables_location.js +22 -0
- package/build/src/service_tenants/client_metadata.d.ts +39 -0
- package/build/src/service_tenants/client_metadata.js +80 -0
- package/build/src/service_tenants/config.d.ts +44 -0
- package/build/src/service_tenants/config.js +44 -0
- package/build/src/service_tenants/provider_hooks.d.ts +52 -0
- package/build/src/service_tenants/provider_hooks.js +124 -0
- package/build/src/service_tenants/tenant_verifier.d.ts +73 -0
- package/build/src/service_tenants/tenant_verifier.js +104 -0
- package/build/src/tenancy/tenant_labels.d.ts +30 -0
- package/build/src/tenancy/tenant_labels.js +64 -0
- package/build/types.d.ts +3 -1
- package/package.json +9 -6
- package/build/src/agents/poppy/client_registry.d.ts +0 -50
- package/build/src/agents/poppy/client_registry.js +0 -260
- package/build/src/agents/poppy/config.d.ts +0 -396
- package/build/src/agents/poppy/config.js +0 -228
- package/build/src/agents/poppy/dpop.d.ts +0 -61
- package/build/src/agents/poppy/dpop.js +0 -158
- package/build/src/agents/poppy/email_code_sign_in.d.ts +0 -27
- package/build/src/agents/poppy/email_code_sign_in.js +0 -140
- package/build/src/agents/poppy/errors.d.ts +0 -25
- package/build/src/agents/poppy/errors.js +0 -25
- package/build/src/agents/poppy/replay.d.ts +0 -25
- package/build/src/agents/poppy/replay.js +0 -106
- package/build/src/agents/poppy/resource.d.ts +0 -100
- package/build/src/agents/poppy/resource.js +0 -129
- package/build/src/agents/poppy/safe_fetch.d.ts +0 -48
- package/build/src/agents/poppy/safe_fetch.js +0 -262
- package/build/src/agents/poppy/service.d.ts +0 -293
- package/build/src/agents/poppy/service.js +0 -1458
- package/build/src/agents/poppy/session_jwt.d.ts +0 -30
- package/build/src/agents/poppy/session_jwt.js +0 -133
- package/build/src/agents/poppy/store.d.ts +0 -106
- package/build/src/agents/poppy/store.js +0 -261
- package/build/src/agents/poppy/web_session.d.ts +0 -39
- package/build/src/agents/poppy/web_session.js +0 -122
- package/build/src/host/controllers/poppy_consent_controller.d.ts +0 -19
- package/build/src/host/controllers/poppy_consent_controller.js +0 -199
- package/build/src/host/controllers/poppy_controller.d.ts +0 -33
- package/build/src/host/controllers/poppy_controller.js +0 -219
- package/build/src/host/poppy_session_key.d.ts +0 -9
- package/build/src/host/poppy_session_key.js +0 -9
- package/build/src/host/ui-dist/assets/index-D0EIeyKK.js +0 -67
|
@@ -1,158 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Verificação de provas DPoP (RFC 9449) — utilitário genérico para o token
|
|
3
|
-
* endpoint e para resource servers (§4.5 do Poppy).
|
|
4
|
-
*
|
|
5
|
-
* Confere: um único header `DPoP`; `typ` `dpop+jwt`; algoritmo permitido; `jwk`
|
|
6
|
-
* público no header e a assinatura com ele; `jti`, `htm`, `htu` (sem query nem
|
|
7
|
-
* fragmento), `iat` dentro da janela; `ath` = SHA-256 do access token; o
|
|
8
|
-
* `nonce` quando exigido; replay do `jti` na janela; e, num resource server, que
|
|
9
|
-
* a chave é a do token (`cnf.jkt`).
|
|
10
|
-
*/
|
|
11
|
-
import { createHash, createHmac, timingSafeEqual } from 'node:crypto';
|
|
12
|
-
import { calculateJwkThumbprint, decodeProtectedHeader, EmbeddedJWK, jwtVerify, } from 'jose';
|
|
13
|
-
import { replayKey } from './replay.js';
|
|
14
|
-
/**
|
|
15
|
-
* Nonces sem estado: `base64url(ts).base64url(hmac(ts))`, válidos por
|
|
16
|
-
* `ttlSeconds` (default 300). Qualquer instância com o mesmo segredo valida.
|
|
17
|
-
*
|
|
18
|
-
* @experimental Poppy (Personal Agent Protocol) Draft 0.3 — acompanha a spec em desenvolvimento e PODE MUDAR
|
|
19
|
-
* de forma incompatível fora de majors enquanto ela for draft.
|
|
20
|
-
*/
|
|
21
|
-
export function hmacNonceSource(secret, options = {}) {
|
|
22
|
-
const ttl = (options.ttlSeconds ?? 300) * 1000;
|
|
23
|
-
const now = options.now ?? Date.now;
|
|
24
|
-
const mac = (ts) => createHmac('sha256', secret).update(`dpop-nonce:${ts}`).digest('base64url');
|
|
25
|
-
return {
|
|
26
|
-
issue() {
|
|
27
|
-
const ts = Buffer.from(String(now())).toString('base64url');
|
|
28
|
-
return `${ts}.${mac(ts)}`;
|
|
29
|
-
},
|
|
30
|
-
valid(nonce) {
|
|
31
|
-
const [ts, sig] = nonce.split('.');
|
|
32
|
-
if (!ts || !sig)
|
|
33
|
-
return false;
|
|
34
|
-
const expected = Buffer.from(mac(ts));
|
|
35
|
-
const given = Buffer.from(sig);
|
|
36
|
-
if (expected.length !== given.length || !timingSafeEqual(expected, given))
|
|
37
|
-
return false;
|
|
38
|
-
const issuedAt = Number(Buffer.from(ts, 'base64url').toString());
|
|
39
|
-
const t = now();
|
|
40
|
-
return Number.isFinite(issuedAt) && issuedAt <= t + 5000 && t - issuedAt <= ttl;
|
|
41
|
-
},
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
/** `ath`: base64url(SHA-256(access token)). */
|
|
45
|
-
export function accessTokenHash(token) {
|
|
46
|
-
return createHash('sha256').update(token).digest('base64url');
|
|
47
|
-
}
|
|
48
|
-
/**
|
|
49
|
-
* `htu` normalizado para comparação: esquema e host minúsculos, sem porta
|
|
50
|
-
* default, sem query nem fragmento. `null` se não for URL http(s).
|
|
51
|
-
*/
|
|
52
|
-
export function normalizeHtu(value) {
|
|
53
|
-
try {
|
|
54
|
-
const url = new URL(value);
|
|
55
|
-
if (url.protocol !== 'https:' && url.protocol !== 'http:')
|
|
56
|
-
return null;
|
|
57
|
-
url.hash = '';
|
|
58
|
-
url.search = '';
|
|
59
|
-
return url.toString();
|
|
60
|
-
}
|
|
61
|
-
catch {
|
|
62
|
-
return null;
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
function failure(error, description) {
|
|
66
|
-
return { ok: false, error, description };
|
|
67
|
-
}
|
|
68
|
-
/**
|
|
69
|
-
* @experimental Poppy (Personal Agent Protocol) Draft 0.3 — pode mudar de forma incompatível enquanto a spec for draft.
|
|
70
|
-
*/
|
|
71
|
-
export async function verifyDpopProof(input) {
|
|
72
|
-
const raw = input.proof;
|
|
73
|
-
if (raw === undefined || raw === null || raw === '') {
|
|
74
|
-
return failure('invalid_dpop_proof', 'DPoP proof is missing');
|
|
75
|
-
}
|
|
76
|
-
if (Array.isArray(raw) ? raw.length !== 1 : raw.includes(',')) {
|
|
77
|
-
return failure('invalid_dpop_proof', 'Exactly one DPoP proof is allowed');
|
|
78
|
-
}
|
|
79
|
-
const proof = Array.isArray(raw) ? raw[0] : raw;
|
|
80
|
-
let header;
|
|
81
|
-
try {
|
|
82
|
-
header = decodeProtectedHeader(proof);
|
|
83
|
-
}
|
|
84
|
-
catch {
|
|
85
|
-
return failure('invalid_dpop_proof', 'Malformed DPoP proof');
|
|
86
|
-
}
|
|
87
|
-
if (header.typ !== 'dpop+jwt')
|
|
88
|
-
return failure('invalid_dpop_proof', 'typ must be dpop+jwt');
|
|
89
|
-
if (!header.alg || !input.algorithms.includes(header.alg)) {
|
|
90
|
-
return failure('invalid_dpop_proof', 'Unsupported DPoP algorithm');
|
|
91
|
-
}
|
|
92
|
-
const jwk = header.jwk;
|
|
93
|
-
if (!jwk || typeof jwk !== 'object')
|
|
94
|
-
return failure('invalid_dpop_proof', 'jwk header is required');
|
|
95
|
-
if ('d' in jwk || jwk.kty === 'oct') {
|
|
96
|
-
return failure('invalid_dpop_proof', 'jwk must be a public key');
|
|
97
|
-
}
|
|
98
|
-
const nowMs = (input.now ?? Date.now)();
|
|
99
|
-
let payload;
|
|
100
|
-
try {
|
|
101
|
-
({ payload } = await jwtVerify(proof, EmbeddedJWK, {
|
|
102
|
-
algorithms: input.algorithms,
|
|
103
|
-
typ: 'dpop+jwt',
|
|
104
|
-
currentDate: new Date(nowMs),
|
|
105
|
-
}));
|
|
106
|
-
}
|
|
107
|
-
catch {
|
|
108
|
-
return failure('invalid_dpop_proof', 'DPoP proof signature is invalid');
|
|
109
|
-
}
|
|
110
|
-
const { jti, htm, htu, iat, ath, nonce } = payload;
|
|
111
|
-
if (typeof jti !== 'string' || jti.length < 8 || jti.length > 256) {
|
|
112
|
-
return failure('invalid_dpop_proof', 'jti is required');
|
|
113
|
-
}
|
|
114
|
-
if (typeof htm !== 'string' || htm !== input.method.toUpperCase()) {
|
|
115
|
-
return failure('invalid_dpop_proof', 'htm does not match the request method');
|
|
116
|
-
}
|
|
117
|
-
const expectedHtu = normalizeHtu(input.url);
|
|
118
|
-
if (typeof htu !== 'string' || !expectedHtu || normalizeHtu(htu) !== expectedHtu) {
|
|
119
|
-
return failure('invalid_dpop_proof', 'htu does not match the request URL');
|
|
120
|
-
}
|
|
121
|
-
const nowS = Math.floor(nowMs / 1000);
|
|
122
|
-
const skew = input.clockSkew ?? 5;
|
|
123
|
-
if (typeof iat !== 'number' || iat > nowS + skew || iat < nowS - input.maxAge) {
|
|
124
|
-
return failure('invalid_dpop_proof', 'iat is outside the acceptance window');
|
|
125
|
-
}
|
|
126
|
-
if (input.accessToken !== undefined) {
|
|
127
|
-
if (typeof ath !== 'string' || ath !== accessTokenHash(input.accessToken)) {
|
|
128
|
-
return failure('invalid_dpop_proof', 'ath does not match the access token');
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
let jkt;
|
|
132
|
-
try {
|
|
133
|
-
jkt = await calculateJwkThumbprint(jwk, 'sha256');
|
|
134
|
-
}
|
|
135
|
-
catch {
|
|
136
|
-
return failure('invalid_dpop_proof', 'Invalid jwk');
|
|
137
|
-
}
|
|
138
|
-
if (input.expectedJkt !== undefined && jkt !== input.expectedJkt) {
|
|
139
|
-
return failure('invalid_dpop_proof', 'DPoP key does not match the token binding');
|
|
140
|
-
}
|
|
141
|
-
if (input.nonce?.required) {
|
|
142
|
-
if (typeof nonce !== 'string' || !input.nonce.source.valid(nonce)) {
|
|
143
|
-
return failure('use_dpop_nonce', 'A DPoP nonce issued by the server is required');
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
else if (nonce !== undefined && input.nonce && typeof nonce === 'string') {
|
|
147
|
-
// Nonce mandado sem ser exigido: se vier, tem de ser um nosso e válido.
|
|
148
|
-
if (!input.nonce.source.valid(nonce)) {
|
|
149
|
-
return failure('use_dpop_nonce', 'The DPoP nonce is invalid or expired');
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
// Replay por último: uma prova inválida não queima o `jti`.
|
|
153
|
-
const expiresAt = new Date((iat + input.maxAge + skew) * 1000);
|
|
154
|
-
if (!(await input.replay.claim(replayKey('dpop', jkt, jti), expiresAt))) {
|
|
155
|
-
return failure('invalid_dpop_proof', 'DPoP proof was already used');
|
|
156
|
-
}
|
|
157
|
-
return { ok: true, jkt, jti };
|
|
158
|
-
}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { type AuthAccount } from '../../accounts/account_store.js';
|
|
2
|
-
import type { PoppyMediatedConfigInput } from './config.js';
|
|
3
|
-
export interface PoppyEmailCodeSignInOptions {
|
|
4
|
-
/** Scopes que este sign-in pode conceder. */
|
|
5
|
-
scopes: string[];
|
|
6
|
-
/** Validade do código, em segundos. Default: 600. */
|
|
7
|
-
codeTtl?: number;
|
|
8
|
-
/** Tentativas de código antes de `invalid_grant`. Default: 5. */
|
|
9
|
-
maxCodeAttempts?: number;
|
|
10
|
-
/**
|
|
11
|
-
* Quem pode entrar por aqui (ex.: só pacientes, não profissionais). `false` = recebe a
|
|
12
|
-
* resposta de conta inexistente. Default: toda conta ativa.
|
|
13
|
-
*/
|
|
14
|
-
eligible?: (account: AuthAccount) => boolean | Promise<boolean>;
|
|
15
|
-
/**
|
|
16
|
-
* Códigos por e-mail por hora, nesta instância — impede um agente de lotar a caixa de
|
|
17
|
-
* alguém. Acima disso a resposta é a mesma, sem e-mail. Default: 5.
|
|
18
|
-
*/
|
|
19
|
-
maxPerHour?: number;
|
|
20
|
-
/** Rótulo do campo que o agente mostra ao usuário. Default: `'Email address'`. */
|
|
21
|
-
label?: string;
|
|
22
|
-
/** Texto de `sentTo` a partir do e-mail mascarado. Default: `` `Email to ${masked}` ``. */
|
|
23
|
-
sentTo?: (masked: string) => string;
|
|
24
|
-
}
|
|
25
|
-
/** `ana.souza@gmail.com` → `a***@gmail.com`: o bastante para a pessoa reconhecer. */
|
|
26
|
-
export declare function maskEmail(email: string): string;
|
|
27
|
-
export declare function poppyEmailCodeSignIn(options: PoppyEmailCodeSignInOptions): PoppyMediatedConfigInput;
|
|
@@ -1,140 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @experimental Poppy (Personal Agent Protocol) Draft 0.3 — pode mudar de forma incompatível enquanto a spec for draft.
|
|
3
|
-
*
|
|
4
|
-
* Mediated Sign-In pronto (extensão `mediated-sign-in`): o agente pede o e-mail da conta, o authkit manda
|
|
5
|
-
* um código de 6 dígitos para ele e o agente devolve o código. Usa as contas
|
|
6
|
-
* (`accountStore`) e o e-mail (hook `mail.onPoppySignInCode` ou o mailer default)
|
|
7
|
-
* do próprio authkit — o app só liga:
|
|
8
|
-
*
|
|
9
|
-
* ```ts
|
|
10
|
-
* personalAgents: {
|
|
11
|
-
* poppy: { signIn: { mediated: poppyEmailCodeSignIn({ scopes: ['orders:read'] }) } },
|
|
12
|
-
* }
|
|
13
|
-
* ```
|
|
14
|
-
*
|
|
15
|
-
* Sem enumeração de contas: e-mail sem conta, conta desativada, conta recusada
|
|
16
|
-
* por `eligible` ou e-mail acima do limite recebem a MESMA resposta, sem código
|
|
17
|
-
* (`accountId: null`) — a lib recusa qualquer código como errado. O envio não é
|
|
18
|
-
* esperado, então o tempo de resposta também não denuncia.
|
|
19
|
-
*/
|
|
20
|
-
import { randomInt } from 'node:crypto';
|
|
21
|
-
import { supportsAccountStatus } from '../../accounts/account_store.js';
|
|
22
|
-
import { sendPoppySignInCodeEmail } from '../../host/default_mailer.js';
|
|
23
|
-
import { personalAgentsFor } from '../runtime.js';
|
|
24
|
-
/** `ana.souza@gmail.com` → `a***@gmail.com`: o bastante para a pessoa reconhecer. */
|
|
25
|
-
export function maskEmail(email) {
|
|
26
|
-
const at = email.lastIndexOf('@');
|
|
27
|
-
const user = at > 0 ? email.slice(0, at) : '';
|
|
28
|
-
const domain = at > 0 ? email.slice(at + 1) : '';
|
|
29
|
-
if (!user || !domain)
|
|
30
|
-
return '***';
|
|
31
|
-
return `${user[0]}***@${domain}`;
|
|
32
|
-
}
|
|
33
|
-
const EMAIL = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
34
|
-
const HOUR_MS = 3600 * 1000;
|
|
35
|
-
const MAX_TRACKED = 10_000;
|
|
36
|
-
export function poppyEmailCodeSignIn(options) {
|
|
37
|
-
const positive = (value, fallback, what) => {
|
|
38
|
-
if (value === undefined)
|
|
39
|
-
return fallback;
|
|
40
|
-
if (!Number.isFinite(value) || value < 1) {
|
|
41
|
-
throw new Error(`authkit: poppyEmailCodeSignIn ${what} precisa ser um número >= 1.`);
|
|
42
|
-
}
|
|
43
|
-
return Math.floor(value);
|
|
44
|
-
};
|
|
45
|
-
const codeTtl = positive(options.codeTtl, 600, 'codeTtl');
|
|
46
|
-
const maxPerHour = positive(options.maxPerHour, 5, 'maxPerHour');
|
|
47
|
-
const maxCodeAttempts = positive(options.maxCodeAttempts, 5, 'maxCodeAttempts');
|
|
48
|
-
const sentToText = options.sentTo ?? ((masked) => `Email to ${masked}`);
|
|
49
|
-
const sends = new Map();
|
|
50
|
-
/** `true` = ainda cabe um envio para este e-mail na última hora (e conta este). */
|
|
51
|
-
const claim = (email) => {
|
|
52
|
-
const now = Date.now();
|
|
53
|
-
const recent = (sends.get(email) ?? []).filter((t) => now - t < HOUR_MS);
|
|
54
|
-
if (recent.length >= maxPerHour) {
|
|
55
|
-
sends.set(email, recent);
|
|
56
|
-
return false;
|
|
57
|
-
}
|
|
58
|
-
recent.push(now);
|
|
59
|
-
sends.delete(email);
|
|
60
|
-
sends.set(email, recent);
|
|
61
|
-
if (sends.size > MAX_TRACKED)
|
|
62
|
-
sends.delete(sends.keys().next().value);
|
|
63
|
-
return true;
|
|
64
|
-
};
|
|
65
|
-
const eligibleAccount = async (ctx, email) => {
|
|
66
|
-
const service = await ctx.containerResolver.make('authkit.server');
|
|
67
|
-
const store = service.config.accountStore;
|
|
68
|
-
const account = await store.findByEmail(email);
|
|
69
|
-
if (!account)
|
|
70
|
-
return null;
|
|
71
|
-
if (supportsAccountStatus(store) && (await store.isDisabled(account.id)))
|
|
72
|
-
return null;
|
|
73
|
-
if (options.eligible) {
|
|
74
|
-
// Um `eligible` que lança vira "não elegível": um 500 só para algumas contas as denunciaria.
|
|
75
|
-
try {
|
|
76
|
-
if (!(await options.eligible(account)))
|
|
77
|
-
return null;
|
|
78
|
-
}
|
|
79
|
-
catch (error) {
|
|
80
|
-
ctx.logger.error({ err: error }, 'authkit: poppyEmailCodeSignIn eligible lançou');
|
|
81
|
-
return null;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
return account;
|
|
85
|
-
};
|
|
86
|
-
return {
|
|
87
|
-
fields: [{ name: 'email', label: options.label ?? 'Email address', secret: false }],
|
|
88
|
-
scopes: options.scopes,
|
|
89
|
-
codeTtl,
|
|
90
|
-
maxCodeAttempts,
|
|
91
|
-
async verify({ credentials, clientId, ctx }) {
|
|
92
|
-
const email = (credentials.email ?? '').trim().toLowerCase();
|
|
93
|
-
if (!EMAIL.test(email))
|
|
94
|
-
return { status: 'failed' };
|
|
95
|
-
const sentTo = sentToText(maskEmail(email));
|
|
96
|
-
const decoy = { status: 'code_required', accountId: null, sentTo };
|
|
97
|
-
// O limite conta para qualquer e-mail — com ou sem conta, a resposta não muda.
|
|
98
|
-
if (!claim(email))
|
|
99
|
-
return decoy;
|
|
100
|
-
const account = await eligibleAccount(ctx, email);
|
|
101
|
-
if (!account)
|
|
102
|
-
return decoy;
|
|
103
|
-
const code = String(randomInt(0, 1_000_000)).padStart(6, '0');
|
|
104
|
-
// Sem `await`: o caminho com conta não pode demorar mais que o sem conta.
|
|
105
|
-
void deliver(ctx, { email, code, clientId, expiresInMinutes: Math.ceil(codeTtl / 60) });
|
|
106
|
-
return { status: 'code_required', accountId: account.id, sentTo, code };
|
|
107
|
-
},
|
|
108
|
-
};
|
|
109
|
-
}
|
|
110
|
-
function hostOf(clientId) {
|
|
111
|
-
try {
|
|
112
|
-
return new URL(clientId).host;
|
|
113
|
-
}
|
|
114
|
-
catch {
|
|
115
|
-
return clientId;
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
async function deliver(ctx, data) {
|
|
119
|
-
try {
|
|
120
|
-
const runtime = await personalAgentsFor(ctx);
|
|
121
|
-
const agentName = runtime?.poppy
|
|
122
|
-
? await runtime.poppy.registry.displayName(data.clientId)
|
|
123
|
-
: hostOf(data.clientId);
|
|
124
|
-
const service = await ctx.containerResolver.make('authkit.server');
|
|
125
|
-
const hook = service.config.mail?.onPoppySignInCode;
|
|
126
|
-
const input = {
|
|
127
|
-
email: data.email,
|
|
128
|
-
code: data.code,
|
|
129
|
-
agentName,
|
|
130
|
-
expiresInMinutes: data.expiresInMinutes,
|
|
131
|
-
};
|
|
132
|
-
if (hook)
|
|
133
|
-
await hook(input);
|
|
134
|
-
else
|
|
135
|
-
await sendPoppySignInCodeEmail(ctx, input);
|
|
136
|
-
}
|
|
137
|
-
catch (error) {
|
|
138
|
-
ctx.logger.error({ err: error }, 'authkit: o código do Poppy Mediated Sign-In não saiu');
|
|
139
|
-
}
|
|
140
|
-
}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Erros OAuth do Poppy (§4.7, RFC 6749 §5.2, RFC 8628 §3.5, RFC 9449, extensão Mediated Sign-In)
|
|
3
|
-
* — viram `{ error, error_description }` com o status da spec.
|
|
4
|
-
*/
|
|
5
|
-
export type PoppyErrorCode = 'invalid_request' | 'invalid_client' | 'invalid_grant' | 'invalid_session' | 'invalid_dpop_proof' | 'use_dpop_nonce'
|
|
6
|
-
/** Interno: HTTP 429 com `Retry-After`, sem corpo (§5.6). */
|
|
7
|
-
| 'too_many_requests' | 'code_required' | 'invalid_scope' | 'invalid_target' | 'unsupported_grant_type' | 'unsupported_token_type' | 'unauthorized_client' | 'authorization_pending' | 'slow_down' | 'access_denied' | 'expired_token';
|
|
8
|
-
export declare class PoppyError extends Error {
|
|
9
|
-
readonly code: PoppyErrorCode;
|
|
10
|
-
readonly description: string;
|
|
11
|
-
readonly status: number;
|
|
12
|
-
/** Headers extras da resposta (`DPoP-Nonce`, `Retry-After`). */
|
|
13
|
-
readonly headers: Record<string, string>;
|
|
14
|
-
/** Campos extras do corpo (`sign_in_id`, `sent_to`, `expires_in` do `code_required`). */
|
|
15
|
-
readonly extra: Record<string, unknown>;
|
|
16
|
-
constructor(code: PoppyErrorCode, description: string, options?: {
|
|
17
|
-
status?: number;
|
|
18
|
-
headers?: Record<string, string>;
|
|
19
|
-
extra?: Record<string, unknown>;
|
|
20
|
-
});
|
|
21
|
-
toJSON(): {
|
|
22
|
-
error: PoppyErrorCode;
|
|
23
|
-
error_description: string;
|
|
24
|
-
};
|
|
25
|
-
}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
const STATUS = {
|
|
2
|
-
invalid_client: 401,
|
|
3
|
-
too_many_requests: 429,
|
|
4
|
-
};
|
|
5
|
-
export class PoppyError extends Error {
|
|
6
|
-
code;
|
|
7
|
-
description;
|
|
8
|
-
status;
|
|
9
|
-
/** Headers extras da resposta (`DPoP-Nonce`, `Retry-After`). */
|
|
10
|
-
headers;
|
|
11
|
-
/** Campos extras do corpo (`sign_in_id`, `sent_to`, `expires_in` do `code_required`). */
|
|
12
|
-
extra;
|
|
13
|
-
constructor(code, description, options = {}) {
|
|
14
|
-
super(description);
|
|
15
|
-
this.code = code;
|
|
16
|
-
this.description = description;
|
|
17
|
-
this.name = 'PoppyError';
|
|
18
|
-
this.status = options.status ?? STATUS[code] ?? 400;
|
|
19
|
-
this.headers = options.headers ?? {};
|
|
20
|
-
this.extra = options.extra ?? {};
|
|
21
|
-
}
|
|
22
|
-
toJSON() {
|
|
23
|
-
return { error: this.code, error_description: this.description, ...this.extra };
|
|
24
|
-
}
|
|
25
|
-
}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import type { PoppyLimiter, PoppyReplayStore } from './config.js';
|
|
2
|
-
export declare const JTI_TABLE = "auth_poppy_jtis";
|
|
3
|
-
/** Chave curta e de tamanho fixo para um `jti` de um tipo/agente. */
|
|
4
|
-
export declare function replayKey(kind: string, ...parts: string[]): string;
|
|
5
|
-
/** Em memória, por processo. Só serve com uma instância. */
|
|
6
|
-
export declare function memoryReplayStore(options?: {
|
|
7
|
-
max?: number;
|
|
8
|
-
now?: () => number;
|
|
9
|
-
}): PoppyReplayStore;
|
|
10
|
-
/**
|
|
11
|
-
* Na tabela lib-owned `auth_poppy_jtis` (PK = chave): o INSERT de uma chave que
|
|
12
|
-
* já existe falha — atômico entre instâncias. Linhas vencidas saem aos poucos.
|
|
13
|
-
*/
|
|
14
|
-
export declare function databaseReplayStore(conn: () => any, options?: {
|
|
15
|
-
now?: () => Date;
|
|
16
|
-
}): PoppyReplayStore;
|
|
17
|
-
/** Numa conexão Redis (`SET key 1 PX ttl NX`). */
|
|
18
|
-
export declare function redisReplayStore(redis: {
|
|
19
|
-
set: (...args: any[]) => Promise<unknown>;
|
|
20
|
-
}): PoppyReplayStore;
|
|
21
|
-
/** Janelas fixas em memória, por processo: `sessionsPerMinute` por agente, `mediatedPerHour` por (agente, usuário). */
|
|
22
|
-
export declare function memoryLimiter(limits: {
|
|
23
|
-
sessionsPerMinute: number;
|
|
24
|
-
mediatedPerHour: number;
|
|
25
|
-
}, now?: () => number): PoppyLimiter;
|
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Proteção contra replay (`jti` de asserções, client assertions, provas DPoP e
|
|
3
|
-
* asserções de navegador) e limites de taxa do Poppy.
|
|
4
|
-
*/
|
|
5
|
-
import { createHash } from 'node:crypto';
|
|
6
|
-
export const JTI_TABLE = 'auth_poppy_jtis';
|
|
7
|
-
/** Chave curta e de tamanho fixo para um `jti` de um tipo/agente. */
|
|
8
|
-
export function replayKey(kind, ...parts) {
|
|
9
|
-
return `${kind}:${createHash('sha256').update(parts.join('\u0000')).digest('base64url')}`;
|
|
10
|
-
}
|
|
11
|
-
/** Em memória, por processo. Só serve com uma instância. */
|
|
12
|
-
export function memoryReplayStore(options = {}) {
|
|
13
|
-
const seen = new Map();
|
|
14
|
-
const max = options.max ?? 100_000;
|
|
15
|
-
const now = options.now ?? Date.now;
|
|
16
|
-
let claims = 0;
|
|
17
|
-
return {
|
|
18
|
-
async claim(key, expiresAt) {
|
|
19
|
-
const t = now();
|
|
20
|
-
if (++claims % 1000 === 0 || seen.size >= max) {
|
|
21
|
-
for (const [k, exp] of seen)
|
|
22
|
-
if (exp <= t)
|
|
23
|
-
seen.delete(k);
|
|
24
|
-
}
|
|
25
|
-
const existing = seen.get(key);
|
|
26
|
-
if (existing !== undefined && existing > t)
|
|
27
|
-
return false;
|
|
28
|
-
if (seen.size >= max)
|
|
29
|
-
seen.delete(seen.keys().next().value);
|
|
30
|
-
seen.set(key, expiresAt.getTime());
|
|
31
|
-
return true;
|
|
32
|
-
},
|
|
33
|
-
};
|
|
34
|
-
}
|
|
35
|
-
/**
|
|
36
|
-
* Na tabela lib-owned `auth_poppy_jtis` (PK = chave): o INSERT de uma chave que
|
|
37
|
-
* já existe falha — atômico entre instâncias. Linhas vencidas saem aos poucos.
|
|
38
|
-
*/
|
|
39
|
-
export function databaseReplayStore(conn, options = {}) {
|
|
40
|
-
const now = options.now ?? (() => new Date());
|
|
41
|
-
let claims = 0;
|
|
42
|
-
return {
|
|
43
|
-
async claim(key, expiresAt) {
|
|
44
|
-
const t = now();
|
|
45
|
-
if (++claims % 200 === 1) {
|
|
46
|
-
await conn().from(JTI_TABLE).where('expires_at', '<', t).delete();
|
|
47
|
-
}
|
|
48
|
-
try {
|
|
49
|
-
await conn().table(JTI_TABLE).insert({ key, expires_at: expiresAt });
|
|
50
|
-
return true;
|
|
51
|
-
}
|
|
52
|
-
catch (error) {
|
|
53
|
-
// Chave já usada — a não ser que a linha vencida ainda não tenha saído.
|
|
54
|
-
const row = await conn().from(JTI_TABLE).where('key', key).first();
|
|
55
|
-
if (!row)
|
|
56
|
-
throw error;
|
|
57
|
-
const exp = row.expires_at instanceof Date
|
|
58
|
-
? row.expires_at
|
|
59
|
-
: new Date(Number(row.expires_at) || row.expires_at);
|
|
60
|
-
if (exp.getTime() > t.getTime())
|
|
61
|
-
return false;
|
|
62
|
-
const updated = await conn()
|
|
63
|
-
.from(JTI_TABLE)
|
|
64
|
-
.where('key', key)
|
|
65
|
-
.where('expires_at', '<=', t)
|
|
66
|
-
.update({ expires_at: expiresAt });
|
|
67
|
-
return ((typeof updated === 'number' ? updated : Array.isArray(updated) ? updated.length : 0) > 0);
|
|
68
|
-
}
|
|
69
|
-
},
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
/** Numa conexão Redis (`SET key 1 PX ttl NX`). */
|
|
73
|
-
export function redisReplayStore(redis) {
|
|
74
|
-
return {
|
|
75
|
-
async claim(key, expiresAt) {
|
|
76
|
-
const ttl = Math.max(1000, expiresAt.getTime() - Date.now());
|
|
77
|
-
const result = await redis.set(`authkit:poppy:jti:${key}`, '1', 'PX', ttl, 'NX');
|
|
78
|
-
return result === 'OK';
|
|
79
|
-
},
|
|
80
|
-
};
|
|
81
|
-
}
|
|
82
|
-
/** Janelas fixas em memória, por processo: `sessionsPerMinute` por agente, `mediatedPerHour` por (agente, usuário). */
|
|
83
|
-
export function memoryLimiter(limits, now = Date.now) {
|
|
84
|
-
const windows = new Map();
|
|
85
|
-
return async ({ action, key }) => {
|
|
86
|
-
const [limit, windowMs] = action === 'session'
|
|
87
|
-
? [limits.sessionsPerMinute, 60_000]
|
|
88
|
-
: [limits.mediatedPerHour, 3_600_000];
|
|
89
|
-
const t = now();
|
|
90
|
-
const id = `${action}:${key}`;
|
|
91
|
-
let w = windows.get(id);
|
|
92
|
-
if (!w || t - w.start >= windowMs) {
|
|
93
|
-
w = { start: t, count: 0 };
|
|
94
|
-
windows.set(id, w);
|
|
95
|
-
if (windows.size > 50_000) {
|
|
96
|
-
for (const [k, v] of windows)
|
|
97
|
-
if (t - v.start >= 3_600_000)
|
|
98
|
-
windows.delete(k);
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
if (w.count >= limit)
|
|
102
|
-
return Math.ceil((w.start + windowMs - t) / 1000);
|
|
103
|
-
w.count++;
|
|
104
|
-
return null;
|
|
105
|
-
};
|
|
106
|
-
}
|
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Lado resource server do Poppy (§4.5, §5.3, §7): verificar o header `Poppy-Session` e o access
|
|
3
|
-
* token de uma request às APIs/conversas do app — e o slot GLOBAL que o `@adonis-agora/agent` usa
|
|
4
|
-
* para autenticar o endpoint de conversas sem importar este pacote.
|
|
5
|
-
*
|
|
6
|
-
* Contrato do slot (o mesmo padrão do `Symbol.for('@adonis-agora/oauth:resources')`):
|
|
7
|
-
*
|
|
8
|
-
* ```ts
|
|
9
|
-
* const authenticate = globalThis[Symbol.for('@adonis-agora/poppy:authenticate')]
|
|
10
|
-
* const result = await authenticate({ method, url, headers }, { scopes?, signedIn?, resource? })
|
|
11
|
-
* // { ok: true, principal } | { ok: false, status, error, scope?, wwwAuthenticate, headers }
|
|
12
|
-
* ```
|
|
13
|
-
*/
|
|
14
|
-
import type { HttpContext } from '@adonisjs/core/http';
|
|
15
|
-
import type { PoppyPrincipalBase } from './config.js';
|
|
16
|
-
import type { PoppyAuthError, PoppyService, PoppyVerifyOptions } from './service.js';
|
|
17
|
-
/** Símbolo do slot global de autenticação Poppy. */
|
|
18
|
-
export declare const POPPY_AUTHENTICATE_SLOT: unique symbol;
|
|
19
|
-
/**
|
|
20
|
-
* O principal de uma request verificada.
|
|
21
|
-
*
|
|
22
|
-
* @experimental Poppy (Personal Agent Protocol) Draft 0.3 — acompanha a spec em desenvolvimento e PODE MUDAR
|
|
23
|
-
* de forma incompatível fora de majors enquanto ela for draft.
|
|
24
|
-
*/
|
|
25
|
-
export interface PoppyPrincipal extends PoppyPrincipalBase {
|
|
26
|
-
/** O que `personalAgents.poppy.toActor` devolveu, quando configurado. */
|
|
27
|
-
actor?: unknown;
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
|
-
* @experimental Poppy (Personal Agent Protocol) Draft 0.3 — pode mudar de forma incompatível enquanto a spec for draft.
|
|
31
|
-
*/
|
|
32
|
-
export type PoppyAuthResult = {
|
|
33
|
-
ok: true;
|
|
34
|
-
principal: PoppyPrincipal;
|
|
35
|
-
} | {
|
|
36
|
-
ok: false;
|
|
37
|
-
status: 400 | 401 | 403 | 429;
|
|
38
|
-
/** `null`: challenge sem código (falta o access token, §7) ou limite de taxa (§5.6). */
|
|
39
|
-
error: PoppyAuthError | null;
|
|
40
|
-
/** Scopes exigidos (challenge e `insufficient_scope`). */
|
|
41
|
-
scope?: string;
|
|
42
|
-
/** Valor pronto do header `WWW-Authenticate`; `null` em `invalid_session` e no 429. */
|
|
43
|
-
wwwAuthenticate: string | null;
|
|
44
|
-
/** Texto para logs/corpo — nunca contém o token. */
|
|
45
|
-
description: string;
|
|
46
|
-
/** Headers extras a devolver (`DPoP-Nonce`, `Retry-After`). */
|
|
47
|
-
headers: Record<string, string>;
|
|
48
|
-
};
|
|
49
|
-
/** Request no formato do slot (sem `HttpContext`). */
|
|
50
|
-
export interface PoppySlotRequest {
|
|
51
|
-
method: string;
|
|
52
|
-
/** URL pública completa da request (a query é ignorada). */
|
|
53
|
-
url: string;
|
|
54
|
-
headers: Record<string, string | string[] | undefined>;
|
|
55
|
-
}
|
|
56
|
-
export type PoppyAuthenticate = (request: PoppySlotRequest, options?: PoppyVerifyOptions) => Promise<PoppyAuthResult>;
|
|
57
|
-
/** URL pública da request: atrás de proxy TLS, o esquema segue o do issuer. */
|
|
58
|
-
export declare function publicRequestUrl(ctx: HttpContext, poppy: PoppyService): string;
|
|
59
|
-
/**
|
|
60
|
-
* Verifica o header `Poppy-Session` de uma request e, se houver, o access token. Aceita o
|
|
61
|
-
* `HttpContext` ou `{ method, url, headers }`.
|
|
62
|
-
*
|
|
63
|
-
* @experimental Poppy (Personal Agent Protocol) Draft 0.3 — acompanha a spec em desenvolvimento e PODE MUDAR
|
|
64
|
-
* de forma incompatível fora de majors enquanto ela for draft.
|
|
65
|
-
*/
|
|
66
|
-
export declare function verifyPoppyRequest(input: HttpContext | PoppySlotRequest, options?: PoppyVerifyOptions): Promise<PoppyAuthResult>;
|
|
67
|
-
/** Escreve a resposta de erro de um {@link PoppyAuthResult} recusado. */
|
|
68
|
-
export declare function writePoppyAuthError(ctx: HttpContext, result: Extract<PoppyAuthResult, {
|
|
69
|
-
ok: false;
|
|
70
|
-
}>): void;
|
|
71
|
-
/**
|
|
72
|
-
* O principal Poppy da request — preenchido por {@link poppyAuth}.
|
|
73
|
-
*
|
|
74
|
-
* @experimental Poppy (Personal Agent Protocol) Draft 0.3 — acompanha a spec em desenvolvimento e PODE MUDAR
|
|
75
|
-
* de forma incompatível fora de majors enquanto ela for draft.
|
|
76
|
-
*/
|
|
77
|
-
export declare function poppyOf(ctx: HttpContext): PoppyPrincipal | null;
|
|
78
|
-
/**
|
|
79
|
-
* Middleware das APIs/rotas que usam a Session Poppy.
|
|
80
|
-
*
|
|
81
|
-
* ```ts
|
|
82
|
-
* router.post('/orders/:id/exchanges', [Orders, 'exchange'])
|
|
83
|
-
* .use(poppyAuth({ scopes: ['orders:write'] }))
|
|
84
|
-
* ```
|
|
85
|
-
*
|
|
86
|
-
* Isente essas rotas do CSRF (são chamadas por agentes, sem navegador).
|
|
87
|
-
*
|
|
88
|
-
* @experimental Poppy (Personal Agent Protocol) Draft 0.3 — acompanha a spec em desenvolvimento e PODE MUDAR
|
|
89
|
-
* de forma incompatível fora de majors enquanto ela for draft.
|
|
90
|
-
*/
|
|
91
|
-
export declare function poppyAuth(options?: PoppyVerifyOptions): (ctx: HttpContext, next: () => Promise<void>) => Promise<void>;
|
|
92
|
-
/**
|
|
93
|
-
* Publica o slot global `Symbol.for('@adonis-agora/poppy:authenticate')` (e
|
|
94
|
-
* `Symbol.for('@adonis-agora/poppy:issuer')`). Chamado no boot do provider
|
|
95
|
-
* quando `personalAgents.poppy` está no config.
|
|
96
|
-
*
|
|
97
|
-
* @experimental Poppy (Personal Agent Protocol) Draft 0.3 — acompanha a spec em desenvolvimento e PODE MUDAR
|
|
98
|
-
* de forma incompatível fora de majors enquanto ela for draft.
|
|
99
|
-
*/
|
|
100
|
-
export declare function installPoppySlots(issuer: string): void;
|