diff --git a/package-lock.json b/package-lock.json
index 2f916b83..b779eba9 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -51,7 +51,6 @@
"html-to-text": "^9.0.5",
"http-errors": "^2.0.0",
"ioredis": "^5.4.1",
- "is-disposable-email-domain": "^1.0.7",
"lodash": "^4.17.21",
"lodash-es": "^4.17.21",
"moment": "^2.30.1",
@@ -67,7 +66,7 @@
"qrcode": "^1.5.4",
"rate-limiter-flexible": "^2.4.2",
"tld-extract": "^2.1.0",
- "tsx": "^4.17.0",
+ "tsx": "^4.19.2",
"typescript": "^5.5.4",
"vite": "^5.2.14",
"zod": "^3.23.8",
@@ -78,28 +77,28 @@
"@changesets/cli": "^2.27.10",
"@simplewebauthn/types": "^10.0.0",
"@sinonjs/fake-timers": "^11.2.2",
- "@types/chai": "^5.0.0",
+ "@types/chai": "^5.0.1",
"@types/chai-as-promised": "^7.1.8",
"@types/html-to-text": "^9.0.4",
"@types/http-errors": "^2.0.4",
"@types/lodash": "^4.17.10",
"@types/lodash-es": "^4.17.12",
- "@types/mocha": "^10.0.7",
- "@types/node": "^22.1.0",
+ "@types/mocha": "^10.0.10",
+ "@types/node": "^22.10.2",
"@types/nodemailer": "^6.4.16",
"@types/oidc-provider": "^8.5.2",
"@types/qrcode": "^1.5.5",
"@types/sinonjs__fake-timers": "^8.1.5",
"axe-core": "^4.8.4",
- "chai": "^5.1.1",
- "chai-as-promised": "^8.0.0",
+ "chai": "^5.1.2",
+ "chai-as-promised": "^8.0.1",
"concurrently": "^9.0.1",
"copy-and-watch": "^0.1.6",
"csv": "^6.3.9",
"cypress": "^13.15.2",
"cypress-axe": "^1.5.0",
"cypress-maildev": "^1.3.2",
- "mocha": "^10.7.3",
+ "mocha": "^11.0.1",
"nock": "^13.5.4",
"prettier": "^3.3.3",
"prettier-plugin-organize-imports": "^4.0.0"
@@ -2397,11 +2396,14 @@
}
},
"node_modules/@types/chai": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.0.0.tgz",
- "integrity": "sha512-+DwhEHAaFPPdJ2ral3kNHFQXnTfscEEFsUxzD+d7nlcLrFK23JtNjH71RGasTcHb88b4vVi4mTyfpf8u2L8bdA==",
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.0.1.tgz",
+ "integrity": "sha512-5T8ajsg3M/FOncpLYW7sdOcD6yf4+722sze/tc4KQV0P8Z2rAr3SAuHCIkYmYpt8VbcQlnz8SxlOlPQYefe4cA==",
"dev": true,
- "license": "MIT"
+ "license": "MIT",
+ "dependencies": {
+ "@types/deep-eql": "*"
+ }
},
"node_modules/@types/chai-as-promised": {
"version": "7.1.8",
@@ -2469,6 +2471,13 @@
"@types/node": "*"
}
},
+ "node_modules/@types/deep-eql": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz",
+ "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/@types/ejs": {
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/@types/ejs/-/ejs-3.1.5.tgz",
@@ -2585,9 +2594,9 @@
"integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA=="
},
"node_modules/@types/mocha": {
- "version": "10.0.7",
- "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.7.tgz",
- "integrity": "sha512-GN8yJ1mNTcFcah/wKEFIJckJx9iJLoMSzWcfRRuxz/Jk+U6KQNnml+etbtxFK8lPjzOw3zp4Ha/kjSst9fsHYw==",
+ "version": "10.0.10",
+ "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.10.tgz",
+ "integrity": "sha512-xPyYSz1cMPnJQhl0CLMH68j3gprKZaTjG3s5Vi+fDgx+uhG9NOXwbVt52eFS8ECyXhyKcjDLCBEqBExKuiZb7Q==",
"dev": true,
"license": "MIT"
},
@@ -2600,12 +2609,12 @@
}
},
"node_modules/@types/node": {
- "version": "22.5.0",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.0.tgz",
- "integrity": "sha512-DkFrJOe+rfdHTqqMg0bSNlGlQ85hSoh2TPzZyhHsXnMtligRWpxUySiyw8FY14ITt24HVCiQPWxS3KO/QlGmWg==",
+ "version": "22.10.2",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.2.tgz",
+ "integrity": "sha512-Xxr6BBRCAOQixvonOye19wnzyDiUtTeqldOOmj3CkeblonbccA12PFwlufvRdrpjXxqnmUaeiU5EOA+7s5diUQ==",
"license": "MIT",
"dependencies": {
- "undici-types": "~6.19.2"
+ "undici-types": "~6.20.0"
}
},
"node_modules/@types/nodemailer": {
@@ -3495,9 +3504,9 @@
}
},
"node_modules/chai": {
- "version": "5.1.1",
- "resolved": "https://registry.npmjs.org/chai/-/chai-5.1.1.tgz",
- "integrity": "sha512-pT1ZgP8rPNqUgieVaEY+ryQr6Q4HXNg8Ei9UnLUrjN4IA7dvQC5JB+/kxVcPNDHyBcc/26CXPkbNzq3qwrOEKA==",
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/chai/-/chai-5.1.2.tgz",
+ "integrity": "sha512-aGtmf24DW6MLHHG5gCx4zaI3uBq3KRtxeVs0DjFH6Z0rDNbsvTxFASFvdj79pxjxZ8/5u3PIiN3IwEIQkiiuPw==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -3512,11 +3521,11 @@
}
},
"node_modules/chai-as-promised": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-8.0.0.tgz",
- "integrity": "sha512-sMsGXTrS3FunP/wbqh/KxM8Kj/aLPXQGkNtvE5wPfSToq8wkkvBpTZo1LIiEVmC4BwkKpag+l5h/20lBMk6nUg==",
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-8.0.1.tgz",
+ "integrity": "sha512-OIEJtOL8xxJSH8JJWbIoRjybbzR52iFuDHuF8eb+nTPD6tgXLjRqsgnUGqQfFODxYvq5QdirT0pN9dZ0+Gz6rA==",
"dev": true,
- "license": "WTFPL",
+ "license": "MIT",
"dependencies": {
"check-error": "^2.0.0"
},
@@ -6893,9 +6902,9 @@
"peer": true
},
"node_modules/mocha": {
- "version": "10.7.3",
- "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.7.3.tgz",
- "integrity": "sha512-uQWxAu44wwiACGqjbPYmjo7Lg8sFrS3dQe7PP2FQI+woptP4vZXSMcfMyFL/e1yFEeEpV4RtyTpZROOKmxis+A==",
+ "version": "11.0.1",
+ "resolved": "https://registry.npmjs.org/mocha/-/mocha-11.0.1.tgz",
+ "integrity": "sha512-+3GkODfsDG71KSCQhc4IekSW+ItCK/kiez1Z28ksWvYhKXV/syxMlerR/sC7whDp7IyreZ4YxceMLdTs5hQE8A==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -6906,7 +6915,7 @@
"diff": "^5.2.0",
"escape-string-regexp": "^4.0.0",
"find-up": "^5.0.0",
- "glob": "^8.1.0",
+ "glob": "^10.4.5",
"he": "^1.2.0",
"js-yaml": "^4.1.0",
"log-symbols": "^4.1.0",
@@ -6925,7 +6934,7 @@
"mocha": "bin/mocha.js"
},
"engines": {
- "node": ">= 14.0.0"
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
}
},
"node_modules/mocha/node_modules/brace-expansion": {
@@ -6933,6 +6942,7 @@
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0"
}
@@ -6963,19 +6973,37 @@
"license": "MIT"
},
"node_modules/mocha/node_modules/glob": {
- "version": "8.1.0",
- "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz",
- "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==",
+ "version": "10.4.5",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
+ "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==",
"dev": true,
+ "license": "ISC",
"dependencies": {
- "fs.realpath": "^1.0.0",
- "inflight": "^1.0.4",
- "inherits": "2",
- "minimatch": "^5.0.1",
- "once": "^1.3.0"
+ "foreground-child": "^3.1.0",
+ "jackspeak": "^3.1.2",
+ "minimatch": "^9.0.4",
+ "minipass": "^7.1.2",
+ "package-json-from-dist": "^1.0.0",
+ "path-scurry": "^1.11.1"
+ },
+ "bin": {
+ "glob": "dist/esm/bin.mjs"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/mocha/node_modules/glob/node_modules/minimatch": {
+ "version": "9.0.5",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
+ "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^2.0.1"
},
"engines": {
- "node": ">=12"
+ "node": ">=16 || 14 >=14.17"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
@@ -9410,9 +9438,9 @@
}
},
"node_modules/tsx": {
- "version": "4.17.0",
- "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.17.0.tgz",
- "integrity": "sha512-eN4mnDA5UMKDt4YZixo9tBioibaMBpoxBkD+rIPAjVmYERSG0/dWEY1CEFuV89CgASlKL499q8AhmkMnnjtOJg==",
+ "version": "4.19.2",
+ "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.19.2.tgz",
+ "integrity": "sha512-pOUl6Vo2LUq/bSa8S5q7b91cgNSjctn9ugq/+Mvow99qW6x/UZYwzxy/3NmqoT66eHYfCVvFvACC58UBPFf28g==",
"license": "MIT",
"dependencies": {
"esbuild": "~0.23.0",
@@ -9548,9 +9576,9 @@
}
},
"node_modules/undici-types": {
- "version": "6.19.8",
- "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz",
- "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==",
+ "version": "6.20.0",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
+ "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
"license": "MIT"
},
"node_modules/universalify": {
@@ -10365,14 +10393,18 @@
"license": "MIT",
"dependencies": {
"@zootools/email-spell-checker": "^1.12.0",
- "is-disposable-email-domain": "^1.0.7"
+ "is-disposable-email-domain": "^1.0.7",
+ "lodash-es": "^4.17.21",
+ "tld-extract": "^2.1.0"
},
"devDependencies": {
"@tsconfig/node22": "^22.0.0",
- "@types/mocha": "^10.0.7",
- "chai": "^5.1.1",
- "mocha": "^10.7.3",
- "tsx": "^4.17.0"
+ "@types/lodash-es": "^4.17.12",
+ "@types/mocha": "^10.0.10",
+ "@types/node": "^22.10.2",
+ "chai": "^5.1.2",
+ "mocha": "^11.0.1",
+ "tsx": "^4.19.2"
}
},
"packages/email": {
diff --git a/package.json b/package.json
index 3facc92c..81782c98 100644
--- a/package.json
+++ b/package.json
@@ -85,7 +85,6 @@
"html-to-text": "^9.0.5",
"http-errors": "^2.0.0",
"ioredis": "^5.4.1",
- "is-disposable-email-domain": "^1.0.7",
"lodash": "^4.17.21",
"lodash-es": "^4.17.21",
"moment": "^2.30.1",
@@ -101,7 +100,7 @@
"qrcode": "^1.5.4",
"rate-limiter-flexible": "^2.4.2",
"tld-extract": "^2.1.0",
- "tsx": "^4.17.0",
+ "tsx": "^4.19.2",
"typescript": "^5.5.4",
"vite": "^5.2.14",
"zod": "^3.23.8",
@@ -112,28 +111,28 @@
"@changesets/cli": "^2.27.10",
"@simplewebauthn/types": "^10.0.0",
"@sinonjs/fake-timers": "^11.2.2",
- "@types/chai": "^5.0.0",
+ "@types/chai": "^5.0.1",
"@types/chai-as-promised": "^7.1.8",
"@types/html-to-text": "^9.0.4",
"@types/http-errors": "^2.0.4",
"@types/lodash": "^4.17.10",
"@types/lodash-es": "^4.17.12",
- "@types/mocha": "^10.0.7",
- "@types/node": "^22.1.0",
+ "@types/mocha": "^10.0.10",
+ "@types/node": "^22.10.2",
"@types/nodemailer": "^6.4.16",
"@types/oidc-provider": "^8.5.2",
"@types/qrcode": "^1.5.5",
"@types/sinonjs__fake-timers": "^8.1.5",
"axe-core": "^4.8.4",
- "chai": "^5.1.1",
- "chai-as-promised": "^8.0.0",
+ "chai": "^5.1.2",
+ "chai-as-promised": "^8.0.1",
"concurrently": "^9.0.1",
"copy-and-watch": "^0.1.6",
"csv": "^6.3.9",
"cypress": "^13.15.2",
"cypress-axe": "^1.5.0",
"cypress-maildev": "^1.3.2",
- "mocha": "^10.7.3",
+ "mocha": "^11.0.1",
"nock": "^13.5.4",
"prettier": "^3.3.3",
"prettier-plugin-organize-imports": "^4.0.0"
diff --git a/packages/core/package.json b/packages/core/package.json
index e953d5d7..4e1360a4 100644
--- a/packages/core/package.json
+++ b/packages/core/package.json
@@ -20,15 +20,15 @@
"exports": {
"./*": {
"require": {
- "types": "./dist/*",
- "default": "./dist/*"
+ "types": "./dist/*/index.d.ts",
+ "default": "./dist/*/index.js"
},
"import": {
- "types": "./dist/*",
- "default": "./dist/*"
+ "types": "./dist/*/index.d.ts",
+ "default": "./dist/*/index.js"
},
- "types": "./dist/*",
- "default": "./dist/*"
+ "types": "./dist/*/index.d.ts",
+ "default": "./dist/*/index.js"
}
},
"scripts": {
@@ -46,14 +46,18 @@
},
"dependencies": {
"@zootools/email-spell-checker": "^1.12.0",
- "is-disposable-email-domain": "^1.0.7"
+ "is-disposable-email-domain": "^1.0.7",
+ "lodash-es": "^4.17.21",
+ "tld-extract": "^2.1.0"
},
"devDependencies": {
"@tsconfig/node22": "^22.0.0",
- "@types/mocha": "^10.0.7",
- "chai": "^5.1.1",
- "mocha": "^10.7.3",
- "tsx": "^4.17.0"
+ "@types/mocha": "^10.0.10",
+ "@types/node": "^22.10.2",
+ "@types/lodash-es": "^4.17.12",
+ "chai": "^5.1.2",
+ "mocha": "^11.0.1",
+ "tsx": "^4.19.2"
},
"publishConfig": {
"access": "public",
diff --git a/packages/core/src/security/index.ts b/packages/core/src/security/index.ts
new file mode 100644
index 00000000..83ae5ab7
--- /dev/null
+++ b/packages/core/src/security/index.ts
@@ -0,0 +1,7 @@
+//
+
+export * from "./is-domain-valid.js";
+export * from "./is-email-valid.js";
+export * from "./is-name-valid.js";
+export * from "./is-phone-number-valid.js";
+export * from "./is-siret-valid.js";
diff --git a/packages/core/src/security/is-domain-valid.test.ts b/packages/core/src/security/is-domain-valid.test.ts
new file mode 100644
index 00000000..ea5f4b2b
--- /dev/null
+++ b/packages/core/src/security/is-domain-valid.test.ts
@@ -0,0 +1,27 @@
+//
+
+import { assert } from "chai";
+import { isDomainValid } from "./is-domain-valid.js";
+
+//
+
+describe("isDomainValid", () => {
+ it("should return false for undefined value", () => {
+ assert.equal(isDomainValid(undefined), false);
+ });
+
+ it("should return false for empty string", () => {
+ assert.equal(isDomainValid(""), false);
+ });
+
+ it("should return false if contains characters other than number and letters", () => {
+ assert.equal(isDomainValid("héééééé"), false);
+ });
+
+ it("should allow dot less tld", () => {
+ assert.equal(isDomainValid("co.uk"), true);
+ });
+ it("should allow gouv.fr", () => {
+ assert.equal(isDomainValid("gouv.fr"), true);
+ });
+});
diff --git a/packages/core/src/security/is-domain-valid.ts b/packages/core/src/security/is-domain-valid.ts
new file mode 100644
index 00000000..1c084e3a
--- /dev/null
+++ b/packages/core/src/security/is-domain-valid.ts
@@ -0,0 +1,28 @@
+//
+
+import { isEmpty, isString } from "lodash-es";
+import { parse_host } from "tld-extract";
+
+//
+
+/*
+ * specifications of these functions can be found at
+ * https://cheatsheetseries.owasp.org/cheatsheets/Input_Validation_Cheat_Sheet.html#email-address-validation
+ */
+export function isDomainValid(domain: unknown): domain is string {
+ if (!isString(domain) || isEmpty(domain)) {
+ return false;
+ }
+
+ if (domain.match(/^[a-zA-Z0-9.-]*$/) === null) {
+ return false;
+ }
+
+ try {
+ parse_host(domain, { allowDotlessTLD: true });
+ } catch {
+ return false;
+ }
+
+ return true;
+}
diff --git a/packages/core/src/security/is-email-valid.test.ts b/packages/core/src/security/is-email-valid.test.ts
new file mode 100644
index 00000000..c1e74f73
--- /dev/null
+++ b/packages/core/src/security/is-email-valid.test.ts
@@ -0,0 +1,70 @@
+import { assert } from "chai";
+import { isEmailValid } from "./is-email-valid.js";
+
+describe("isEmailValid", () => {
+ it("should return false for undefined value", () => {
+ assert.equal(isEmailValid(undefined), false);
+ });
+
+ it("should return false for empty string", () => {
+ assert.equal(isEmailValid(""), false);
+ });
+
+ it("should return false if no @ is present", () => {
+ assert.equal(isEmailValid("test"), false);
+ });
+
+ it("should return false if no domain is present", () => {
+ assert.equal(isEmailValid("test@"), false);
+ });
+
+ it("should return false if two @ are present", () => {
+ assert.equal(isEmailValid("test@test@test"), false);
+ });
+
+ it("should return false if domains contain other than letters, numbers, hyphens (-) and periods (.)", () => {
+ assert.equal(isEmailValid("test@test_test"), false);
+ });
+
+ it("should return false if tld has the wrong case", () => {
+ assert.equal(isEmailValid("jean@wanadoo.Fr"), false);
+ });
+
+ it("should return false if local part is longer than 63 characters", () => {
+ assert.equal(
+ isEmailValid(
+ "1234567890123456789012345678901234567890123456789012345678901234@test",
+ ),
+ false,
+ );
+ });
+
+ it("should return false if total length is longer than 254 characters", () => {
+ assert.equal(
+ isEmailValid(
+ "test@1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890",
+ ),
+ false,
+ );
+ });
+
+ // this test cases have been taken from
+ // https://stackoverflow.com/questions/46155/how-to-validate-an-email-address-in-javascript/32686261#32686261
+ const validEmailAddresses = [
+ "prettyandsimple@example.com",
+ "very.common@example.com",
+ "disposable.style.email.with+symbol@example.com",
+ "other.email-with-dash@example.com",
+ "#!$%&'*+-/=?^_`{}|~@example.org",
+ '"()[]:,;\\"!#$%&\'*+-/=?^_`{}| ~.a"@example.org',
+ '" "@example.org', // space between the quotes
+ "üñîçøðé@example.com", // Unicode characters in local part
+ "Pelé@example.com", // Latin
+ ];
+
+ validEmailAddresses.forEach((validEmailAddress) => {
+ it("should return true for valid email address", () => {
+ assert.equal(isEmailValid(validEmailAddress), true);
+ });
+ });
+});
diff --git a/packages/core/src/security/is-email-valid.ts b/packages/core/src/security/is-email-valid.ts
new file mode 100644
index 00000000..c09e4ef5
--- /dev/null
+++ b/packages/core/src/security/is-email-valid.ts
@@ -0,0 +1,44 @@
+//
+
+import { isEmpty, isString } from "lodash-es";
+import { Buffer } from "node:buffer";
+import { isDomainValid } from "./is-domain-valid.js";
+
+//
+
+export function isEmailValid(email: unknown): email is string {
+ if (!isString(email) || isEmpty(email)) {
+ return false;
+ }
+
+ const parts = email.split("@").filter((part) => part);
+
+ // The email address contains two parts, separated with an @ symbol.
+ // => these parts are non-empty strings
+ // => there are two and only two parts
+ if (parts.length !== 2) {
+ return false;
+ }
+
+ // The email address does not contain dangerous characters
+ // => the postgres connector is taking care of this
+
+ // The domain part contains only letters, numbers, hyphens (-) and periods (.)
+ const domain = parts[1];
+ if (!isDomainValid(domain)) {
+ return false;
+ }
+
+ // The local part (before the @) should be no more than 63 characters.
+ const localPart = parts[0];
+ if (Buffer.from(localPart).length > 63) {
+ return false;
+ }
+
+ // The total length should be no more than 254 characters.
+ if (Buffer.from(email).length > 254) {
+ return false;
+ }
+
+ return true;
+}
diff --git a/packages/core/src/security/is-name-valid.test.ts b/packages/core/src/security/is-name-valid.test.ts
new file mode 100644
index 00000000..3a9fef27
--- /dev/null
+++ b/packages/core/src/security/is-name-valid.test.ts
@@ -0,0 +1,61 @@
+//
+
+import { assert } from "chai";
+import { describe, it } from "mocha";
+import { isNameValid } from "./is-name-valid.js";
+
+//
+
+describe("isNameValid", () => {
+ const invalidNames = [
+ "jean@domaine.fr",
+ "dsi_etudes_applications",
+ "R2 - Sebastien",
+ "0000",
+ "CCTV70",
+ "0623456789",
+ ";GOUZE",
+ "Agathe/Carine",
+ ``,
+ "SG/PAFF/DDTM06",
+ "Jean*Robert",
+ "Jose_luis",
+ "MME.",
+ "Sabrina.b",
+ "M.Christine",
+ "Bousbecque59098*",
+ "vAL2RIE",
+ "Ch.",
+ "YOANNI TH.",
+ "M. le Président",
+ ];
+
+ invalidNames.forEach((invalidName) => {
+ it(`should return false for invalid names: ${invalidName}`, () => {
+ assert.equal(isNameValid(invalidName), false);
+ });
+ });
+
+ const validNames = [
+ "Jean",
+ "Jean-Jean",
+ "TAREK WAJDI",
+ " Tania",
+ "Надежда",
+ "沃德天·",
+ "อาทิตย์ นาถมทอง",
+ "俊宇",
+ "Doğan",
+ "Hanåğğne",
+ "سليمان خالد",
+ "marcn bh",
+ "THỊ PHƯƠNG HỒNG",
+ "Yamina⁵",
+ ];
+
+ validNames.forEach((validName) => {
+ it(`should return true for valid names: ${validName}`, () => {
+ assert.equal(isNameValid(validName), true);
+ });
+ });
+});
diff --git a/packages/core/src/security/is-name-valid.ts b/packages/core/src/security/is-name-valid.ts
new file mode 100644
index 00000000..09a61077
--- /dev/null
+++ b/packages/core/src/security/is-name-valid.ts
@@ -0,0 +1,5 @@
+//
+
+export function isNameValid(name: string) {
+ return !!name.match(/^[^$&+:;=?@#|<>.^*()%!\d_\[\]{}\\\/"`~]*$/);
+}
diff --git a/packages/core/src/security/is-phone-number-valid.test.ts b/packages/core/src/security/is-phone-number-valid.test.ts
new file mode 100644
index 00000000..4e7f2bc0
--- /dev/null
+++ b/packages/core/src/security/is-phone-number-valid.test.ts
@@ -0,0 +1,44 @@
+//
+
+import { assert } from "chai";
+import { describe, it } from "mocha";
+import { isPhoneNumberValid } from "./is-phone-number-valid.js";
+
+//
+
+describe("isPhoneNumberValid", () => {
+ [
+ undefined,
+ null,
+ 0,
+ true,
+ "📞",
+ "FR",
+ "Jean Michel",
+ "$",
+ "&",
+ "(",
+ ")",
+ "+33210",
+ ].forEach((name) => {
+ it(`should return false for "${name}"`, () => {
+ assert.equal(isPhoneNumberValid(name), false);
+ });
+ });
+
+ it("should return true for '0123456789'", () => {
+ assert.equal(isPhoneNumberValid("0123456789"), true);
+ });
+
+ it("should return true for '0-1-2-3-4-5-6-7-8-9'", () => {
+ assert.equal(isPhoneNumberValid("0-1-2-3-4-5-6-7-8-9"), true);
+ });
+
+ it("should return true for '+00123456'", () => {
+ assert.equal(isPhoneNumberValid("+00123456"), true);
+ });
+
+ it("should return true for '+33123456789'", () => {
+ assert.equal(isPhoneNumberValid("+33123456789"), true);
+ });
+});
diff --git a/packages/core/src/security/is-phone-number-valid.ts b/packages/core/src/security/is-phone-number-valid.ts
new file mode 100644
index 00000000..e7532f26
--- /dev/null
+++ b/packages/core/src/security/is-phone-number-valid.ts
@@ -0,0 +1,19 @@
+//
+
+import { isEmpty, isString } from "lodash-es";
+
+//
+
+export function isPhoneNumberValid(
+ phoneNumber: unknown,
+): phoneNumber is string {
+ if (!isString(phoneNumber) || isEmpty(phoneNumber)) {
+ return false;
+ }
+
+ if (!phoneNumber.match(/^\+?(?:[0-9][ -]?){6,14}[0-9]$/)) {
+ return false;
+ }
+
+ return true;
+}
diff --git a/packages/core/src/security/is-siret-valid.test.ts b/packages/core/src/security/is-siret-valid.test.ts
new file mode 100644
index 00000000..2aa9b48b
--- /dev/null
+++ b/packages/core/src/security/is-siret-valid.test.ts
@@ -0,0 +1,36 @@
+//
+
+import { assert } from "chai";
+import { describe, it } from "mocha";
+import { isSiretValid } from "./is-siret-valid.js";
+
+//
+
+describe("isSiretValid", () => {
+ it("should return false for undefined value", () => {
+ assert.equal(isSiretValid(undefined), false);
+ });
+
+ it("should return false for empty string", () => {
+ assert.equal(isSiretValid(""), false);
+ });
+
+ it("should return false if it contains characters other than number", () => {
+ assert.equal(isSiretValid("a2345678901234"), false);
+ });
+ it("should return false if it contains more that 14 numbers", () => {
+ assert.equal(isSiretValid("123456789012345"), false);
+ });
+
+ it("should return false if it contains less that 14 numbers", () => {
+ assert.equal(isSiretValid("1234567890123"), false);
+ });
+
+ it("should return true if it contains exactly 14 numbers", () => {
+ assert.equal(isSiretValid("12345678901234"), true);
+ });
+
+ it("should return true if it contains exactly 14 numbers with spaces", () => {
+ assert.equal(isSiretValid(" 123 456 789\n\r01234 \n"), true);
+ });
+});
diff --git a/packages/core/src/security/is-siret-valid.ts b/packages/core/src/security/is-siret-valid.ts
new file mode 100644
index 00000000..106cbf97
--- /dev/null
+++ b/packages/core/src/security/is-siret-valid.ts
@@ -0,0 +1,15 @@
+//
+
+import { isEmpty, isString } from "lodash-es";
+
+//
+
+export function isSiretValid(siret: unknown): siret is string {
+ if (!isString(siret) || isEmpty(siret)) {
+ return false;
+ }
+
+ const siretNoSpaces = siret.replace(/\s/g, "");
+
+ return /^\d{14}$/.test(siretNoSpaces);
+}
diff --git a/packages/core/src/services/email/index.ts b/packages/core/src/services/email/index.ts
new file mode 100644
index 00000000..da7061c2
--- /dev/null
+++ b/packages/core/src/services/email/index.ts
@@ -0,0 +1,3 @@
+//
+
+export * from "./isAFreeDomain.js";
diff --git a/packages/core/src/services/suggestion/index.ts b/packages/core/src/services/suggestion/index.ts
new file mode 100644
index 00000000..1352d188
--- /dev/null
+++ b/packages/core/src/services/suggestion/index.ts
@@ -0,0 +1,3 @@
+//
+
+export * from "./did-you-mean.js";
diff --git a/packages/core/tsconfig.json b/packages/core/tsconfig.json
index 1c2a9acc..23b7c277 100644
--- a/packages/core/tsconfig.json
+++ b/packages/core/tsconfig.json
@@ -5,7 +5,7 @@
"declarationMap": true,
"outDir": "./dist",
"rootDir": "src",
- "types": ["./types"],
+ "types": ["node", "./types"],
"module": "NodeNext",
"moduleResolution": "nodenext",
"verbatimModuleSyntax": true,
diff --git a/packages/core/tsconfig.lib.json b/packages/core/tsconfig.lib.json
index c3d239e6..3ba35441 100644
--- a/packages/core/tsconfig.lib.json
+++ b/packages/core/tsconfig.lib.json
@@ -1,16 +1,9 @@
{
"compilerOptions": {
"outDir": "./dist",
- "rootDir": "./src",
- "types": [
- "./types"
- ]
+ "rootDir": "./src"
},
- "exclude": [
- "src/**/*.test.ts"
- ],
+ "exclude": ["src/**/*.test.ts"],
"extends": "./tsconfig.json",
- "include": [
- "src"
- ]
+ "include": ["src"]
}
diff --git a/packages/core/types/index.d.ts b/packages/core/types/index.d.ts
index 644b727e..a8c6994f 100644
--- a/packages/core/types/index.d.ts
+++ b/packages/core/types/index.d.ts
@@ -1,5 +1,4 @@
//
-declare module "is-disposable-email-domain" {
- function isFree(email: string): boolean;
-}
+///
+///
diff --git a/packages/core/types/is-disposable-email-domain.d.ts b/packages/core/types/is-disposable-email-domain.d.ts
new file mode 100644
index 00000000..644b727e
--- /dev/null
+++ b/packages/core/types/is-disposable-email-domain.d.ts
@@ -0,0 +1,5 @@
+//
+
+declare module "is-disposable-email-domain" {
+ function isFree(email: string): boolean;
+}
diff --git a/packages/core/types/tld-extract.d.ts b/packages/core/types/tld-extract.d.ts
new file mode 100644
index 00000000..0211b457
--- /dev/null
+++ b/packages/core/types/tld-extract.d.ts
@@ -0,0 +1,5 @@
+//
+
+declare module "tld-extract" {
+ function parse_host(domain: string, { allowDotlessTLD: boolean }): boolean;
+}
diff --git a/scripts/import-accounts-coop.ts b/scripts/import-accounts-coop.ts
index 0bbd9419..9ae3f438 100644
--- a/scripts/import-accounts-coop.ts
+++ b/scripts/import-accounts-coop.ts
@@ -1,4 +1,10 @@
// src https://stackoverflow.com/questions/40994095/pipe-streams-to-edit-csv-file-in-node-js
+import {
+ isEmailValid,
+ isNameValid,
+ isPhoneNumberValid,
+ isSiretValid,
+} from "@gouvfr-lasuite/proconnect.core/security";
import { AxiosError } from "axios";
import { parse, stringify, transform } from "csv";
import fs from "fs";
@@ -22,12 +28,6 @@ import {
startDurationMesure,
throttleApiCall,
} from "../src/services/script-helpers";
-import {
- isEmailValid,
- isNameValid,
- isPhoneNumberValid,
- isSiretValid,
-} from "../src/services/security";
const { INPUT_FILE, OUTPUT_FILE } = z
.object({
diff --git a/scripts/import-accounts.ts b/scripts/import-accounts.ts
index 12789604..bf50e97f 100644
--- a/scripts/import-accounts.ts
+++ b/scripts/import-accounts.ts
@@ -1,4 +1,9 @@
// src https://stackoverflow.com/questions/40994095/pipe-streams-to-edit-csv-file-in-node-js
+import {
+ isEmailValid,
+ isNameValid,
+ isSiretValid,
+} from "@gouvfr-lasuite/proconnect.core/security";
import { AxiosError } from "axios";
import { parse, stringify, transform } from "csv";
import fs from "fs";
@@ -22,11 +27,6 @@ import {
startDurationMesure,
throttleApiCall,
} from "../src/services/script-helpers";
-import {
- isEmailValid,
- isNameValid,
- isSiretValid,
-} from "../src/services/security";
const { INPUT_FILE, OUTPUT_FILE } = z
.object({
diff --git a/scripts/import-domains.ts b/scripts/import-domains.ts
index 19560844..e967b79f 100644
--- a/scripts/import-domains.ts
+++ b/scripts/import-domains.ts
@@ -1,4 +1,8 @@
// src https://stackoverflow.com/questions/40994095/pipe-streams-to-edit-csv-file-in-node-js
+import {
+ isDomainValid,
+ isSiretValid,
+} from "@gouvfr-lasuite/proconnect.core/security";
import { AxiosError } from "axios";
import { parse, stringify, transform } from "csv";
import fs from "fs";
@@ -23,7 +27,6 @@ import {
startDurationMesure,
throttleApiCall,
} from "../src/services/script-helpers";
-import { isDomainValid, isSiretValid } from "../src/services/security";
const { INPUT_FILE, OUTPUT_FILE } = z
.object({
diff --git a/src/connectors/api-annuaire-education-nationale.ts b/src/connectors/api-annuaire-education-nationale.ts
index e66373bb..9f026750 100644
--- a/src/connectors/api-annuaire-education-nationale.ts
+++ b/src/connectors/api-annuaire-education-nationale.ts
@@ -1,3 +1,4 @@
+import { isEmailValid } from "@gouvfr-lasuite/proconnect.core/security";
import axios, { AxiosError, type AxiosResponse } from "axios";
import { isEmpty, isString } from "lodash-es";
import {
@@ -11,7 +12,6 @@ import {
ApiAnnuaireNotFoundError,
} from "../config/errors";
import { logger } from "../services/log";
-import { isEmailValid } from "../services/security";
type ApiAnnuaireEducationNationaleReponse = {
total_count: number;
diff --git a/src/connectors/api-annuaire-service-public.ts b/src/connectors/api-annuaire-service-public.ts
index e9812df0..d5ac87a8 100644
--- a/src/connectors/api-annuaire-service-public.ts
+++ b/src/connectors/api-annuaire-service-public.ts
@@ -1,3 +1,4 @@
+import { isEmailValid } from "@gouvfr-lasuite/proconnect.core/security";
import axios, { AxiosError, type AxiosResponse } from "axios";
import { isEmpty, isString } from "lodash-es";
import {
@@ -12,7 +13,6 @@ import {
ApiAnnuaireTooManyResultsError,
} from "../config/errors";
import { logger } from "../services/log";
-import { isEmailValid } from "../services/security";
// more info at https://api-lannuaire.service-public.fr/api/explore/v2.1/console
diff --git a/src/managers/organization/join.ts b/src/managers/organization/join.ts
index 322a45db..1e5adfa7 100644
--- a/src/managers/organization/join.ts
+++ b/src/managers/organization/join.ts
@@ -1,3 +1,4 @@
+import { isEmailValid } from "@gouvfr-lasuite/proconnect.core/security";
import { Welcome } from "@gouvfr-lasuite/proconnect.email";
import * as Sentry from "@sentry/node";
import { isEmpty, some } from "lodash-es";
@@ -53,7 +54,6 @@ import {
isEtablissementScolaireDuPremierEtSecondDegre,
isSmallAssociation,
} from "../../services/organization";
-import { isEmailValid } from "../../services/security";
import { unableToAutoJoinOrganizationMd } from "../../views/mails/unable-to-auto-join-organization";
import { getOrganizationsByUserId, markDomainAsVerified } from "./main";
diff --git a/src/managers/user.ts b/src/managers/user.ts
index b6bb4c0e..46ad07f7 100644
--- a/src/managers/user.ts
+++ b/src/managers/user.ts
@@ -1,3 +1,4 @@
+import { getDidYouMeanSuggestion } from "@gouvfr-lasuite/proconnect.core/services/suggestion";
import {
Add2fa,
AddAccessKey,
@@ -12,6 +13,13 @@ import {
VerifyEmail,
} from "@gouvfr-lasuite/proconnect.email";
import { isEmpty } from "lodash-es";
+import {
+ MAGIC_LINK_TOKEN_EXPIRATION_DURATION_IN_MINUTES,
+ MAX_DURATION_BETWEEN_TWO_EMAIL_ADDRESS_VERIFICATION_IN_MINUTES,
+ MONCOMPTEPRO_HOST,
+ RESET_PASSWORD_TOKEN_EXPIRATION_DURATION_IN_MINUTES,
+ VERIFY_EMAIL_TOKEN_EXPIRATION_DURATION_IN_MINUTES,
+} from "../config/env";
import {
EmailUnavailableError,
InvalidCredentialsError,
@@ -26,15 +34,6 @@ import {
} from "../config/errors";
import { isEmailSafeToSendTransactional } from "../connectors/debounce";
import { sendMail } from "../connectors/mail";
-
-import { getDidYouMeanSuggestion } from "@gouvfr-lasuite/proconnect.core/services/suggestion/did-you-mean.js";
-import {
- MAGIC_LINK_TOKEN_EXPIRATION_DURATION_IN_MINUTES,
- MAX_DURATION_BETWEEN_TWO_EMAIL_ADDRESS_VERIFICATION_IN_MINUTES,
- MONCOMPTEPRO_HOST,
- RESET_PASSWORD_TOKEN_EXPIRATION_DURATION_IN_MINUTES,
- VERIFY_EMAIL_TOKEN_EXPIRATION_DURATION_IN_MINUTES,
-} from "../config/env";
import { hasPasswordBeenPwned } from "../connectors/pwnedpasswords";
import {
create,
diff --git a/src/services/custom-zod-schemas.ts b/src/services/custom-zod-schemas.ts
index 0300bb86..4fc4f3fc 100644
--- a/src/services/custom-zod-schemas.ts
+++ b/src/services/custom-zod-schemas.ts
@@ -1,13 +1,12 @@
-import { z } from "zod";
-import { normalizeOfficialContactEmailVerificationToken } from "./normalize-official-contact-email-verification-token";
import {
isEmailValid,
isNameValid,
- isNotificationLabelValid,
isPhoneNumberValid,
isSiretValid,
- isVisibleString,
-} from "./security";
+} from "@gouvfr-lasuite/proconnect.core/security";
+import { z } from "zod";
+import { normalizeOfficialContactEmailVerificationToken } from "./normalize-official-contact-email-verification-token";
+import { isNotificationLabelValid, isVisibleString } from "./security";
export const siretSchema = () =>
z
diff --git a/src/services/email.ts b/src/services/email.ts
index dfd01b9e..14093989 100644
--- a/src/services/email.ts
+++ b/src/services/email.ts
@@ -1,6 +1,6 @@
//
-import { isAFreeDomain } from "@gouvfr-lasuite/proconnect.core/services/email/isAFreeDomain.js";
+import { isAFreeDomain } from "@gouvfr-lasuite/proconnect.core/services/email";
import { parse_host } from "tld-extract";
import {
FEATURE_CONSIDER_ALL_EMAIL_DOMAINS_AS_FREE,
diff --git a/src/services/organization.ts b/src/services/organization.ts
index ded90c16..668ecacb 100644
--- a/src/services/organization.ts
+++ b/src/services/organization.ts
@@ -1,4 +1,4 @@
-import { isDomainValid } from "./security";
+import { isDomainValid } from "@gouvfr-lasuite/proconnect.core/security";
/**
* These fonctions return approximate results. As the data tranche effectifs is
diff --git a/src/services/security.ts b/src/services/security.ts
index da147904..f87c7bf5 100644
--- a/src/services/security.ts
+++ b/src/services/security.ts
@@ -1,7 +1,6 @@
import bcrypt from "bcryptjs";
import { hasIn, isEmpty, isString } from "lodash-es";
import { customAlphabet, nanoid } from "nanoid/async";
-import { parse_host } from "tld-extract";
import { MONCOMPTEPRO_HOST } from "../config/env";
import notificationMessages from "../config/notification-messages";
import dicewareWordlistFrAlt from "../data/diceware-wordlist-fr-alt";
@@ -52,88 +51,12 @@ export const isPasswordSecure = (plainPassword: string, email: string) => {
return !containsBlacklistedWord && strong;
};
-/*
- * specifications of these functions can be found at
- * https://cheatsheetseries.owasp.org/cheatsheets/Input_Validation_Cheat_Sheet.html#email-address-validation
- */
-export const isDomainValid = (domain: unknown): domain is string => {
- if (!isString(domain) || isEmpty(domain)) {
- return false;
- }
-
- if (domain.match(/^[a-zA-Z0-9.-]*$/) === null) {
- return false;
- }
-
- try {
- parse_host(domain, { allowDotlessTLD: true });
- } catch (error) {
- return false;
- }
-
- return true;
-};
-export const isEmailValid = (email: unknown): email is string => {
- if (!isString(email) || isEmpty(email)) {
- return false;
- }
-
- const parts = email.split("@").filter((part) => part);
-
- // The email address contains two parts, separated with an @ symbol.
- // => these parts are non-empty strings
- // => there are two and only two parts
- if (parts.length !== 2) {
- return false;
- }
-
- // The email address does not contain dangerous characters
- // => the postgres connector is taking care of this
-
- // The domain part contains only letters, numbers, hyphens (-) and periods (.)
- const domain = parts[1];
- if (!isDomainValid(domain)) {
- return false;
- }
-
- // The local part (before the @) should be no more than 63 characters.
- const localPart = parts[0];
- if (Buffer.from(localPart).length > 63) {
- return false;
- }
-
- // The total length should be no more than 254 characters.
- if (Buffer.from(email).length > 254) {
- return false;
- }
-
- return true;
-};
-
-export const isPhoneNumberValid = (
- phoneNumber: unknown,
-): phoneNumber is string => {
- if (!isString(phoneNumber) || isEmpty(phoneNumber)) {
- return false;
- }
-
- if (!phoneNumber.match(/^\+?(?:[0-9][ -]?){6,14}[0-9]$/)) {
- return false;
- }
-
- return true;
-};
-
export const isVisibleString = (input: string) => {
const visibleCharRegex = /[^\s\p{Cf}\p{Cc}\p{Zl}\p{Zp}]/u;
return visibleCharRegex.test(input);
};
-export const isNameValid = (name: string) => {
- return !!name.match(/^[^$&+:;=?@#|<>.^*()%!\d_\[\]{}\\\/"`~]*$/);
-};
-
const nanoidPin = customAlphabet("0123456789", 10);
export const generatePinToken = async () => {
@@ -155,16 +78,6 @@ export const generateDicewarePassword = async () => {
return `${dicewareWordlistFrAlt[firstFiveDices]}-${dicewareWordlistFrAlt[secondFiveDices]}`;
};
-export const isSiretValid = (siret: unknown): siret is string => {
- if (!isString(siret) || isEmpty(siret)) {
- return false;
- }
-
- const siretNoSpaces = siret.replace(/\s/g, "");
-
- return /^\d{14}$/.test(siretNoSpaces);
-};
-
export const getTrustedReferrerPath = (referrer: unknown): string | null => {
if (!isString(referrer) || isEmpty(referrer)) {
return null;
diff --git a/src/types/is-disposable-email-domain.d.ts b/src/types/is-disposable-email-domain.d.ts
deleted file mode 100644
index 1b3715e5..00000000
--- a/src/types/is-disposable-email-domain.d.ts
+++ /dev/null
@@ -1 +0,0 @@
-declare module "is-disposable-email-domain";
diff --git a/test/security.test.ts b/test/security.test.ts
index 94324c54..be7bf02e 100644
--- a/test/security.test.ts
+++ b/test/security.test.ts
@@ -2,110 +2,10 @@ import { assert } from "chai";
import { MONCOMPTEPRO_HOST } from "../src/config/env";
import {
getTrustedReferrerPath,
- isEmailValid,
- isNameValid,
isPasswordSecure,
- isSiretValid,
isVisibleString,
} from "../src/services/security";
-describe("isEmailValid", () => {
- it("should return false for undefined value", () => {
- assert.equal(isEmailValid(undefined), false);
- });
-
- it("should return false for empty string", () => {
- assert.equal(isEmailValid(""), false);
- });
-
- it("should return false if no @ is present", () => {
- assert.equal(isEmailValid("test"), false);
- });
-
- it("should return false if no domain is present", () => {
- assert.equal(isEmailValid("test@"), false);
- });
-
- it("should return false if two @ are present", () => {
- assert.equal(isEmailValid("test@test@test"), false);
- });
-
- it("should return false if domains contain other than letters, numbers, hyphens (-) and periods (.)", () => {
- assert.equal(isEmailValid("test@test_test"), false);
- });
-
- it("should return false if tld has the wrong case", () => {
- assert.equal(isEmailValid("jean@wanadoo.Fr"), false);
- });
-
- it("should return false if local part is longer than 63 characters", () => {
- assert.equal(
- isEmailValid(
- "1234567890123456789012345678901234567890123456789012345678901234@test",
- ),
- false,
- );
- });
-
- it("should return false if total length is longer than 254 characters", () => {
- assert.equal(
- isEmailValid(
- "test@1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890",
- ),
- false,
- );
- });
-
- // this test cases have been taken from
- // https://stackoverflow.com/questions/46155/how-to-validate-an-email-address-in-javascript/32686261#32686261
- const validEmailAddresses = [
- "prettyandsimple@example.com",
- "very.common@example.com",
- "disposable.style.email.with+symbol@example.com",
- "other.email-with-dash@example.com",
- "#!$%&'*+-/=?^_`{}|~@example.org",
- '"()[]:,;\\"!#$%&\'*+-/=?^_`{}| ~.a"@example.org',
- '" "@example.org', // space between the quotes
- "üñîçøðé@example.com", // Unicode characters in local part
- "Pelé@example.com", // Latin
- ];
-
- validEmailAddresses.forEach((validEmailAddress) => {
- it("should return true for valid email address", () => {
- assert.equal(isEmailValid(validEmailAddress), true);
- });
- });
-});
-
-describe("isSiretValid", () => {
- it("should return false for undefined value", () => {
- assert.equal(isSiretValid(undefined), false);
- });
-
- it("should return false for empty string", () => {
- assert.equal(isSiretValid(""), false);
- });
-
- it("should return false if it contains characters other than number", () => {
- assert.equal(isSiretValid("a2345678901234"), false);
- });
- it("should return false if it contains more that 14 numbers", () => {
- assert.equal(isSiretValid("123456789012345"), false);
- });
-
- it("should return false if it contains less that 14 numbers", () => {
- assert.equal(isSiretValid("1234567890123"), false);
- });
-
- it("should return true if it contains exactly 14 numbers", () => {
- assert.equal(isSiretValid("12345678901234"), true);
- });
-
- it("should return true if it contains exactly 14 numbers with spaces", () => {
- assert.equal(isSiretValid(" 123 456 789\n\r01234 \n"), true);
- });
-});
-
describe("isVisibleString", () => {
const nonVisibleStrings = [
"",
@@ -131,60 +31,6 @@ describe("isVisibleString", () => {
});
});
-describe("isNameValid", () => {
- const invalidNames = [
- "jean@domaine.fr",
- "dsi_etudes_applications",
- "R2 - Sebastien",
- "0000",
- "CCTV70",
- "0623456789",
- ";GOUZE",
- "Agathe/Carine",
- ``,
- "SG/PAFF/DDTM06",
- "Jean*Robert",
- "Jose_luis",
- "MME.",
- "Sabrina.b",
- "M.Christine",
- "Bousbecque59098*",
- "vAL2RIE",
- "Ch.",
- "YOANNI TH.",
- "M. le Président",
- ];
-
- invalidNames.forEach((invalidName) => {
- it(`should return false for invalid names: ${invalidName}`, () => {
- assert.equal(isNameValid(invalidName), false);
- });
- });
-
- const validNames = [
- "Jean",
- "Jean-Jean",
- "TAREK WAJDI",
- " Tania",
- "Надежда",
- "沃德天·",
- "อาทิตย์ นาถมทอง",
- "俊宇",
- "Doğan",
- "Hanåğğne",
- "سليمان خالد",
- "marcn bh",
- "THỊ PHƯƠNG HỒNG",
- "Yamina⁵",
- ];
-
- validNames.forEach((validName) => {
- it(`should return true for valid names: ${validName}`, () => {
- assert.equal(isNameValid(validName), true);
- });
- });
-});
-
describe("isUrlTrusted", () => {
it("should not trust null url", () => {
assert.equal(getTrustedReferrerPath(null), null);