@mostajs/auth 3.0.2 → 3.1.0

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,40 @@
1
+ /**
2
+ * Génère un nouveau token anonyme — 32 caractères hexadécimaux issus de
3
+ * 16 bytes de `randomBytes` (CSPRNG).
4
+ */
5
+ export declare function generateAnonToken(): string;
6
+ /**
7
+ * Formate un email synthétique stable pour un token + un scope.
8
+ * Le scope évite qu'un même token "fuite" inter-projets *(domaine
9
+ * différent → email différent → respondent distinct par projet)*.
10
+ *
11
+ * Le résultat est non-routable (`.anon.local`) — pas de risque
12
+ * d'envoi mail par accident.
13
+ *
14
+ * @example
15
+ * anonEmail('a1b2c3d4e5f6', 'survey-2026')
16
+ * → 'anon-a1b2c3d4e5f6@survey-2026.anon.local'
17
+ */
18
+ export declare function anonEmail(token: string, scope: string): string;
19
+ /**
20
+ * Vrai si l'email donné a la forme générée par `anonEmail` — utile
21
+ * pour repérer les respondents anonymes dans les dashboards / exports
22
+ * sans avoir à stocker un flag séparé *(quoique le flag reste une
23
+ * bonne pratique pour la requête DB)*.
24
+ */
25
+ export declare function isAnonEmail(email: string | null | undefined): boolean;
26
+ /**
27
+ * Convention de nom du cookie à utiliser. Le consumer reste libre de
28
+ * choisir le sien, mais cette constante factorise la pratique courante.
29
+ */
30
+ export declare const ANON_COOKIE_DEFAULT_NAME = "anon_tk";
31
+ /**
32
+ * Options de cookie recommandées (utilisées par les implémentations
33
+ * Next/Express). Le consumer applique celles-ci à son cookie store.
34
+ */
35
+ export declare const ANON_COOKIE_DEFAULT_OPTIONS: {
36
+ httpOnly: boolean;
37
+ sameSite: "lax";
38
+ path: string;
39
+ maxAge: number;
40
+ };
@@ -0,0 +1,69 @@
1
+ // @mostajs/auth — Anonymous token primitives — v3.1.0+
2
+ // Author: Dr Hamid MADANI <drmdh@msn.com>
3
+ //
4
+ // Pour les questionnaires / pages publiques `visibility=public-anon` qui
5
+ // veulent retrouver les réponses entre sessions sans demander d'email.
6
+ // Le module fournit uniquement les **primitives** : génération d'un token
7
+ // aléatoire et formatage d'un email synthétique stable. Le **stockage du
8
+ // cookie** est laissé au consumer car la signature dépend du framework
9
+ // (Next.js `cookies()`, Express `res.cookie()`, etc.).
10
+ //
11
+ // Design clé :
12
+ // - 16 bytes de hasard cryptographique → 32 chars hex. Suffisant contre
13
+ // la collision (probabilité < 2⁻⁶⁴ pour 10⁹ tokens).
14
+ // - Email synthétique de la forme `anon-<token12>@<scope>.anon.local` :
15
+ // stable, reconnaissable comme anon dans les exports / dashboards,
16
+ // non-routable (TLD `.local` réservé) → impossible d'envoyer un mail
17
+ // dessus par accident.
18
+ // - Aucune dépendance externe — uniquement `node:crypto`.
19
+ import { randomBytes } from 'node:crypto';
20
+ /**
21
+ * Génère un nouveau token anonyme — 32 caractères hexadécimaux issus de
22
+ * 16 bytes de `randomBytes` (CSPRNG).
23
+ */
24
+ export function generateAnonToken() {
25
+ return randomBytes(16).toString('hex');
26
+ }
27
+ /**
28
+ * Formate un email synthétique stable pour un token + un scope.
29
+ * Le scope évite qu'un même token "fuite" inter-projets *(domaine
30
+ * différent → email différent → respondent distinct par projet)*.
31
+ *
32
+ * Le résultat est non-routable (`.anon.local`) — pas de risque
33
+ * d'envoi mail par accident.
34
+ *
35
+ * @example
36
+ * anonEmail('a1b2c3d4e5f6', 'survey-2026')
37
+ * → 'anon-a1b2c3d4e5f6@survey-2026.anon.local'
38
+ */
39
+ export function anonEmail(token, scope) {
40
+ const t = String(token ?? '').slice(0, 12);
41
+ const s = String(scope ?? 'default').toLowerCase().replace(/[^a-z0-9-]+/g, '-');
42
+ return `anon-${t}@${s}.anon.local`;
43
+ }
44
+ /**
45
+ * Vrai si l'email donné a la forme générée par `anonEmail` — utile
46
+ * pour repérer les respondents anonymes dans les dashboards / exports
47
+ * sans avoir à stocker un flag séparé *(quoique le flag reste une
48
+ * bonne pratique pour la requête DB)*.
49
+ */
50
+ export function isAnonEmail(email) {
51
+ if (!email)
52
+ return false;
53
+ return /^anon-[a-f0-9]{12}@[a-z0-9-]+\.anon\.local$/.test(email);
54
+ }
55
+ /**
56
+ * Convention de nom du cookie à utiliser. Le consumer reste libre de
57
+ * choisir le sien, mais cette constante factorise la pratique courante.
58
+ */
59
+ export const ANON_COOKIE_DEFAULT_NAME = 'anon_tk';
60
+ /**
61
+ * Options de cookie recommandées (utilisées par les implémentations
62
+ * Next/Express). Le consumer applique celles-ci à son cookie store.
63
+ */
64
+ export const ANON_COOKIE_DEFAULT_OPTIONS = {
65
+ httpOnly: true,
66
+ sameSite: 'lax',
67
+ path: '/',
68
+ maxAge: 60 * 60 * 24 * 365, // 1 an
69
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mostajs/auth",
3
- "version": "3.0.2",
3
+ "version": "3.1.0",
4
4
  "description": "Authentication — complete: email/password (Argon2id) + OAuth + magic link + MFA TOTP + WebAuthn/Passkeys + RGPD lifecycle + device_flow/pkce events + accountId propagation server↔client",
5
5
  "author": "Dr Hamid MADANI <drmdh@msn.com>",
6
6
  "license": "AGPL-3.0-or-later",
@@ -113,6 +113,11 @@
113
113
  "import": "./dist/lib/magic-link.js",
114
114
  "default": "./dist/lib/magic-link.js"
115
115
  },
116
+ "./lib/anon-token": {
117
+ "types": "./dist/lib/anon-token.d.ts",
118
+ "import": "./dist/lib/anon-token.js",
119
+ "default": "./dist/lib/anon-token.js"
120
+ },
116
121
  "./lib/mfa-totp": {
117
122
  "types": "./dist/lib/mfa-totp.d.ts",
118
123
  "import": "./dist/lib/mfa-totp.js",