@adonis-agora/authkit-server 1.0.0-rc.3 → 1.0.0-rc.5

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.
@@ -0,0 +1,27 @@
1
+ import type { ApplicationService } from '@adonisjs/core/types';
2
+ import { type DoctorInput, type Finding } from './checks.js';
3
+ /** Logger mínimo para reportar peers instalados-mas-quebrados. */
4
+ export interface CanImportLogger {
5
+ warning(msg: string): void;
6
+ }
7
+ /**
8
+ * Tenta importar um peer; `true` se importável.
9
+ *
10
+ * Distingue "não instalado" de "instalado mas quebrado": só um erro de
11
+ * módulo-não-encontrado (`ERR_MODULE_NOT_FOUND`/`MODULE_NOT_FOUND`) é tratado como
12
+ * peer ausente (silencioso — é o caso esperado). Qualquer outro erro significa que
13
+ * o peer ESTÁ presente mas falhou ao carregar (import circular, erro de sintaxe,
14
+ * config inválida) — isso o doctor precisa gritar, senão um peer quebrado aparece
15
+ * como "ausente" e o diagnóstico mente.
16
+ */
17
+ export declare function canImport(specifier: string, logger?: CanImportLogger): Promise<boolean>;
18
+ /**
19
+ * Monta o `DoctorInput` a partir do app (config `authkit` resolvida, `session`, peers). Usado por
20
+ * `authkit:doctor` e pelos checks do `agora:doctor`. Lança se `config/authkit.ts` não resolver.
21
+ */
22
+ export declare function buildDoctorInput(app: ApplicationService, logger?: CanImportLogger): Promise<DoctorInput>;
23
+ /**
24
+ * O finding de idade da chave de assinatura managed (best-effort): `null` quando o jwks não é
25
+ * `managed` com store, ou quando o keystore não pôde ser lido.
26
+ */
27
+ export declare function managedSigningKeyAgeFinding(app: ApplicationService, authkitConfig: Record<string, any> | null): Promise<Finding | null>;
@@ -0,0 +1,86 @@
1
+ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
2
+ if (typeof path === "string" && /^\.\.?\//.test(path)) {
3
+ return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
4
+ return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
5
+ });
6
+ }
7
+ return path;
8
+ };
9
+ import { DatabaseAdapter } from '../adapters/database_adapter.js';
10
+ import { resolveAuthkitConfig } from '../commands/resolve_config.js';
11
+ import { defaultEncryptForStore } from '../define_config.js';
12
+ import { signingKeyAgeDays } from '../keys/keystore.js';
13
+ import { KeystoreCodec } from '../keys/keystore_codec.js';
14
+ import { loadEncryptionService } from '../keys/keystore_crypto.js';
15
+ import { KeystoreManager, resolveKeystoreVault } from '../keys/keystore_manager.js';
16
+ import { signingKeyAgeFinding } from './checks.js';
17
+ /**
18
+ * Tenta importar um peer; `true` se importável.
19
+ *
20
+ * Distingue "não instalado" de "instalado mas quebrado": só um erro de
21
+ * módulo-não-encontrado (`ERR_MODULE_NOT_FOUND`/`MODULE_NOT_FOUND`) é tratado como
22
+ * peer ausente (silencioso — é o caso esperado). Qualquer outro erro significa que
23
+ * o peer ESTÁ presente mas falhou ao carregar (import circular, erro de sintaxe,
24
+ * config inválida) — isso o doctor precisa gritar, senão um peer quebrado aparece
25
+ * como "ausente" e o diagnóstico mente.
26
+ */
27
+ export async function canImport(specifier, logger) {
28
+ try {
29
+ await import(__rewriteRelativeImportExtension(specifier));
30
+ return true;
31
+ }
32
+ catch (err) {
33
+ const code = err?.code;
34
+ if (code !== 'ERR_MODULE_NOT_FOUND' && code !== 'MODULE_NOT_FOUND') {
35
+ logger?.warning(`⚠️ ${specifier} está instalado mas falhou ao carregar: ${err.message}`);
36
+ }
37
+ return false;
38
+ }
39
+ }
40
+ /**
41
+ * Monta o `DoctorInput` a partir do app (config `authkit` resolvida, `session`, peers). Usado por
42
+ * `authkit:doctor` e pelos checks do `agora:doctor`. Lança se `config/authkit.ts` não resolver.
43
+ */
44
+ export async function buildDoctorInput(app, logger) {
45
+ const config = await app.container.make('config');
46
+ // `defineConfig` exporta um config provider — resolve antes de inspecionar,
47
+ // senão todo campo aparece como "ausente" (provider cru não tem issuer etc.).
48
+ const authkitConfig = await resolveAuthkitConfig(app, config.get('authkit', null));
49
+ const sessionConfig = config.get('session', null) ?? null;
50
+ return {
51
+ authkitConfig,
52
+ sessionConfig,
53
+ peers: {
54
+ session: await canImport('@adonisjs/session', logger),
55
+ shield: await canImport('@adonisjs/shield', logger),
56
+ ally: await canImport('@adonisjs/ally', logger),
57
+ limiter: await canImport('@adonisjs/limiter', logger),
58
+ },
59
+ __adapterClasses: { DatabaseAdapter },
60
+ };
61
+ }
62
+ /**
63
+ * O finding de idade da chave de assinatura managed (best-effort): `null` quando o jwks não é
64
+ * `managed` com store, ou quando o keystore não pôde ser lido.
65
+ */
66
+ export async function managedSigningKeyAgeFinding(app, authkitConfig) {
67
+ const jwksInput = (authkitConfig?.jwksConfig ?? authkitConfig?.jwks);
68
+ if (jwksInput?.source !== 'managed' || !jwksInput?.store)
69
+ return null;
70
+ try {
71
+ const vault = resolveKeystoreVault(jwksInput.store, {
72
+ makePath: (p) => app.makePath(p),
73
+ container: app.container,
74
+ });
75
+ const encrypt = jwksInput.encrypt ?? defaultEncryptForStore(jwksInput.store);
76
+ const enc = encrypt ? await loadEncryptionService().catch(() => undefined) : undefined;
77
+ const mgr = new KeystoreManager(vault, new KeystoreCodec({ encrypt, enc }), jwksInput.algorithm ?? 'RS256');
78
+ const store = await mgr.read().catch(() => null);
79
+ const maxAge = jwksInput.rotationDays ?? 90;
80
+ return signingKeyAgeFinding(signingKeyAgeDays(store), maxAge);
81
+ }
82
+ catch {
83
+ /* idade é best-effort no doctor */
84
+ return null;
85
+ }
86
+ }
@@ -0,0 +1,5 @@
1
+ import type { AgoraDoctorCheck } from './agora_doctor.js';
2
+ export type { AgoraDoctorCheck, AgoraDoctorRegistry, AgoraDoctorReport, AgoraDoctorResult, AgoraDoctorStatus, } from './agora_doctor.js';
3
+ export { AGORA_DOCTOR_BINDING, registerDoctorChecks } from './agora_doctor.js';
4
+ /** authkit's checks, for `node ace agora:doctor --no-boot` (which imports this entry instead of booting). */
5
+ export declare const agoraDoctorChecks: AgoraDoctorCheck[];
@@ -0,0 +1,4 @@
1
+ import { authkitDoctorChecks } from './agora_checks.js';
2
+ export { AGORA_DOCTOR_BINDING, registerDoctorChecks } from './agora_doctor.js';
3
+ /** authkit's checks, for `node ace agora:doctor --no-boot` (which imports this entry instead of booting). */
4
+ export const agoraDoctorChecks = authkitDoctorChecks();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adonis-agora/authkit-server",
3
- "version": "1.0.0-rc.3",
3
+ "version": "1.0.0-rc.5",
4
4
  "description": "AdonisJS OIDC/OAuth2 provider (Identity Provider) toolkit: ejectable auth server with sessions, rate-limiting, MFA/TOTP, audit log, federated logout and OpenTelemetry metrics.",
