Version 0.24.0 #158
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "dev"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Version 0.24.0 : le socle du hub d'identité (#157) — routes fermées réglables, fragments Prisma du serveur d'autorisation (dont two-factor), crochets de l'application, rotation du secret, limites de débit par chemin, Redis,
@Authentifie(), identifiant de requête dans better-auth, reprise OAuth à la connexion, jetons du hub acceptés par tout satellite (D-067 à D-081), et deux correctifs de sécurité (retourSur,porteAuth).Sortie selon D-037 : publication de la candidate sous
nextdepuismainfusionné, bac à sableeqs-demo, puis promotion enlatest.🤖 Generated with Claude Code
Plan du hub A-6. Le hub avait mesuré (L-039) que better-auth lit `secondaryStorage` et le stockage de la limitation AVANT l'`init` des greffons : posé par un greffon, seul l'adaptateur interne passait sur Redis. La parade est au niveau de `creerAuth`. - `creerAuth({ secondaryStorage })` : passé avec le reste, entraîne `session.storeSessionInDatabase` et la limitation sur le stockage ; - `@eqs/auth/redis` : `clientRedis`, `stockageRedis` (`getAndDelete` et `increment` atomiques par script Lua, clés préfixées) ; `ioredis` chargé seulement par qui pose `REDIS_URL` ; - `createEqsApp` : client sur `REDIS_URL` (schéma de base), donné à better-auth et au limiteur de Nest (`LimiteurRedis`), sonde `redis` non vitale, fermé à l'arrêt ; `redis` injecte un client. Sans `REDIS_URL`, rien ne change. Prouvé sur un vrai Redis jetable (`EQS_TEST_REDIS_URL`, sauté sinon) : deux répliques à bases distinctes partagent le seau du limiteur et la session ; et, sans Redis, la mécanique better-auth sur un stockage de même forme. En montant : `REDIS_URL=` dans `.env.example`. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>Le hub a renoncé au TOTP sur son compte de secours (L-035) : `twoFactor` décide sur `user.twoFactorEnabled`, et Prisma n'étend pas `User` depuis un autre fichier — or `auth.prisma` est généré, refusé à l'édition. Même trou pour les `champsUtilisateur` de D-072. - un fragment déclare ses colonnes de `User` par `// @eqs:user <champ>` ; `schemaAuth({ fragments, colonnesUtilisateur })` (`@eqs/auth/prisma`) compose et les injecte, en signant chaque ligne de sa source ; - `schemas/two-factor.prisma` : `TwoFactor` et `User.twoFactorEnabled` ; - `eqs auth prisma [--out] [--check]` lit `package.json#eqs.schemasAuth` (défaut `["auth"]`, la copie de toujours) et `eqs.colonnesUtilisateur` : le script que D-069 laissait au gabarit devient une commande du socle. Prouvé : fragment composé confronté au schéma de better-auth avec `twoFactor` ; trajet TOTP complet sur `creerAuth` (activation, `twoFactorRedirect` sans session, code faux refusé, session au bon code) ; hors dépôt, PostgreSQL 16 jetable + Prisma 6.19 : `validate`, `db push` du schéma composé, même trajet par `prismaAdapter`, colonne et table écrites. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>Seul `moi.lire` échappait à la permission, en dur. Le hub, pour ses routes « pour soi » (sessions, audit, consentement), n'avait que `@Public()` plus un contrôle à la main, ou `@Permission()` vers un droit donné à tous — écart de `auth.route-sans-decision` (L-028, L-033). - `@Authentifie()` (Nest) et `withApi({ authentifie: true })` / `garder` (Next) : identité exigée (401 sans), aucune permission ; `@SessionSeule()` se combine ; - décision énumérée `authentifiee`, acceptée par `auth.route-sans-decision` ; `@Permission()` croisé est un écart qui dit de la retirer ; - contrat Next : `x-eqs-authentifie` ; les deux harnais écartent ces routes de `auth.403-permission`, comme `moi.lire` ; - `/moi` de la plateforme porte `@Authentifie()` ; `LIBRES` reste. Déjà sur `main` : les dispenses s'appliquent dans les harnais (#149) ; le message de l'écart la nomme désormais. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>Le hub réécrivait le corps de `sign-in/social` par un `fetchImpl` pour y glisser `oauth_query`, recopiait l'extraction des paramètres signés, et sa page `/connexion?echec=…` n'était alimentée par rien : `errorCallbackURL` n'était jamais posé. - `urlDeConnexion` et `SignIn` : `oauthQuery` (→ `oauth_query`, sur `sign-in/social` et `sign-in/email` ; par mot de passe, la connexion suit l'adresse que better-auth rend) et `retourEchec` (→ `errorCallbackURL`, filtré par `retourSur`) ; - `repriseOAuth(recherche)` : les seuls paramètres signés ; - `PageConnexion({ reprendreOAuth: true })`. Absents, le corps de toujours (testé). Un `retourEchec` hors du site n'est pas transmis, tabulation comprise. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>Plan du hub A-7. Jeton du hub : `at+jwt` EdDSA, `iss` = le hub, `aud` = le service, `scope` = permissions natives, `oid`, `act: { sub, typ: 'agent' }`. - `DepsPrincipal.emetteurs` : `resoudrePrincipal` lit l'`iss` sans vérifier, pour choisir qui vérifiera, et confie le jeton à cet émetteur : signature contre SES clés, `typ`, EdDSA, expiration (401) ; audience (403) ; la personne retrouvée ICI (`utilisateurParOid`, compte Microsoft ; 403 si inconnue ou suspendue) ; permissions = rôles d'ici ∩ portée ; `Principal.agent = { clientId, scopes }`. Un `iss` inconnu : Entra, sinon 401 ; - `HUB_ISSUER`, `HUB_AUDIENCE` (défaut `PUBLIC_URL`), `HUB_JWKS_URL` (défaut : découverte RFC 8414, un `issuer` différent annoncé est refusé), deux règles bloquantes ; `auth.hub` (jwks, utilisateur, now) dans `createEqsApp` et `creerApi` ; - conformité : `auth.jeton-hub-emetteur` (401), `-audience` (403), `-portee` (403), sans objet sans `HUB_ISSUER` ; `hubDeTest()` dans `@eqs/testing`. Sans `HUB_ISSUER`, rien ne change (testé). Prouvé : 18 cas sur `resoudrePrincipal` dont la découverte sur un serveur local ; de bout en bout sur `createEqsApp` et `creerApi` ; les trois contrôles verts contre un service qui accepte le hub, l'audience rouge contre un qui ne l'accepte pas. En montant : `HUB_ISSUER=`, `HUB_AUDIENCE=`, `HUB_JWKS_URL=` dans `.env.example`. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>