@lab-anssi/lib 1.4.2 → 1.5.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.
package/README.md CHANGED
@@ -1,2 +1,43 @@
1
1
  # lab-anssi-lib
2
2
  Une librairie de code mutualisé pour les produits du Lab. Innovation de l'ANSSI
3
+
4
+ ## serveur
5
+
6
+ Un certain nombre de comportements standards sont intégrés dans `serveur/serveurLab`, en particulier
7
+ le filtrage IP (pour n'autoriser que les requêtes venant du waf) et le rate limit.
8
+
9
+ Pour l'utiliser, remplacez votre code de la forme :
10
+
11
+ ```
12
+ const app = express();
13
+ app.get('/', (req, res) => {res.json({})});
14
+ ```
15
+
16
+ Par un code de la forme :
17
+
18
+ ```
19
+ const app = creeServeurLab({
20
+ reseau: {
21
+ ipAutorisees: [ipWaf],
22
+ trustProxy: 0,
23
+ maxRequetesParMinute: 500,
24
+ },
25
+ });
26
+ app.get('/', (req, res) => {res.json({})});
27
+ ```
28
+
29
+ La configuration serveur peut-être construite automatiquement à partir des variables d'environnement :
30
+
31
+ ```
32
+ const config = adaptateurEnvironnementServeurLab();
33
+ const app = creeServeurLab(config);
34
+ app.get('/', (req, res) => {res.json({})});
35
+ ```
36
+
37
+ Dans ce cas, vous devez positionner des variables d'environnement de la forme :
38
+
39
+ ```
40
+ SERVEUR_TRUST_PROXY = # optionnel (0 par défaut) nombre de proxies en amont du service ou configuration plus fine de trust proxy, Cf. https://expressjs.com/en/guide/behind-proxies.html
41
+ SERVEUR_MAX_REQUETES_PAR_MINUTE = # optionnel (600 par défaut) nombre maximum de requêtes par minute par IP
42
+ SERVEUR_ADRESSES_IP_AUTORISEES = # Seules ces IP seront autorisées. Les autres ne seront pas servies. Séparées par des ',' s'il y en a plusieurs. Supprimer la variable d'env pour désactiver le filtrage.
43
+ ```
package/dist/index.d.ts CHANGED
@@ -2,3 +2,6 @@ export { type EntreeTableDesMatieres, type PageHtmlCrisp, type ResumeArticleCris
2
2
  export { CmsCrisp } from './cms/cmsCrisp';
3
3
  export { AdaptateurProfilAnssi } from './profilAnssi/adaptateurProfilAnssi';
4
4
  export { ErreurArticleCrispIntrouvable } from './erreurs';
5
+ export { type ConfigurationServeurLab } from './serveur/serveurLab';
6
+ export { creeServeurLab } from './serveur/serveurLab';
7
+ export { adaptateurEnvironnementServeurLab } from './serveur/adaptateurEnvironnementServeurLab';
package/dist/index.js CHANGED
@@ -1,9 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ErreurArticleCrispIntrouvable = exports.AdaptateurProfilAnssi = exports.CmsCrisp = void 0;
3
+ exports.adaptateurEnvironnementServeurLab = exports.creeServeurLab = exports.ErreurArticleCrispIntrouvable = exports.AdaptateurProfilAnssi = exports.CmsCrisp = void 0;
4
4
  var cmsCrisp_1 = require("./cms/cmsCrisp");
5
5
  Object.defineProperty(exports, "CmsCrisp", { enumerable: true, get: function () { return cmsCrisp_1.CmsCrisp; } });
6
6
  var adaptateurProfilAnssi_1 = require("./profilAnssi/adaptateurProfilAnssi");
7
7
  Object.defineProperty(exports, "AdaptateurProfilAnssi", { enumerable: true, get: function () { return adaptateurProfilAnssi_1.AdaptateurProfilAnssi; } });
8
8
  var erreurs_1 = require("./erreurs");
9
9
  Object.defineProperty(exports, "ErreurArticleCrispIntrouvable", { enumerable: true, get: function () { return erreurs_1.ErreurArticleCrispIntrouvable; } });
10
+ var serveurLab_1 = require("./serveur/serveurLab");
11
+ Object.defineProperty(exports, "creeServeurLab", { enumerable: true, get: function () { return serveurLab_1.creeServeurLab; } });
12
+ var adaptateurEnvironnementServeurLab_1 = require("./serveur/adaptateurEnvironnementServeurLab");
13
+ Object.defineProperty(exports, "adaptateurEnvironnementServeurLab", { enumerable: true, get: function () { return adaptateurEnvironnementServeurLab_1.adaptateurEnvironnementServeurLab; } });
@@ -0,0 +1,2 @@
1
+ import { ConfigurationServeurLab } from './serveurLab';
2
+ export declare const adaptateurEnvironnementServeurLab: () => ConfigurationServeurLab;
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.adaptateurEnvironnementServeurLab = void 0;
4
+ const trustProxy = () => {
5
+ const trustProxyEnChaine = process.env.SERVEUR_TRUST_PROXY || '0';
6
+ const trustProxyEnNombre = Number(trustProxyEnChaine);
7
+ if (isNaN(trustProxyEnNombre)) {
8
+ console.warn(`Attention ! SERVEUR_TRUST_PROXY positionné à ${trustProxyEnChaine}`);
9
+ return trustProxyEnChaine;
10
+ }
11
+ else {
12
+ return trustProxyEnNombre;
13
+ }
14
+ };
15
+ const maxRequetesParMinute = () => {
16
+ const maxEnChaine = process.env.SERVEUR_MAX_REQUETES_PAR_MINUTE || '600';
17
+ const maxEnNombre = Number(maxEnChaine);
18
+ if (isNaN(maxEnNombre)) {
19
+ throw new Error(`SERVEUR_MAX_REQUETES_PAR_MINUTE n'est pas un nombre : ${maxEnChaine}`);
20
+ }
21
+ else {
22
+ return maxEnNombre;
23
+ }
24
+ };
25
+ const adaptateurEnvironnementServeurLab = () => {
26
+ return {
27
+ reseau: {
28
+ trustProxy: trustProxy(),
29
+ maxRequetesParMinute: maxRequetesParMinute(),
30
+ ipAutorisees: process.env.SERVEUR_ADRESSES_IP_AUTORISEES?.split(',') ?? false,
31
+ },
32
+ };
33
+ };
34
+ exports.adaptateurEnvironnementServeurLab = adaptateurEnvironnementServeurLab;
@@ -0,0 +1,9 @@
1
+ import { Express } from 'express';
2
+ export declare const creeServeurLab: (config: ConfigurationServeurLab) => Express;
3
+ export type ConfigurationServeurLab = {
4
+ reseau: {
5
+ trustProxy: number | string;
6
+ maxRequetesParMinute: number;
7
+ ipAutorisees: string[] | false;
8
+ };
9
+ };
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.creeServeurLab = void 0;
7
+ const express_ipfilter_1 = require("express-ipfilter");
8
+ const express_rate_limit_1 = __importDefault(require("express-rate-limit"));
9
+ const creeServeurLab = (config) => {
10
+ const express = require('express');
11
+ const app = express();
12
+ const limiteRequetesParMinute = (0, express_rate_limit_1.default)({
13
+ windowMs: 60 * 1000,
14
+ limit: config.reseau.maxRequetesParMinute,
15
+ });
16
+ app.set('trust proxy', config.reseau.trustProxy);
17
+ app.use(limiteRequetesParMinute);
18
+ if (config.reseau.ipAutorisees) {
19
+ app.use((0, express_ipfilter_1.IpFilter)(config.reseau.ipAutorisees, {
20
+ detectIp: (request) => {
21
+ const forwardedFor = request.headers['x-forwarded-for'];
22
+ if (typeof forwardedFor === 'string') {
23
+ const ips = forwardedFor
24
+ .split(',')
25
+ .map((ip) => ip.trim())
26
+ .filter((ip) => ip !== '');
27
+ if (ips.length > 0) {
28
+ const ipWaf = ips[ips.length - 1];
29
+ return ipWaf;
30
+ }
31
+ }
32
+ return 'interdire';
33
+ },
34
+ mode: 'allow',
35
+ log: false,
36
+ }));
37
+ app.use((err, req, res, next) => {
38
+ if (err instanceof express_ipfilter_1.IpDeniedError) {
39
+ res.status(403).send('Access denied');
40
+ }
41
+ else {
42
+ next(err);
43
+ }
44
+ });
45
+ }
46
+ return app;
47
+ };
48
+ exports.creeServeurLab = creeServeurLab;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lab-anssi/lib",
3
- "version": "1.4.2",
3
+ "version": "1.5.0",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/betagouv/lab-anssi-lib.git"
@@ -26,14 +26,22 @@
26
26
  }
27
27
  },
28
28
  "devDependencies": {
29
+ "@types/express": "5.0.0",
29
30
  "@types/node": "^22.14.1",
31
+ "@types/supertest": "^6.0.3",
30
32
  "prettier": "^3.5.3",
33
+ "supertest": "^7.1.1",
31
34
  "tsx": "^4.19.3",
32
35
  "typescript": "^5.8.3"
33
36
  },
34
37
  "dependencies": {
38
+ "express-ipfilter": "^1.3.2",
39
+ "express-rate-limit": "^7.5.1",
35
40
  "axios": "^1.9.0",
36
41
  "html-entities": "^2.6.0",
37
42
  "marked": "^13.0.3"
43
+ },
44
+ "peerDependencies": {
45
+ "express": "^4.21.2"
38
46
  }
39
- }
47
+ }