5
5
  "license": "MIT",
6
6
  "author": "dudousxd",
@@ -46,7 +46,8 @@
46
46
  "./telescope": "./build/src/observability/telescope/index.js",
47
47
  "./authkit_server_provider": "./build/providers/authkit_server_provider.js",
48
48
  "./commands": "./build/commands/main.js",
49
- "./commands/configure": "./build/commands/configure.js"
49
+ "./commands/configure": "./build/commands/configure.js",
50
+ "./doctor": "./build/src/doctor/index.js"
50
51
  },
51
52
  "adonisjs": {
52
53
  "types": "@adonis-agora/authkit-server",
@@ -109,7 +110,7 @@
109
110
  "@adonis-agora/authkit-core": "1.0.0-rc.0",
110
111
  "@simplewebauthn/browser": "14.0.0",
111
112
  "@simplewebauthn/server": "14.1.0",
112
- "jose": "6.2.15",
113
+ "jose": "6.2.16",
113
114
  "koa": "3.3.0",
114
115
  "koa-mount": "4.2.0",
115
116
  "oidc-provider": "9.13.3",
@@ -118,7 +119,7 @@
118
119
  },
119
120
  "devDependencies": {
120
121
  "@adonis-agora/authkit-react": "1.0.0-rc.2",
121
- "@adonis-agora/durable": "0.59.0",
122
+ "@adonis-agora/durable": "0.60.0",
122
123
  "@adonis-agora/telescope": "0.27.1",
123
124
  "@adonisjs/ally": "6.3.2",
124
125
  "@adonisjs/auth": "10.1.0",
@@ -169,6 +170,7 @@
169
170
  "build": "node scripts/build_host_css.mjs && node scripts/build_webauthn.mjs && node scripts/build_ui.mjs && node -e \"const fs=require('node:fs');for(const d of ['build/stubs','build/host/views'])fs.rmSync(d,{recursive:true,force:true})\" && tsc && node -e \"require('node:fs').cpSync('src/host/assets','build/src/host/assets',{recursive:true})\" && node -e \"require('node:fs').cpSync('stubs','build/stubs',{recursive:true,filter:(s)=>!s.endsWith('.ts')})\" && node -e \"const fs=require('node:fs');if(fs.existsSync('assets'))fs.cpSync('assets','build/assets',{recursive:true})\" && node -e \"require('node:fs').cpSync('src/host/views','build/host/views',{recursive:true})\" && node -e \"const fs=require('node:fs');fs.mkdirSync('build/host/ui',{recursive:true});fs.readdirSync('src/host/ui').filter(f=>f.endsWith('.html')).forEach(f=>fs.copyFileSync('src/host/ui/'+f,'build/host/ui/'+f))\" && node -e \"require('node:fs').copyFileSync('commands/commands.json','build/commands/commands.json')\" && node -e \"const fs=require('node:fs');fs.mkdirSync('build/src/password',{recursive:true});fs.copyFileSync('src/password/common_passwords.txt','build/src/password/common_passwords.txt')\"",
170
171
  "build:ui": "node scripts/build_ui.mjs",
171
172
  "build:webauthn": "node scripts/build_webauthn.mjs",
173
+ "check:agora-doctor": "node ../../scripts/check-agora-doctor.mjs .",
172
174
  "check:host-css": "node scripts/check_host_css.mjs",
173
175
  "check:webauthn-bundle": "node scripts/check_webauthn_bundle.mjs",
174
176
  "typecheck": "tsc --noEmit && node scripts/typecheck_ui.mjs && node scripts/typecheck_tests.mjs",