@zarex/next 0.1.0 → 0.1.1
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 +117 -0
- package/package.json +2 -2
package/README.md
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# @zarex/next
|
|
2
|
+
|
|
3
|
+
Garde Zarex pour Next.js — fonctionne dans le middleware (runtime edge) **et** dans les route handlers. Aucune dépendance à `next` à l'exécution : utilise la `Request`/`Response` standard, sans risque d'incompatibilité de version.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @zarex/next
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Démarrage rapide — middleware
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
// middleware.ts
|
|
15
|
+
import { NextResponse } from "next/server";
|
|
16
|
+
import { zarexNext, shield, rateLimit } from "@zarex/next";
|
|
17
|
+
|
|
18
|
+
const guard = zarexNext({
|
|
19
|
+
key: process.env.ZAREX_KEY!,
|
|
20
|
+
ipSource: "vercel", // voir "L'adresse IP du visiteur" ci-dessous
|
|
21
|
+
rules: [shield(), rateLimit({ max: 100, window: "1m" })],
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
export async function middleware(request: Request) {
|
|
25
|
+
// `guard.finalize(...)` sur la réponse AUTORISÉE aussi, pas seulement sur un refus —
|
|
26
|
+
// sans cet appel, secureHeaders/responseGuard ne s'appliqueraient JAMAIS au trafic autorisé.
|
|
27
|
+
return (await guard(request)) ?? guard.finalize(NextResponse.next(), request);
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
**Fail-open** : si Zarex est injoignable, lent ou répond de façon inattendue, la requête passe toujours.
|
|
32
|
+
|
|
33
|
+
## Démarrage rapide — route handler
|
|
34
|
+
|
|
35
|
+
```ts
|
|
36
|
+
// app/api/produits/route.ts
|
|
37
|
+
import { withZarex, shield } from "@zarex/next";
|
|
38
|
+
|
|
39
|
+
export const GET = withZarex(
|
|
40
|
+
{ key: process.env.ZAREX_KEY!, ipSource: "vercel", rules: [shield()] },
|
|
41
|
+
async (request) => Response.json({ produits: [] })
|
|
42
|
+
);
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Avec `withZarex`, `secureHeaders`/`responseGuard` s'appliquent automatiquement à la réponse — pas d'appel à `finalize` à faire soi-même.
|
|
46
|
+
|
|
47
|
+
## L'adresse IP du visiteur — point important
|
|
48
|
+
|
|
49
|
+
Le **middleware** Next.js ne voit jamais l'adresse de la connexion TCP (limite de la plateforme, pas du SDK). Seules les sources qui lisent un en-tête posé par la plateforme fonctionnent donc en middleware :
|
|
50
|
+
|
|
51
|
+
| `ipSource` | Quand l'utiliser |
|
|
52
|
+
|---|---|
|
|
53
|
+
| `"vercel"` | Hébergé sur Vercel. |
|
|
54
|
+
| `"fly"` | Hébergé sur Fly.io. |
|
|
55
|
+
| `"auto"` | Détecte Vercel/Fly via les variables d'environnement du serveur. |
|
|
56
|
+
| `"cloudflare"` | Derrière Cloudflare : lit `CF-Connecting-IP`, seulement si la connexion vient réellement de Cloudflare. |
|
|
57
|
+
| `{ proxies: n }` / `{ trustedProxies: [...] }` | Un nombre connu de proxys de confiance, ou leurs plages CIDR exactes. |
|
|
58
|
+
|
|
59
|
+
Hébergé ailleurs (nginx, Docker, un VPS...) sans que la plateforme ne pose un en-tête fiable : utiliser un route handler avec `withZarex` ne change rien à cette limite non plus, puisque la limite vient de Next.js lui-même, pas de l'adaptateur.
|
|
60
|
+
|
|
61
|
+
## Options
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
zarexNext({
|
|
65
|
+
key: string, // obligatoire : clé API du projet
|
|
66
|
+
rules: Rule[], // obligatoire : 1 à 10 règles, voir ci-dessous
|
|
67
|
+
ipSource: IpSource, // obligatoire — voir ci-dessus
|
|
68
|
+
inspectBody?: boolean,
|
|
69
|
+
secureHeaders?: boolean | SecureHeadersOptions,
|
|
70
|
+
responseGuard?: boolean | ResponseGuardOptions,
|
|
71
|
+
onDeny?: (request, decision) => Response | undefined,
|
|
72
|
+
onDegraded?: (request, decision) => void,
|
|
73
|
+
call?: (request: Request) => ProtectCall | undefined,
|
|
74
|
+
timeoutMs?: number, // défaut 500 ms
|
|
75
|
+
breaker?: BreakerOptions | false,
|
|
76
|
+
})
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### En-têtes de sécurité et surveillance des réponses
|
|
80
|
+
|
|
81
|
+
```ts
|
|
82
|
+
const guard = zarexNext({ ..., secureHeaders: true, responseGuard: true });
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
En **middleware**, appelez bien `guard.finalize(response, request)` sur la réponse autorisée (voir l'exemple de démarrage rapide) — un avertissement s'affiche au démarrage (`console.warn`) si `secureHeaders`/`responseGuard` est configuré sans jamais appeler `finalize` sur le chemin autorisé, pour éviter que cette protection reste silencieusement inactive. En **route handler** (`withZarex`), c'est automatique.
|
|
86
|
+
|
|
87
|
+
### Identifiants personnalisés (`call`)
|
|
88
|
+
|
|
89
|
+
```ts
|
|
90
|
+
zarexNext({
|
|
91
|
+
key, ipSource: "vercel",
|
|
92
|
+
rules: [rateLimit({ max: 100, window: "1m", characteristics: ["userId"] })],
|
|
93
|
+
call: (request) => ({ characteristics: { userId: request.headers.get("x-user-id") ?? undefined } }),
|
|
94
|
+
});
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Les valeurs sont hachées en SHA-256 avant l'envoi à Zarex. Une erreur dans cette fonction est silencieusement ignorée. `call` peut aussi fournir `tokensRequested`, `email`/`phone` ou `text` (voir [`@zarex/core`](https://www.npmjs.com/package/@zarex/core)).
|
|
98
|
+
|
|
99
|
+
## Règles disponibles
|
|
100
|
+
|
|
101
|
+
| Fonction | Résumé |
|
|
102
|
+
|---|---|
|
|
103
|
+
| `shield(opts?)` | Pare-feu applicatif : injection SQL, XSS, traversée de répertoires, SSRF, SSTI... |
|
|
104
|
+
| `rateLimit({ max, window, ... })` | Limite de requêtes par visiteur sur une fenêtre de temps. |
|
|
105
|
+
| `tokenBucket({ capacity, refillRate, interval })` | Budget de jetons avec pics autorisés. |
|
|
106
|
+
| `detectBot(opts?)` | Détecte les robots connus, avec vérification DNS inversée. |
|
|
107
|
+
| `requestFilter({ expressions, logic })` | Règles personnalisées sur IP, chemin, en-têtes, cookies, pays... |
|
|
108
|
+
| `sensitiveInfo(opts?)` | Refuse une requête contenant une donnée sensible (nécessite `inspectBody`). |
|
|
109
|
+
| `emailValidation(opts?)` | Valide un email donné via `call: () => ({ email })`. |
|
|
110
|
+
| `phoneValidation(opts?)` | Valide un numéro donné, orienté opérateurs africains (MTN, Moov, Orange, Wave...). |
|
|
111
|
+
| `promptInjection(opts?)` | Détecte les tentatives de manipulation d'un assistant IA, via `call: () => ({ text })`. |
|
|
112
|
+
|
|
113
|
+
Chaque règle accepte `mode: "LIVE" | "DRY_RUN" | "OFF"`. Détails complets des options : voir [`@zarex/core`](https://www.npmjs.com/package/@zarex/core).
|
|
114
|
+
|
|
115
|
+
## Licence
|
|
116
|
+
|
|
117
|
+
MIT
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zarex/next",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Zarex — Next.js (middleware edge et route handlers)",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"publishConfig": {
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
],
|
|
28
28
|
"sideEffects": false,
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@zarex/core": "^0.1.
|
|
30
|
+
"@zarex/core": "^0.1.1"
|
|
31
31
|
},
|
|
32
32
|
"peerDependencies": {
|
|
33
33
|
"next": ">=13"
|