@nodefony/framework 10.0.0-beta.2 → 10.0.0-beta.4
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/README.md +4 -0
- package/dist/_virtual/{_@oxc-project_runtime@0.152.0 → _@oxc-project_runtime@0.155.0}/helpers/esm/decorate.js +1 -2
- package/dist/index.js +15 -20
- package/dist/nodefony/config/config.js +1 -2
- package/dist/nodefony/config/defineModuleConfig.js +1 -2
- package/dist/nodefony/controller/AdminApiController.js +45 -11
- package/dist/nodefony/controller/ApiKeyController.js +18 -10
- package/dist/nodefony/controller/BenchController.js +1 -2
- package/dist/nodefony/controller/IssuerMetadataController.js +1 -2
- package/dist/nodefony/controller/LoginPageController.js +117 -0
- package/dist/nodefony/controller/OAuth2Controller.js +133 -17
- package/dist/nodefony/controller/ProtectedResourceMetadataController.js +1 -2
- package/dist/nodefony/controller/SessionAuthController.js +50 -13
- package/dist/nodefony/controller/TokenAuthController.js +14 -8
- package/dist/nodefony/controller/TotpController.js +7 -8
- package/dist/nodefony/controller/WebAuthnController.js +28 -12
- package/dist/nodefony/controller/oauthAuthority.js +1 -2
- package/dist/nodefony/decorators/routerDecorators.js +268 -65
- package/dist/nodefony/service/AdminBroker.js +4 -6
- package/dist/nodefony/service/Eta.js +1 -2
- package/dist/nodefony/service/IdempotencyStore.js +4 -6
- package/dist/nodefony/service/router.js +97 -34
- package/dist/nodefony/src/Controller.js +71 -43
- package/dist/nodefony/src/FrameworkAdminApi.js +33 -11
- package/dist/nodefony/src/KernelAdminApi.js +82 -18
- package/dist/nodefony/src/PlaygroundAdminApi.js +72 -3
- package/dist/nodefony/src/RedisIdempotencyStore.js +46 -4
- package/dist/nodefony/src/Resolver.js +105 -36
- package/dist/nodefony/src/ResourceController.js +2 -3
- package/dist/nodefony/src/Route.js +54 -8
- package/dist/nodefony/src/SecurityApiController.js +23 -0
- package/dist/nodefony/src/SyslogAdminApi.js +1 -2
- package/dist/nodefony/src/Template.js +1 -2
- package/dist/nodefony/src/configMutation.js +1 -2
- package/dist/nodefony/src/docsReader.js +39 -23
- package/dist/nodefony/src/idempotency.js +14 -22
- package/dist/nodefony/src/idempotencyGc.js +1 -2
- package/dist/nodefony/src/idempotencyStoreRegistry.js +1 -2
- package/dist/nodefony/src/loginPage.js +430 -0
- package/dist/nodefony/src/requireAuthentication.js +35 -0
- package/dist/nodefony/src/routeSchema.js +81 -0
- package/dist/nodefony/src/scopeCatalog.js +1 -2
- package/dist/nodefony/src/singletonGuard.js +1 -2
- package/dist/nodefony/src/syslogFilters.js +1 -2
- package/dist/types/index.d.ts +8 -12
- package/dist/types/nodefony/controller/AdminApiController.d.ts +12 -0
- package/dist/types/nodefony/controller/ApiKeyController.d.ts +2 -2
- package/dist/types/nodefony/controller/LoginPageController.d.ts +32 -0
- package/dist/types/nodefony/controller/OAuth2Controller.d.ts +67 -8
- package/dist/types/nodefony/controller/SessionAuthController.d.ts +46 -8
- package/dist/types/nodefony/controller/TokenAuthController.d.ts +6 -4
- package/dist/types/nodefony/controller/TotpController.d.ts +2 -2
- package/dist/types/nodefony/controller/WebAuthnController.d.ts +12 -4
- package/dist/types/nodefony/decorators/routerDecorators.d.ts +221 -35
- package/dist/types/nodefony/interfaces/IController.d.ts +2 -3
- package/dist/types/nodefony/interfaces/IRoute.d.ts +1 -2
- package/dist/types/nodefony/service/router.d.ts +40 -1
- package/dist/types/nodefony/src/Controller.d.ts +54 -17
- package/dist/types/nodefony/src/PlaygroundAdminApi.d.ts +12 -0
- package/dist/types/nodefony/src/Resolver.d.ts +44 -1
- package/dist/types/nodefony/src/ResourceController.d.ts +1 -1
- package/dist/types/nodefony/src/Route.d.ts +21 -1
- package/dist/types/nodefony/src/SecurityApiController.d.ts +17 -0
- package/dist/types/nodefony/src/docsReader.d.ts +10 -6
- package/dist/types/nodefony/src/idempotency.d.ts +12 -10
- package/dist/types/nodefony/src/loginPage.d.ts +144 -0
- package/dist/types/nodefony/src/requireAuthentication.d.ts +29 -0
- package/dist/types/nodefony/src/routeSchema.d.ts +112 -0
- package/docs/admin.md +83 -78
- package/docs/controller.md +112 -111
- package/docs/decorateurs.md +212 -163
- package/docs/idempotence.md +137 -135
- package/docs/routing.md +96 -95
- package/docs/templates.md +55 -55
- package/package.json +10 -13
- package/dist/_virtual/_@oxc-project_runtime@0.152.0/helpers/esm/decorateMetadata.js +0 -6
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
import type { ContextType } from "@nodefony/http";
|
|
2
2
|
import Controller from "../src/Controller.js";
|
|
3
|
+
type AdminQuery = Record<string, string | string[]>;
|
|
4
|
+
/**
|
|
5
|
+
* Ramène les paramètres d'URL au contrat {@link IAdminRequest.query} : seules
|
|
6
|
+
* les chaînes et les tableaux de chaînes passent. `qs` produit des objets pour
|
|
7
|
+
* `a[b]=1` ; les laisser passer sous un type qui les nie tromperait chaque
|
|
8
|
+
* producteur du plan d'administration.
|
|
9
|
+
*
|
|
10
|
+
* @param source - paramètres d'URL de la requête (`Controller.query`)
|
|
11
|
+
* @returns `source` lui-même quand il respecte déjà le contrat (aucune
|
|
12
|
+
* allocation), sinon une copie sans les valeurs imbriquées
|
|
13
|
+
*/
|
|
14
|
+
export declare function toAdminQuery(source: Record<string, unknown> | undefined): AdminQuery;
|
|
3
15
|
/**
|
|
4
16
|
* Controller pont unique du data plane admin (Studio).
|
|
5
17
|
*
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Module } from "nodefony";
|
|
2
2
|
import type { ContextType } from "@nodefony/http";
|
|
3
|
-
import
|
|
3
|
+
import SecurityApiController from "../src/SecurityApiController.js";
|
|
4
4
|
/**
|
|
5
5
|
* Endpoints HTTP de **gestion des clés API personnelles (PAT, P6.12)** — console
|
|
6
6
|
* « mes clés » façon GitHub, adaptateurs MINCES au-dessus du service `apiKeys`
|
|
@@ -22,7 +22,7 @@ import Controller from "../src/Controller.js";
|
|
|
22
22
|
* Erreurs mappées par DUCK-TYPING sur `code` (400/409/503) — framework ne peut pas
|
|
23
23
|
* importer les classes d'erreur de security.
|
|
24
24
|
*/
|
|
25
|
-
declare class ApiKeyController extends
|
|
25
|
+
declare class ApiKeyController extends SecurityApiController {
|
|
26
26
|
#private;
|
|
27
27
|
constructor(context: ContextType);
|
|
28
28
|
/** Émission : crée une clé pour le porteur courant → token clair (1×). */
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { type Module } from "nodefony";
|
|
2
|
+
import type { ContextType } from "@nodefony/http";
|
|
3
|
+
import Controller from "../src/Controller.js";
|
|
4
|
+
/**
|
|
5
|
+
* Page de connexion par défaut (ADR-0015) : gabarit F03 rendu côté serveur,
|
|
6
|
+
* feuille `nodefony/login.css`, script `nodefony/login.js`. Aucun front, aucun
|
|
7
|
+
* build côté application.
|
|
8
|
+
*
|
|
9
|
+
* Joignable sans session ; jamais mise en cache (`no-store`) ni affichable
|
|
10
|
+
* dans un cadre (`frame-ancestors 'none'`).
|
|
11
|
+
*/
|
|
12
|
+
declare class LoginPageController extends Controller {
|
|
13
|
+
constructor(context: ContextType);
|
|
14
|
+
/**
|
|
15
|
+
* Rend la page de connexion.
|
|
16
|
+
*
|
|
17
|
+
* @returns la page HTML, ou 404 quand security ne la décrit plus
|
|
18
|
+
*/
|
|
19
|
+
page(): Promise<import("@nodefony/http").HttpResponse | import("@nodefony/http").WebsocketResponse>;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Monte la page de connexion par défaut quand security la décrit : la route
|
|
23
|
+
* sur `loginPage.path`, et ses fichiers sous `LOGIN_PAGE_ASSETS_BASE`.
|
|
24
|
+
*
|
|
25
|
+
* La page est le chemin vers la session : elle échappe au pare-feu, comme les
|
|
26
|
+
* routes de connexion — sinon une application qui protège `^/` exigerait
|
|
27
|
+
* d'être connecté pour se connecter.
|
|
28
|
+
*
|
|
29
|
+
* @param frameworkModule - module framework, qui porte les contrôleurs
|
|
30
|
+
*/
|
|
31
|
+
export declare function mountLoginPage(frameworkModule: Module): void;
|
|
32
|
+
export default LoginPageController;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type Module } from "nodefony";
|
|
2
2
|
import type { ContextType } from "@nodefony/http";
|
|
3
|
-
import
|
|
3
|
+
import SecurityApiController from "../src/SecurityApiController.js";
|
|
4
4
|
/**
|
|
5
5
|
* Vue MINIMALE du service `oauth2` (`@nodefony/security`) — couplage par NOM
|
|
6
6
|
* (framework ne dépend pas de security). Contrat structurel imposé par
|
|
@@ -24,13 +24,31 @@ export interface IOAuth2Service {
|
|
|
24
24
|
success: string;
|
|
25
25
|
failure: string;
|
|
26
26
|
};
|
|
27
|
-
|
|
27
|
+
/** `options` : une version de security qui ne le lit pas l'ignore. */
|
|
28
|
+
createAuthorization(provider: string, options?: {
|
|
29
|
+
theme?: "light" | "dark";
|
|
30
|
+
}): Promise<{
|
|
28
31
|
url: string;
|
|
29
32
|
state: string;
|
|
30
33
|
codeVerifier: string | null;
|
|
31
34
|
}>;
|
|
32
35
|
exchangeAndProvision(provider: string, code: string, codeVerifier: string | null, returnedIss: string | null): Promise<{
|
|
33
36
|
identifier: string;
|
|
37
|
+
logoutHint?: unknown;
|
|
38
|
+
}>;
|
|
39
|
+
/**
|
|
40
|
+
* Retient en session de quoi fermer plus tard la session du fournisseur
|
|
41
|
+
* (RP-Initiated Logout). Optionnel : la clé et la forme appartiennent au
|
|
42
|
+
* service, ce contrôleur ne fait que transmettre.
|
|
43
|
+
*/
|
|
44
|
+
rememberLogout?(session: IOAuth2Session, hint: unknown): void;
|
|
45
|
+
/**
|
|
46
|
+
* Déconnexion demandée par le fournisseur sur le canal arrière (OpenID
|
|
47
|
+
* Connect Back-Channel Logout). Optionnel, même raison que
|
|
48
|
+
* {@link listDisplayProviders} : absent, la route répond 501.
|
|
49
|
+
*/
|
|
50
|
+
backchannelLogout?(provider: string, logoutToken: string): Promise<{
|
|
51
|
+
outcome: "unsupported" | "refused" | "done";
|
|
34
52
|
}>;
|
|
35
53
|
}
|
|
36
54
|
/** Vue minimale d'une session — porte l'état du flux OAuth (anti-CSRF/anti-replay). */
|
|
@@ -50,16 +68,45 @@ export interface IOAuth2BffFlow {
|
|
|
50
68
|
/** Garantit une session (anonyme) pour porter `state`/`code_verifier`. */
|
|
51
69
|
ensureSession(context: ContextType): Promise<IOAuth2Session | null>;
|
|
52
70
|
}
|
|
71
|
+
/**
|
|
72
|
+
* Thème que la page appelante a rendu (`?theme=`), à transmettre à l'écran du
|
|
73
|
+
* fournisseur. Liste FERMÉE : la chaîne vient de l'URL, toute autre valeur est
|
|
74
|
+
* ignorée sans un mot — rien d'arbitraire n'atteint la requête d'autorisation.
|
|
75
|
+
*
|
|
76
|
+
* @param value - paramètre `theme` de la requête, ou `null`
|
|
77
|
+
* @returns l'option à passer à `createAuthorization`, vide hors liste
|
|
78
|
+
*/
|
|
79
|
+
export declare function providerThemeOption(value: string | null): {
|
|
80
|
+
theme?: "light" | "dark";
|
|
81
|
+
};
|
|
82
|
+
/**
|
|
83
|
+
* Compose l'adresse de l'écran d'échec : la raison de l'échec, et la page où
|
|
84
|
+
* aller une fois connecté, pour que l'écran la garde à la tentative suivante.
|
|
85
|
+
*
|
|
86
|
+
* `reason` vaut le code rendu par le fournisseur s'il appartient à la liste
|
|
87
|
+
* normalisée (`access_denied` = l'utilisateur a choisi de revenir), sinon
|
|
88
|
+
* {@link OAUTH2_FAILED_REASON} — jamais la chaîne reçue, qui vient de l'URL.
|
|
89
|
+
* Une `reason` ou un `from` déjà présents sont REMPLACÉS (l'écran qui a lancé
|
|
90
|
+
* le flux peut porter ceux d'une tentative précédente) ; le reste de la
|
|
91
|
+
* requête et le fragment sont conservés, et une adresse relative reste relative.
|
|
92
|
+
*
|
|
93
|
+
* @param failure - l'écran d'échec : `back` revalidé, ou `failureRedirect`
|
|
94
|
+
* @param error - le paramètre `error` reçu au callback, ou `null`
|
|
95
|
+
* @param from - la page où aller une fois connecté (revalidée), ou `null`
|
|
96
|
+
* @returns l'adresse de redirection
|
|
97
|
+
*/
|
|
98
|
+
export declare function oauth2FailureTarget(failure: string, error: string | null, from: string | null): string;
|
|
53
99
|
/**
|
|
54
100
|
* Endpoints HTTP du **social login OAuth 2.0** (P6 J9) — adaptateurs MINCES
|
|
55
101
|
* au-dessus du service `oauth2` (`@nodefony/security`) :
|
|
56
102
|
*
|
|
57
|
-
* - `GET /nodefony/security/api/oauth2/{provider}/authorize
|
|
58
|
-
* pose `state`+`code_verifier` en session (anonyme),
|
|
59
|
-
* fournisseur.
|
|
103
|
+
* - `GET /nodefony/security/api/oauth2/{provider}/authorize?from=&back=` —
|
|
104
|
+
* démarre le flux : pose `state`+`code_verifier` en session (anonyme), avec
|
|
105
|
+
* les retours revalidés en chemins locaux, redirige (302) vers le fournisseur.
|
|
60
106
|
* - `GET /nodefony/security/api/oauth2/{provider}/callback` — valide le `state`
|
|
61
107
|
* (anti-CSRF), échange le `code`, provisionne le Shadow User et OUVRE la
|
|
62
|
-
* session BFF (302 vers `successRedirect`).
|
|
108
|
+
* session BFF (302 vers `from`, sinon `successRedirect`). Un échec mène à
|
|
109
|
+
* `back`, sinon à `failureRedirect`, avec `reason` et `from`.
|
|
63
110
|
*
|
|
64
111
|
* Montés UNIQUEMENT si le service `oauth2` existe (social login activé) — 404
|
|
65
112
|
* sinon, zéro surface.
|
|
@@ -70,7 +117,7 @@ export interface IOAuth2BffFlow {
|
|
|
70
117
|
* La session anonyme ne porte que `state`/`verifier` ; `establishSessionFor`
|
|
71
118
|
* régénère l'ID (anti-fixation) à la promotion.
|
|
72
119
|
*/
|
|
73
|
-
declare class OAuth2Controller extends
|
|
120
|
+
declare class OAuth2Controller extends SecurityApiController {
|
|
74
121
|
#private;
|
|
75
122
|
constructor(context: ContextType);
|
|
76
123
|
/**
|
|
@@ -87,6 +134,18 @@ declare class OAuth2Controller extends Controller {
|
|
|
87
134
|
authorize(provider: string): Promise<import("@nodefony/http").HttpResponse | import("@nodefony/http").WebsocketResponse | undefined>;
|
|
88
135
|
/** Valide `state`, échange le `code`, ouvre la session BFF (302). */
|
|
89
136
|
callback(provider: string): Promise<import("@nodefony/http").HttpResponse | import("@nodefony/http").WebsocketResponse | undefined>;
|
|
137
|
+
/**
|
|
138
|
+
* Canal arrière : le fournisseur demande de fermer les sessions qu'il
|
|
139
|
+
* désigne (OpenID Connect Back-Channel Logout 1.0 §2.5-2.8).
|
|
140
|
+
*
|
|
141
|
+
* Appelé serveur à serveur — ni cookie, ni session, ni jeton CSRF : la
|
|
142
|
+
* SIGNATURE du `logout_token` est la seule authentification. Réponses de la
|
|
143
|
+
* norme (§2.8) : 200 si la déconnexion a eu lieu (ou n'avait plus lieu
|
|
144
|
+
* d'être), 400 sinon — jeton refusé (`invalid_request`) comme déconnexion
|
|
145
|
+
* impossible (la cause part au journal, jamais au fournisseur). Toujours
|
|
146
|
+
* `Cache-Control: no-store`.
|
|
147
|
+
*/
|
|
148
|
+
backchannelLogout(provider: string): Promise<import("@nodefony/http").Http2Response | import("@nodefony/http").HttpResponse | import("@nodefony/http").WebsocketResponse>;
|
|
90
149
|
}
|
|
91
150
|
/**
|
|
92
151
|
* Monte les routes du social login OAuth — appelé par le module framework à
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type ILoginPageDescription, type Module } from "nodefony";
|
|
2
2
|
import type { ContextType } from "@nodefony/http";
|
|
3
|
-
import
|
|
3
|
+
import SecurityApiController from "../src/SecurityApiController.js";
|
|
4
4
|
/**
|
|
5
5
|
* Vue MINIMALE du flux de session BFF que consomme ce controller — le service
|
|
6
6
|
* `authFlow` est posé au container par `@nodefony/security` (P6 J3). Contrat
|
|
@@ -14,14 +14,29 @@ type ILoginOutcome = {
|
|
|
14
14
|
user: unknown;
|
|
15
15
|
} | {
|
|
16
16
|
status: "mfa_required";
|
|
17
|
-
methods: string[];
|
|
17
|
+
methods: readonly string[];
|
|
18
18
|
};
|
|
19
19
|
export interface ISessionAuthFlow {
|
|
20
20
|
login(context: ContextType, identifier: unknown, password: unknown): Promise<ILoginOutcome>;
|
|
21
21
|
completeMfaLogin(context: ContextType, code: unknown): Promise<unknown>;
|
|
22
22
|
logout(context: ContextType): Promise<boolean>;
|
|
23
|
+
/**
|
|
24
|
+
* Déconnexion qui ferme AUSSI la session du fournisseur d'identité. Optionnelle :
|
|
25
|
+
* une version de `@nodefony/security` qui ne l'expose pas encore dégrade sur
|
|
26
|
+
* {@link logout}.
|
|
27
|
+
*/
|
|
28
|
+
logoutWithProvider?(context: ContextType): Promise<{
|
|
29
|
+
destroyed: boolean;
|
|
30
|
+
logoutUrl: string | null;
|
|
31
|
+
}>;
|
|
23
32
|
/** Identité courante, ou `null` sans session authentifiée. */
|
|
24
33
|
me(context: ContextType): Promise<unknown>;
|
|
34
|
+
/**
|
|
35
|
+
* Ce que la page de connexion par défaut doit afficher, ou `null` quand
|
|
36
|
+
* elle est désactivée. Optionnelle : une version de `@nodefony/security`
|
|
37
|
+
* qui ne l'expose pas encore laisse la page absente (404).
|
|
38
|
+
*/
|
|
39
|
+
describeLoginPage?(): ILoginPageDescription | null;
|
|
25
40
|
}
|
|
26
41
|
/**
|
|
27
42
|
* Endpoints HTTP du flux de session BFF — adaptateurs MINCES au-dessus du
|
|
@@ -29,7 +44,8 @@ export interface ISessionAuthFlow {
|
|
|
29
44
|
*
|
|
30
45
|
* - `POST /nodefony/security/api/auth/login` — body JSON `{username, password}`
|
|
31
46
|
* - `POST /nodefony/security/api/auth/logout` — idempotent
|
|
32
|
-
* - `GET /nodefony/security/api/auth/me` — identité de la session courante
|
|
47
|
+
* - `GET /nodefony/security/api/auth/me` — identité de la session courante :
|
|
48
|
+
* TOUJOURS `200`, `{ user }` ou `{ user: null }` sans session
|
|
33
49
|
*
|
|
34
50
|
* Montés par le module framework UNIQUEMENT si le service `authFlow` existe
|
|
35
51
|
* (module security chargé) — sans lui, les routes n'existent pas (404, zéro
|
|
@@ -40,14 +56,20 @@ export interface ISessionAuthFlow {
|
|
|
40
56
|
* `Retry-After` (RFC 6585) posé par le throttler NIST ; tout le reste remonte
|
|
41
57
|
* au pipeline d'erreurs standard (500, détail loggé jamais fuité).
|
|
42
58
|
*
|
|
43
|
-
*
|
|
59
|
+
* `me` est une SONDE d'état, pas une ressource protégée : « pas de session »
|
|
60
|
+
* est un état normal du navigateur, pas une faute — d'où `200` + `{ user:
|
|
61
|
+
* null }`, comme les bibliothèques qui livrent aussi le client de connexion
|
|
62
|
+
* (Auth.js, better-auth). Le `401` y écrivait une erreur réseau dans la console
|
|
63
|
+
* de chaque visiteur anonyme, sans rien protéger : la réponse ne révèle rien.
|
|
64
|
+
*
|
|
65
|
+
* @remarks Dérogation RFC 9110 §15.5.2 DÉLIBÉRÉE : les 401 de `login` ne
|
|
44
66
|
* portent PAS de `WWW-Authenticate` — aucun scheme HTTP ne décrit un cookie de
|
|
45
67
|
* session, et un challenge `Basic` mensonger déclencherait le popup natif du
|
|
46
68
|
* navigateur (l'anti-pattern que le BFF élimine). Les zones du firewall, elles,
|
|
47
69
|
* restent strictement conformes (challenge du premier authenticator qui en
|
|
48
70
|
* déclare un).
|
|
49
71
|
*/
|
|
50
|
-
declare class SessionAuthController extends
|
|
72
|
+
declare class SessionAuthController extends SecurityApiController {
|
|
51
73
|
#private;
|
|
52
74
|
constructor(context: ContextType);
|
|
53
75
|
/** Login BFF : credential JSON présenté UNE fois → cookie de session opaque. */
|
|
@@ -58,9 +80,25 @@ declare class SessionAuthController extends Controller {
|
|
|
58
80
|
* absent/invalide → 401 (uniforme) ; trop de tentatives → 429 (Retry-After).
|
|
59
81
|
*/
|
|
60
82
|
loginTotp(): Promise<import("@nodefony/http").Http2Response | import("@nodefony/http").HttpResponse | import("@nodefony/http").WebsocketResponse>;
|
|
61
|
-
/**
|
|
83
|
+
/**
|
|
84
|
+
* Détruit la session (storage + cookie). Toujours 200 (idempotent). Quand la
|
|
85
|
+
* session venait d'un fournisseur qui publie un point de déconnexion, la
|
|
86
|
+
* réponse porte `logoutUrl` : le client y envoie le navigateur pour fermer
|
|
87
|
+
* aussi la session du fournisseur.
|
|
88
|
+
*/
|
|
62
89
|
logout(): Promise<import("@nodefony/http").Http2Response | import("@nodefony/http").HttpResponse | import("@nodefony/http").WebsocketResponse>;
|
|
63
|
-
/**
|
|
90
|
+
/**
|
|
91
|
+
* Identité de la session courante, re-résolue (rôles frais). Toujours `200` :
|
|
92
|
+
* `{ user: null }` quand il n'y a pas de session (ou qu'elle ne mène plus à
|
|
93
|
+
* un compte actif) — l'absence de session est un état, pas une erreur.
|
|
94
|
+
*
|
|
95
|
+
* **Sème aussi le jeton anti-CSRF** (cookie lisible `csrf-token`) : c'est la
|
|
96
|
+
* seule requête sûre que TOUT client connaît d'avance. Sans elle, une mutation
|
|
97
|
+
* `@CsrfProtect` n'a de jeton à rejouer que si son auteur a AUSSI décoré une
|
|
98
|
+
* lecture — protéger les seules écritures, le geste naturel, rendait alors 403
|
|
99
|
+
* sans issue, au navigateur comme aux tests générés. Le jeton est sans état
|
|
100
|
+
* (HMAC) : celui-ci vaut pour toute route protégée.
|
|
101
|
+
*/
|
|
64
102
|
me(): Promise<import("@nodefony/http").Http2Response | import("@nodefony/http").HttpResponse | import("@nodefony/http").WebsocketResponse>;
|
|
65
103
|
}
|
|
66
104
|
/**
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Module } from "nodefony";
|
|
2
2
|
import type { ContextType } from "@nodefony/http";
|
|
3
|
-
import
|
|
3
|
+
import SecurityApiController from "../src/SecurityApiController.js";
|
|
4
4
|
/**
|
|
5
5
|
* Vue MINIMALE du service d'émission de jetons (`tokenService`, posé au container
|
|
6
6
|
* par `@nodefony/security` P6 J4). Contrat structurel local : framework ne dépend
|
|
@@ -10,7 +10,9 @@ export interface ITokenIssuer {
|
|
|
10
10
|
/** `true` si l'émission JWT est opérationnelle (JWT activé + store prêt). */
|
|
11
11
|
isEnabled(): boolean;
|
|
12
12
|
/** Émet access+refresh après vérification d'un credential (grant M2M/CLI). */
|
|
13
|
-
issueForCredentials(identifier: unknown, password: unknown, scopes?: string[], resource?: unknown
|
|
13
|
+
issueForCredentials(identifier: unknown, password: unknown, scopes?: string[], resource?: unknown,
|
|
14
|
+
/** Requête porteuse — soumet le credential au refus du clair en production. */
|
|
15
|
+
context?: ContextType): Promise<unknown>;
|
|
14
16
|
/** Rotation d'un refresh token (nouveau couple, ancien révoqué). */
|
|
15
17
|
refresh(rawRefresh: unknown, resource?: unknown): Promise<unknown>;
|
|
16
18
|
}
|
|
@@ -31,11 +33,11 @@ export interface ITokenIssuer {
|
|
|
31
33
|
* framework ne peut pas importer les classes d'erreur de security ; un 429
|
|
32
34
|
* reporte le `Retry-After` (RFC 6585) du throttler NIST.
|
|
33
35
|
*
|
|
34
|
-
* @remarks Dérogation RFC
|
|
36
|
+
* @remarks Dérogation RFC 9110 §15.5.2 (comme `SessionAuthController`) : ces 401 ne
|
|
35
37
|
* portent pas de `WWW-Authenticate` — l'endpoint d'émission n'est pas une
|
|
36
38
|
* ressource protégée par Bearer, il DÉLIVRE le Bearer.
|
|
37
39
|
*/
|
|
38
|
-
declare class TokenAuthController extends
|
|
40
|
+
declare class TokenAuthController extends SecurityApiController {
|
|
39
41
|
#private;
|
|
40
42
|
constructor(context: ContextType);
|
|
41
43
|
/** Émission : credential présenté → couple access/refresh. */
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Module } from "nodefony";
|
|
2
2
|
import type { ContextType } from "@nodefony/http";
|
|
3
|
-
import
|
|
3
|
+
import SecurityApiController from "../src/SecurityApiController.js";
|
|
4
4
|
/**
|
|
5
5
|
* Endpoints HTTP **self-service 2FA TOTP (P6.17)** — console « ma sécurité »,
|
|
6
6
|
* adaptateurs MINCES au-dessus du service `totp` (`@nodefony/security`) :
|
|
@@ -19,7 +19,7 @@ import Controller from "../src/Controller.js";
|
|
|
19
19
|
* `totp` existe (security chargé) — sans security, 404 et zéro surface ; 2FA
|
|
20
20
|
* désactivé, les routes répondent 503.
|
|
21
21
|
*/
|
|
22
|
-
declare class TotpController extends
|
|
22
|
+
declare class TotpController extends SecurityApiController {
|
|
23
23
|
#private;
|
|
24
24
|
constructor(context: ContextType);
|
|
25
25
|
/** Démarre l'enrôlement : secret + URI otpauth affichés une seule fois. */
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type Module } from "nodefony";
|
|
2
2
|
import type { ContextType } from "@nodefony/http";
|
|
3
|
-
import
|
|
3
|
+
import SecurityApiController from "../src/SecurityApiController.js";
|
|
4
4
|
/**
|
|
5
5
|
* Options de cérémonie renvoyées au navigateur (forme JSON WebAuthn) — seul le
|
|
6
6
|
* `challenge` nous intéresse côté serveur (stocké en session, anti-replay) ; le
|
|
@@ -20,6 +20,7 @@ export interface IWebAuthnService {
|
|
|
20
20
|
id: string;
|
|
21
21
|
name: string;
|
|
22
22
|
displayName?: string;
|
|
23
|
+
handle?: string;
|
|
23
24
|
}): Promise<CeremonyOptions>;
|
|
24
25
|
verifyRegistration(response: unknown, expectedChallenge: string, userId: string, requestOrigin?: string): Promise<{
|
|
25
26
|
id: string;
|
|
@@ -46,7 +47,8 @@ export interface IWebAuthnSession {
|
|
|
46
47
|
/** Vue minimale du flux de session BFF (`authFlow`) consommée ici. */
|
|
47
48
|
export interface IWebAuthnBffFlow {
|
|
48
49
|
me(context: ContextType): Promise<{
|
|
49
|
-
|
|
50
|
+
id: string;
|
|
51
|
+
identifier: string;
|
|
50
52
|
} | null>;
|
|
51
53
|
/**
|
|
52
54
|
* @param reason - facteur d'authentification journalisé par l'audit
|
|
@@ -84,9 +86,15 @@ export interface IWebAuthnBffFlow {
|
|
|
84
86
|
* firewall (qui, sur l'aire data plane, déclencherait un deadlock identique au
|
|
85
87
|
* login BFF).
|
|
86
88
|
*/
|
|
87
|
-
declare class WebAuthnController extends
|
|
89
|
+
declare class WebAuthnController extends SecurityApiController {
|
|
88
90
|
#private;
|
|
89
91
|
constructor(context: ContextType);
|
|
92
|
+
/**
|
|
93
|
+
* Dit si la connexion par passkey répondra : `{ enabled }`, toujours `200`.
|
|
94
|
+
* Un écran de connexion le lit pour ne pas proposer un bouton dont la
|
|
95
|
+
* cérémonie répondrait `503` (passkeys coupées).
|
|
96
|
+
*/
|
|
97
|
+
status(): import("nodefony").MaybePromise<import("@nodefony/http").Http2Response | import("@nodefony/http").HttpResponse | import("@nodefony/http").WebsocketResponse>;
|
|
90
98
|
/** Défi d'enregistrement — l'utilisateur connecté ajoute un passkey. */
|
|
91
99
|
registerOptions(): Promise<import("@nodefony/http").Http2Response | import("@nodefony/http").HttpResponse | import("@nodefony/http").WebsocketResponse>;
|
|
92
100
|
/** Vérifie la réponse d'enregistrement et persiste le credential. */
|