diff --git a/package-lock.json b/package-lock.json index 9f0cbc88b7ecfd26ebbbdc8a058424f6fdf6242c..10a74150a4155aacf85938351a2b321ec7cb22b0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,9 +4,7 @@ "requires": true, "packages": { "": { - "dependencies": { - "dompurify": "^3.1.0" - }, + "name": "adorsaz.ch", "devDependencies": { "@eslint/eslintrc": "^3.1.0", "@eslint/js": "^9.10.0", @@ -275,21 +273,21 @@ } }, "node_modules/@eslint-community/regexpp": { - "version": "4.11.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.0.tgz", - "integrity": "sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==", + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", "dev": true, "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, "node_modules/@eslint/config-array": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.18.0.tgz", - "integrity": "sha512-fTxvnS1sRMu3+JjXwJG0j/i4RT9u4qJ+lqS/yCGap4lH4zZGzQ7tu+xZqQmcMZq5OBZDL4QRxQzRjkWcGt8IVw==", + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.19.2.tgz", + "integrity": "sha512-GNKqxfHG2ySmJOBSHg7LxeUx4xpuCoFjacmlCoYWEbaPXLwvfIjixRI12xCQZeULksQb23uiA8F40w5TojpV7w==", "dev": true, "dependencies": { - "@eslint/object-schema": "^2.1.4", + "@eslint/object-schema": "^2.1.6", "debug": "^4.3.1", "minimatch": "^3.1.2" }, @@ -297,10 +295,31 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, + "node_modules/@eslint/config-helpers": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.2.1.tgz", + "integrity": "sha512-RI17tsD2frtDu/3dmI7QRrD4bedNKPM08ziRYaC5AhkGrzIAJelm9kJU1TznK+apx6V+cqRz8tfpEeG3oIyjxw==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.12.0.tgz", + "integrity": "sha512-cmrR6pytBuSMTaBweKoGMwu3EiHiEC+DoyupPmlZ0HxBJBtIxwe+j/E4XPIKNx+Q74c8lXKPwYawBf5glsTkHg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, "node_modules/@eslint/eslintrc": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz", - "integrity": "sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", + "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", "dev": true, "dependencies": { "ajv": "^6.12.4", @@ -333,35 +352,83 @@ } }, "node_modules/@eslint/js": { - "version": "9.10.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.10.0.tgz", - "integrity": "sha512-fuXtbiP5GWIn8Fz+LWoOMVf/Jxm+aajZYkhi6CuEm4SxymFM+eUWzbO9qXT+L0iCkL5+KGYMCSGxo686H19S1g==", + "version": "9.23.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.23.0.tgz", + "integrity": "sha512-35MJ8vCPU0ZMxo7zfev2pypqTwWTofFZO6m4KAtdoFhRpLJUpHTZZ+KB3C7Hb1d7bULYwO4lJXGCi5Se+8OMbw==", "dev": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, "node_modules/@eslint/object-schema": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.4.tgz", - "integrity": "sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==", + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz", + "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", "dev": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, "node_modules/@eslint/plugin-kit": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.1.0.tgz", - "integrity": "sha512-autAXT203ixhqei9xt+qkYOvY8l6LAFIdT2UXc/RPNeUVfqRF1BV94GTJyVPFKT8nFM6MyVJhjLj9E8JWvf5zQ==", + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.8.tgz", + "integrity": "sha512-ZAoA40rNMPwSm+AeHpCq8STiNAwzWLJuP8Xv4CHIc9wv/PSuExjMrmjfYNj682vW0OOiZ1HKxzvjQr9XZIisQA==", "dev": true, "dependencies": { + "@eslint/core": "^0.13.0", "levn": "^0.4.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, + "node_modules/@eslint/plugin-kit/node_modules/@eslint/core": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.13.0.tgz", + "integrity": "sha512-yfkgDw1KR66rkT5A8ci4irzDysN7FRpq3ttJolR88OqQikAWqwA8j5VZyas+vjyBNFIJ7MfybJ9plMILI2UrCw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.6", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", + "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", + "dev": true, + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.3.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", + "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", + "dev": true, + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, "node_modules/@humanwhocodes/gitignore-to-minimatch": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@humanwhocodes/gitignore-to-minimatch/-/gitignore-to-minimatch-1.0.2.tgz", @@ -386,9 +453,9 @@ } }, "node_modules/@humanwhocodes/retry": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.0.tgz", - "integrity": "sha512-d2CGZR2o7fS6sWB7DG/3a95bGKQyHMACZ5aW8qGkkqQpUoZV6C0X7Pc7l4ZNMZkfNBf4VWNe9E1jRsf0G146Ew==", + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.2.tgz", + "integrity": "sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==", "dev": true, "engines": { "node": ">=18.18" @@ -742,9 +809,9 @@ } }, "node_modules/@types/estree": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", - "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz", + "integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==", "dev": true }, "node_modules/@types/istanbul-lib-coverage": { @@ -1023,9 +1090,9 @@ } }, "node_modules/acorn": { - "version": "8.12.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", - "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", + "version": "8.14.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz", + "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -1591,9 +1658,9 @@ } }, "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, "dependencies": { "path-key": "^3.1.0", @@ -1909,11 +1976,6 @@ "url": "https://github.com/fb55/domhandler?sponsor=1" } }, - "node_modules/dompurify": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.1.6.tgz", - "integrity": "sha512-cTOAhc36AalkjtBpfG6O8JimdTMWNXjiePT2xQH/ppBGi/4uIpmj8eKyIkMJErXWARyINV/sB38yf8JCLF5pbQ==" - }, "node_modules/domutils": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", @@ -2163,28 +2225,32 @@ } }, "node_modules/eslint": { - "version": "9.10.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.10.0.tgz", - "integrity": "sha512-Y4D0IgtBZfOcOUAIQTSXBKoNGfY0REGqHJG6+Q81vNippW5YlKjHFj4soMxamKK1NXHUWuBZTLdU3Km+L/pcHw==", + "version": "9.23.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.23.0.tgz", + "integrity": "sha512-jV7AbNoFPAY1EkFYpLq5bslU9NLNO8xnEeQXwErNibVryjk67wHVmddTBilc5srIttJDBrB0eMHKZBFbSIABCw==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.11.0", - "@eslint/config-array": "^0.18.0", - "@eslint/eslintrc": "^3.1.0", - "@eslint/js": "9.10.0", - "@eslint/plugin-kit": "^0.1.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.19.2", + "@eslint/config-helpers": "^0.2.0", + "@eslint/core": "^0.12.0", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.23.0", + "@eslint/plugin-kit": "^0.2.7", + "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.3.0", - "@nodelib/fs.walk": "^1.2.8", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", + "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^8.0.2", - "eslint-visitor-keys": "^4.0.0", - "espree": "^10.1.0", + "eslint-scope": "^8.3.0", + "eslint-visitor-keys": "^4.2.0", + "espree": "^10.3.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", @@ -2194,14 +2260,11 @@ "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", "json-stable-stringify-without-jsonify": "^1.0.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" + "optionator": "^0.9.3" }, "bin": { "eslint": "bin/eslint.js" @@ -2501,9 +2564,9 @@ } }, "node_modules/eslint-scope": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.0.2.tgz", - "integrity": "sha512-6E4xmrTw5wtxnLA5wYL3WDfhZ/1bUBGOXV0zQvVRDOtrR8D0p6W7fs3JweNYhwRYeGvd/1CKX2se0/2s7Q/nJA==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.3.0.tgz", + "integrity": "sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==", "dev": true, "dependencies": { "esrecurse": "^4.3.0", @@ -2529,9 +2592,9 @@ } }, "node_modules/eslint/node_modules/eslint-visitor-keys": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", - "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", "dev": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2541,14 +2604,14 @@ } }, "node_modules/espree": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.1.0.tgz", - "integrity": "sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==", + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", + "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", "dev": true, "dependencies": { - "acorn": "^8.12.0", + "acorn": "^8.14.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.0.0" + "eslint-visitor-keys": "^4.2.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2558,9 +2621,9 @@ } }, "node_modules/espree/node_modules/eslint-visitor-keys": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", - "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", "dev": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3624,15 +3687,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/is-plain-obj": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", @@ -4427,9 +4481,9 @@ } }, "node_modules/nanoid": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", - "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", "dev": true, "funding": [ { @@ -5976,12 +6030,6 @@ "node": ">= 16" } }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true - }, "node_modules/theredoc": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/theredoc/-/theredoc-1.0.0.tgz", diff --git a/package.json b/package.json index 6c9bfba6e75089c199495dd8c5f76360634374fa..189f0f07486b5973db666fc3141655c7bb76569d 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,8 @@ "author": { "name": "Adrien Dorsaz", "email": "adrien@adorsaz.ch", - "url": "https://adorsaz.ch" + "url": "https://adorsaz.ch", + "fediverse": "@adrien@adorsaz.ch" } } }, @@ -28,9 +29,6 @@ "test:javascript": "mocha", "coverage:javascript": "c8 mocha" }, - "dependencies": { - "dompurify": "^3.1.0" - }, "devDependencies": { "@eslint/eslintrc": "^3.1.0", "@eslint/js": "^9.10.0", diff --git a/src/articles/a-propos-d-ipv4-et-d-ipv6.html b/src/articles/a-propos-d-ipv4-et-d-ipv6.html index b98adc17d45a81fa02ced5af51363b0b07866b56..75c6d03a6ed32118609222011d9de707ebe92904 100644 --- a/src/articles/a-propos-d-ipv4-et-d-ipv6.html +++ b/src/articles/a-propos-d-ipv4-et-d-ipv6.html @@ -40,6 +40,7 @@ <meta name="author-name" content="Adrien Dorsaz" /> <meta name="author-url" content="https://adorsaz.ch" /> <meta name="author-email" content="adrien@adorsaz.ch" /> + <meta name="fediverse:creator" content="@adrien@adorsaz.ch" /> <meta name="lang" content="fr" /> <meta name="license-name" content="CC-BY-SA 4.0" /> <meta diff --git a/src/articles/astuces-pour-ecrire-des-scripts-shell-et-des-definitions-de-conteneurs.html b/src/articles/astuces-pour-ecrire-des-scripts-shell-et-des-definitions-de-conteneurs.html index 6e9289db5e37e38ba2520f168a816e6afe3c3153..68ac7493fbfd29b569516202a44acc338d292738 100644 --- a/src/articles/astuces-pour-ecrire-des-scripts-shell-et-des-definitions-de-conteneurs.html +++ b/src/articles/astuces-pour-ecrire-des-scripts-shell-et-des-definitions-de-conteneurs.html @@ -15,12 +15,6 @@ media="screen" href="../css/screen.css" /> - <link - rel="stylesheet" - type="text/css" - media="screen" - href="../css/comment.css" - /> <link rel="stylesheet" type="text/css" @@ -44,6 +38,7 @@ <meta name="author-name" content="Adrien Dorsaz" /> <meta name="author-url" content="https://adorsaz.ch" /> <meta name="author-email" content="adrien@adorsaz.ch" /> + <meta name="fediverse:creator" content="@adrien@adorsaz.ch" /> <meta name="lang" content="fr" /> <meta name="license-name" content="CC-BY-SA 4.0" /> <meta @@ -60,11 +55,10 @@ content="https://gitlab.adorsaz.ch/adrien/adorsaz.ch/-/commits/main/src/articles/astuces-pour-ecrire-des-scripts-shell-et-des-definitions-de-conteneurs.html" /> <meta - name="mastodon-comment-url" + name="mastodon-share-url" content="https://mastodon.adorsaz.ch/@adrien/111953486356181833" /> <script type="module" src="../javascript/article.js"></script> - <script type="module" src="../javascript/comment.js"></script> <script type="module" src="../javascript/header.js"></script> </head> @@ -242,26 +236,50 @@ EOF</code> </code> </pre> - <section id="comments"> - <h2>Commentaires</h2> - <p> - Répondez à - <a href="https://mastodon.adorsaz.ch/@adrien/111953486356181833" - >ce message</a - > - du - <a href="https://fr.wikipedia.org/wiki/Fediverse">Fediverse</a> pour - ajouter un commentaire sur cet article. - </p> + <section id="notes"> + <h2>Notes</h2> + <article class="note"> + <h3> + <time datetime="2024-03-27T21:08:52.287Z" + >27 mars 2024 à 22:08</time + > + </h3> + <p> + Si jamais, la fonctionnalité "heredoc" dans les Containerfile est + arrivée pour podman dans son moteur de build <i>buildah</i> version + v1.33.0. + </p> + <p> + Il est actuellement disponible dans Debian trixie (testing) et + Fedora 39 si jamais. + </p> + </article> - <div id="mastodon-comments"> - <noscript - ><p> - Les réponses du Fediverse seront affichées ici si vous avctivez le - moteur JavaScript de votre navigateur web. - </p> - </noscript> - </div> + <article class="note"> + <h3> + <time datetime="2024-04-26T12:06:33.230Z" + >26 avril 2024 à 14:06</time + > + </h3> + <p> + En cherchant un marque-pages dans mes favoris de Mastodon, je viens + de me rendre compte que j'avais ajouté en janvier ce message qui + partageait déjà des astuces pour les scripts : + <a href="https://framapiaf.org/@sebsauvage/111719827048771422" + >https://framapiaf.org/@sebsauvage/111719827048771422</a + > + </p> + <p> + Lien direct vers l'article partagé : + <a href="https://sharats.me/posts/shell-script-best-practices/" + >https://sharats.me/posts/shell-script-best-practices/</a + > + </p> + <p> + Il y a quelques points en plus intéressants (notamment, l'affichage + de l'aide) et un modèle prêt à être utilisé. + </p> + </article> </section> </article> </body> diff --git a/src/articles/blog.atom b/src/articles/blog.atom index b3c83808ef238eafe3fa5a2afbb2048eb4df3dd4..557811179bc1b969c12628381a84267c8e41314d 100644 --- a/src/articles/blog.atom +++ b/src/articles/blog.atom @@ -17,7 +17,7 @@ </author> <rights >Licence CC BY-SA http://creativecommons.org/licenses/by-sa/4.0/deed.fr</rights> - <updated>2024-09-17T21:29:57.801Z</updated> + <updated>2025-04-04T19:55:04.470Z</updated> <entry> <title @@ -303,7 +303,7 @@ $ sudo apt install debootstrap</code></pre><p>Ensuite, je déb Avant d’entrer dans le contexte de l’installation (<i>chroot</i>), je copie l’état actuel des points de montage qui ciblent le dossier <i class="text-no-wrap">/mnt</i> du système autonome dans le fichier - <i>fstab</i> du <i>chroot</i> (ce fichier a été crée par + <i>fstab</i> du <i>chroot</i> (ce fichier a été créé par <i>debootstrap</i>)&nbsp;: </p><pre><code>$ grep /mnt /etc/mtab | sudo tee -a /mnt/etc/fstab</code></pre><p> Pour la partie «&nbsp;<i>Créer les fichiers des périphériques</i>&nbsp;» du manuel @@ -671,17 +671,6 @@ $ sudo systemctl enable --now systemd-boot-sign.path</code></pre>< </p> </li> </ol> - </section><section id="comments"> - <h2>Commentaires</h2> - <p> - Répondez à - <a href="https://mastodon.adorsaz.ch/@adrien/113155013129979818">ce message</a> - du - <a href="https://fr.wikipedia.org/wiki/Fediverse">Fediverse</a> pour - ajouter un commentaire sur cet article. - </p> - - </section></content> </entry> <entry> @@ -906,17 +895,42 @@ EOF</code> apt install python3 apt-get clean </code> -</pre><section id="comments"> - <h2>Commentaires</h2> - <p> - Répondez à - <a href="https://mastodon.adorsaz.ch/@adrien/111953486356181833">ce message</a> - du - <a href="https://fr.wikipedia.org/wiki/Fediverse">Fediverse</a> pour - ajouter un commentaire sur cet article. - </p> +</pre><section id="notes"> + <h2>Notes</h2> + <article class="note"> + <h3> + <time datetime="2024-03-27T21:08:52.287Z">27 mars 2024 à 22:08</time> + </h3> + <p> + Si jamais, la fonctionnalité "heredoc" dans les Containerfile est + arrivée pour podman dans son moteur de build <i>buildah</i> version + v1.33.0. + </p> + <p> + Il est actuellement disponible dans Debian trixie (testing) et + Fedora 39 si jamais. + </p> + </article> - + <article class="note"> + <h3> + <time datetime="2024-04-26T12:06:33.230Z">26 avril 2024 à 14:06</time> + </h3> + <p> + En cherchant un marque-pages dans mes favoris de Mastodon, je viens + de me rendre compte que j'avais ajouté en janvier ce message qui + partageait déjà des astuces pour les scripts : + <a href="https://framapiaf.org/@sebsauvage/111719827048771422">https://framapiaf.org/@sebsauvage/111719827048771422</a> + </p> + <p> + Lien direct vers l'article partagé : + <a href="https://sharats.me/posts/shell-script-best-practices/">https://sharats.me/posts/shell-script-best-practices/</a> + </p> + <p> + Il y a quelques points en plus intéressants (notamment, l'affichage + de l'aide) et un modèle prêt à être utilisé. + </p> + </article> </section></content> </entry> <entry> @@ -962,18 +976,7 @@ EOF</code> </p><p> Ce dossier contient des fichiers textes, je n'ai donc même pas eu besoin de démarrer un serveur web pour visualiser la documentation. - </p><section id="comments"> - <h2>Commentaires</h2> - <p> - Répondez à - <a href="https://mastodon.adorsaz.ch/@adrien/111530014777140306">ce message</a> - du - <a href="https://fr.wikipedia.org/wiki/Fediverse">Fediverse</a> pour - ajouter un commentaire sur cet article. - </p> - - - </section></content> + </p></content> </entry> <entry> <title type="text">Comment savoir si le style sombre est actif ?</title> @@ -1101,18 +1104,7 @@ EOF</code> Toute cette recherche m’a amené à ce <a href="https://gitlab.adorsaz.ch/adrien/config/-/commit/f003dcb0b85ad3a1cfae01b9f8d601e9e1995bc3?view=parallel">petit correctif</a> de quelques lignes dans mon fichier <em>vimrc</em>. - </p><section id="comments"> - <h2>Commentaires</h2> - <p> - Répondez à - <a href="https://mastodon.adorsaz.ch/@adrien/111425807298246655">ce message</a> - du - <a href="https://fr.wikipedia.org/wiki/Fediverse">Fediverse</a> pour - ajouter un commentaire sur cet article. - </p> - - - </section></content> + </p></content> </entry> <entry> <title type="text">Découvertes de logiciels libres - été 2023</title> @@ -1373,18 +1365,7 @@ EOF</code> HTML ne sont pas vraiment liés, il est très difficile de placer les marqueurs de manière exacte et il est nécessaire d’avoir toujours un espace équivalent entre chaque marqueur. - </p><section id="comments"> - <h2>Commentaires</h2> - <p> - Répondez à - <a href="https://mastodon.adorsaz.ch/@adrien/111388345894959194">ce message</a> - du - <a href="https://fr.wikipedia.org/wiki/Fediverse">Fediverse</a> pour - ajouter un commentaire sur cet article. - </p> - - - </section></content> + </p></content> </entry> <entry> <title type="text">Vous avez dit "caractère" ?</title> @@ -1988,17 +1969,27 @@ git clone https://github.com/kien/ctrlp.vim</code></pre><p> projets persos, j’ai préparé un répertoire <em>git</em> avec <a href="https://projects.adorsaz.ch/adrien/config/">mes fichiers de configuration</a> si vous voulez tous les détails. - </p><section id="comments"> - <h2>Commentaires</h2> - <p> - Répondez à - <a href="https://mastodon.adorsaz.ch/@adrien/111693530165472878">ce message</a> - du - <a href="https://fr.wikipedia.org/wiki/Fediverse">Fediverse</a> pour - ajouter un commentaire sur cet article. - </p> - - + </p><section id="notes"> + <h2>Notes</h2> + <article class="note"> + <h3> + <time datetime="2024-01-03T19:12:26.524Z">3 janvier 2024 à 20:12</time> + </h3> + <p> + Ça fait 3 ans que j'utilise vim comme ide, c'est toujours aussi bien + :) + </p> + <p> + Pour mon nouveau job, je suis en train d'utiliser PHP Storm, mais je + vais revenir à vim: l'indexation des fichiers est toujours lente et + l'ide consomme facilement 3-4 Gio de mémoire à la fin de la journée. + </p> + <p> + Il faudrait que j'écrive un petit article sur les quelques + configurations que j'ai faite en plus depuis, mais l'essentiel est + resté identique. + </p> + </article> </section></content> </entry> <entry> diff --git a/src/articles/comment-savoir-si-le-style-sombre-est-actif.html b/src/articles/comment-savoir-si-le-style-sombre-est-actif.html index db67543ca0f60c8c10f5bc3fba3fef8c0e218267..dc5f399e793bd0d9bb8a7c9627ca418b9c6bfd8c 100644 --- a/src/articles/comment-savoir-si-le-style-sombre-est-actif.html +++ b/src/articles/comment-savoir-si-le-style-sombre-est-actif.html @@ -15,12 +15,6 @@ media="screen" href="../css/screen.css" /> - <link - rel="stylesheet" - type="text/css" - media="screen" - href="../css/comment.css" - /> <link rel="stylesheet" type="text/css" @@ -41,6 +35,7 @@ <meta name="author-name" content="Adrien Dorsaz" /> <meta name="author-url" content="https://adorsaz.ch" /> <meta name="author-email" content="adrien@adorsaz.ch" /> + <meta name="fediverse:creator" content="@adrien@adorsaz.ch" /> <meta name="lang" content="fr" /> <meta name="license-name" content="CC-BY-SA 4.0" /> <meta @@ -59,11 +54,10 @@ content="https://gitlab.adorsaz.ch/adrien/adorsaz.ch/-/commits/main/src/articles/comment-savoir-si-le-style-sombre-est-actif.html" /> <meta - name="mastodon-comment-url" + name="mastodon-share-url" content="https://mastodon.adorsaz.ch/@adrien/111425807298246655" /> <script type="module" src="../javascript/article.js"></script> - <script type="module" src="../javascript/comment.js"></script> <script type="module" src="../javascript/header.js"></script> </head> @@ -236,28 +230,6 @@ > de quelques lignes dans mon fichier <em>vimrc</em>. </p> - - <section id="comments"> - <h2>Commentaires</h2> - <p> - Répondez à - <a href="https://mastodon.adorsaz.ch/@adrien/111425807298246655" - >ce message</a - > - du - <a href="https://fr.wikipedia.org/wiki/Fediverse">Fediverse</a> pour - ajouter un commentaire sur cet article. - </p> - - <div id="mastodon-comments"> - <noscript - ><p> - Les réponses du Fediverse seront affichées ici si vous avctivez le - moteur JavaScript de votre navigateur web. - </p> - </noscript> - </div> - </section> </article> </body> </html> diff --git a/src/articles/creer-des-certificats-avec-acme-let-s-encrypt-et-des-verifications-dns.html b/src/articles/creer-des-certificats-avec-acme-let-s-encrypt-et-des-verifications-dns.html index 776a2b1ab730922af61292b3ed396dc72a0ac5de..a1d43ab0a09027b592b9c37f499b5b0aeddc445c 100644 --- a/src/articles/creer-des-certificats-avec-acme-let-s-encrypt-et-des-verifications-dns.html +++ b/src/articles/creer-des-certificats-avec-acme-let-s-encrypt-et-des-verifications-dns.html @@ -42,6 +42,7 @@ <meta name="author-name" content="Adrien Dorsaz" /> <meta name="author-url" content="https://adorsaz.ch" /> <meta name="author-email" content="adrien@adorsaz.ch" /> + <meta name="fediverse:creator" content="@adrien@adorsaz.ch" /> <meta name="lang" content="fr" /> <meta name="license-name" content="CC-BY-SA 4.0" /> <meta diff --git a/src/articles/decouvertes-logiciels-libres-ete-2023.html b/src/articles/decouvertes-logiciels-libres-ete-2023.html index be9400f70e22c24ac80451ddc11bbc5ebec320fe..a8656589bf214cd75af11f7b420b3c8b4d0f4a22 100644 --- a/src/articles/decouvertes-logiciels-libres-ete-2023.html +++ b/src/articles/decouvertes-logiciels-libres-ete-2023.html @@ -15,12 +15,6 @@ media="screen" href="../css/screen.css" /> - <link - rel="stylesheet" - type="text/css" - media="screen" - href="../css/comment.css" - /> <link rel="stylesheet" type="text/css" @@ -41,6 +35,7 @@ <meta name="author-name" content="Adrien Dorsaz" /> <meta name="author-url" content="https://adorsaz.ch" /> <meta name="author-email" content="adrien@adorsaz.ch" /> + <meta name="fediverse:creator" content="@adrien@adorsaz.ch" /> <meta name="lang" content="fr" /> <meta name="license-name" content="CC-BY-SA 4.0" /> <meta @@ -63,7 +58,6 @@ content="https://linuxfr.org/users/trim/journaux/decouvertes-de-logiciels-libres-ete-2023" /> <script type="module" src="../javascript/article.js"></script> - <script type="module" src="../javascript/comment.js"></script> <script type="module" src="../javascript/header.js"></script> </head> @@ -392,28 +386,6 @@ marqueurs de manière exacte et il est nécessaire d’avoir toujours un espace équivalent entre chaque marqueur. </p> - - <section id="comments"> - <h2>Commentaires</h2> - <p> - Répondez à - <a href="https://mastodon.adorsaz.ch/@adrien/111388345894959194" - >ce message</a - > - du - <a href="https://fr.wikipedia.org/wiki/Fediverse">Fediverse</a> pour - ajouter un commentaire sur cet article. - </p> - - <div id="mastodon-comments"> - <noscript - ><p> - Les réponses du Fediverse seront affichées ici si vous avctivez le - moteur JavaScript de votre navigateur web. - </p> - </noscript> - </div> - </section> </article> </body> </html> diff --git a/src/articles/gnome-et-logitech-collaborent-pour-vous-proposer-des-mises-a-jour-de-leur-solution-unify.html b/src/articles/gnome-et-logitech-collaborent-pour-vous-proposer-des-mises-a-jour-de-leur-solution-unify.html index 70640e2d7a6a721dbd04bc5d5501bd6be744452f..c393b75e8bc3438d6ad128731479cd808da67018 100644 --- a/src/articles/gnome-et-logitech-collaborent-pour-vous-proposer-des-mises-a-jour-de-leur-solution-unify.html +++ b/src/articles/gnome-et-logitech-collaborent-pour-vous-proposer-des-mises-a-jour-de-leur-solution-unify.html @@ -43,6 +43,7 @@ <meta name="author-name" content="Adrien Dorsaz" /> <meta name="author-url" content="https://adorsaz.ch" /> <meta name="author-email" content="adrien@adorsaz.ch" /> + <meta name="fediverse:creator" content="@adrien@adorsaz.ch" /> <meta name="lang" content="fr" /> <meta name="license-name" content="CC-BY-SA 4.0" /> <meta diff --git "a/src/articles/installation-personnalis\303\251e-de-debian.html" "b/src/articles/installation-personnalis\303\251e-de-debian.html" index caa4e2354f7c69e27a6ed2a7a8bbe98f6eaf003c..a75be54defd1f328ce4566f71a2b041f0dfff350 100644 --- "a/src/articles/installation-personnalis\303\251e-de-debian.html" +++ "b/src/articles/installation-personnalis\303\251e-de-debian.html" @@ -44,6 +44,7 @@ <meta name="author-name" content="Adrien Dorsaz" /> <meta name="author-url" content="https://adorsaz.ch" /> <meta name="author-email" content="adrien@adorsaz.ch" /> + <meta name="fediverse:creator" content="@adrien@adorsaz.ch" /> <meta name="lang" content="fr" /> <meta name="license-name" content="CC BY-SA" /> <meta @@ -60,7 +61,7 @@ content="https://gitlab.adorsaz.ch/adrien/adorsaz.ch/-/commits/main/src/articles/installation-personnalisée-de-debian.html" /> <meta - name="mastodon-comment-url" + name="mastodon-share-url" content="https://mastodon.adorsaz.ch/@adrien/113155013129979818" /> <meta name="duplicate-1-name" content="LinuxFr.org" /> @@ -69,7 +70,6 @@ content="https://linuxfr.org/users/trim/journaux/installation-personnalisee-de-debian-avec-luks-v2-volumes-btrfs-systemd-boot-et-secure-boot" /> <script type="module" src="../javascript/article.js"></script> - <script type="module" src="../javascript/comment.js"></script> <script type="module" src="../javascript/header.js"></script> </head> @@ -947,27 +947,6 @@ $ sudo systemctl enable --now systemd-boot-sign.path</code></pre> </li> </ol> </section> - <section id="comments"> - <h2>Commentaires</h2> - <p> - Répondez à - <a href="https://mastodon.adorsaz.ch/@adrien/113155013129979818" - >ce message</a - > - du - <a href="https://fr.wikipedia.org/wiki/Fediverse">Fediverse</a> pour - ajouter un commentaire sur cet article. - </p> - - <div id="mastodon-comments"> - <noscript - ><p> - Les réponses du Fediverse seront affichées ici si vous activez le - moteur JavaScript de votre navigateur web. - </p> - </noscript> - </div> - </section> </article> </body> </html> diff --git a/src/articles/livrer-la-documentation-avec-le-code-source.html b/src/articles/livrer-la-documentation-avec-le-code-source.html index 694860cefba2d3fe90b478a12a35a7f1ba115431..b0afe341ae8e73a17f3b58e32d6d83bfad669b2f 100644 --- a/src/articles/livrer-la-documentation-avec-le-code-source.html +++ b/src/articles/livrer-la-documentation-avec-le-code-source.html @@ -15,12 +15,6 @@ media="screen" href="../css/screen.css" /> - <link - rel="stylesheet" - type="text/css" - media="screen" - href="../css/comment.css" - /> <link rel="stylesheet" type="text/css" @@ -41,6 +35,7 @@ <meta name="author-name" content="Adrien Dorsaz" /> <meta name="author-url" content="https://adorsaz.ch" /> <meta name="author-email" content="adrien@adorsaz.ch" /> + <meta name="fediverse:creator" content="@adrien@adorsaz.ch" /> <meta name="lang" content="fr" /> <meta name="license-name" content="CC-BY-SA 4.0" /> <meta @@ -54,11 +49,10 @@ content="https://gitlab.adorsaz.ch/adrien/adorsaz.ch/-/commits/main/src/articles/livrer-la-documentation-avec-le-code-source.html" /> <meta - name="mastodon-comment-url" + name="mastodon-share-url" content="https://mastodon.adorsaz.ch/@adrien/111530014777140306" /> <script type="module" src="../javascript/article.js"></script> - <script type="module" src="../javascript/comment.js"></script> <script type="module" src="../javascript/header.js"></script> </head> @@ -115,28 +109,6 @@ Ce dossier contient des fichiers textes, je n'ai donc même pas eu besoin de démarrer un serveur web pour visualiser la documentation. </p> - - <section id="comments"> - <h2>Commentaires</h2> - <p> - Répondez à - <a href="https://mastodon.adorsaz.ch/@adrien/111530014777140306" - >ce message</a - > - du - <a href="https://fr.wikipedia.org/wiki/Fediverse">Fediverse</a> pour - ajouter un commentaire sur cet article. - </p> - - <div id="mastodon-comments"> - <noscript - ><p> - Les réponses du Fediverse seront affichées ici si vous avctivez le - moteur JavaScript de votre navigateur web. - </p> - </noscript> - </div> - </section> </article> </body> </html> diff --git a/src/articles/mise-a-jour-simplifiee-des-routeurs-openwrt.html b/src/articles/mise-a-jour-simplifiee-des-routeurs-openwrt.html index c337c44d5beeff3293e3d8e6664f84aa4ac225c8..8971843a7c32f64d1d1d66c357f5a85ca7cead6d 100644 --- a/src/articles/mise-a-jour-simplifiee-des-routeurs-openwrt.html +++ b/src/articles/mise-a-jour-simplifiee-des-routeurs-openwrt.html @@ -40,6 +40,7 @@ <meta name="author-name" content="Adrien Dorsaz" /> <meta name="author-url" content="https://adorsaz.ch" /> <meta name="author-email" content="adrien@adorsaz.ch" /> + <meta name="fediverse:creator" content="@adrien@adorsaz.ch" /> <meta name="lang" content="fr" /> <meta name="license-name" content="CC BY-SA" /> <meta diff --git a/src/articles/proteger-sa-vie-privee-avec-l-ipv6.html b/src/articles/proteger-sa-vie-privee-avec-l-ipv6.html index 492d338668411750c11f072bfa4e22edff652d70..d83a8fc2ccc4ccf02abd92ee2e46245895dacae0 100644 --- a/src/articles/proteger-sa-vie-privee-avec-l-ipv6.html +++ b/src/articles/proteger-sa-vie-privee-avec-l-ipv6.html @@ -40,6 +40,7 @@ <meta name="author-name" content="Adrien Dorsaz" /> <meta name="author-url" content="https://adorsaz.ch" /> <meta name="author-email" content="adrien@adorsaz.ch" /> + <meta name="fediverse:creator" content="@adrien@adorsaz.ch" /> <meta name="contributor-1-name" content="Yves Bourguignon" /> <meta name="contributor-1-url" content="https://linuxfr.org/users/biomin" /> <meta name="contributor-2-name" content="Lucas" /> diff --git a/src/articles/publication-d-acme-dns-tiny-et-du-rfc-8555.html b/src/articles/publication-d-acme-dns-tiny-et-du-rfc-8555.html index 11efb92fbf445b1a250281651b1d02670a3f5abe..1d4c70122ee517b0d0b323fc9fbee49e9a0d5db8 100644 --- a/src/articles/publication-d-acme-dns-tiny-et-du-rfc-8555.html +++ b/src/articles/publication-d-acme-dns-tiny-et-du-rfc-8555.html @@ -40,6 +40,7 @@ <meta name="author-name" content="Adrien Dorsaz" /> <meta name="author-url" content="https://adorsaz.ch" /> <meta name="author-email" content="adrien@adorsaz.ch" /> + <meta name="fediverse:creator" content="@adrien@adorsaz.ch" /> <meta name="lang" content="fr" /> <meta name="license-name" content="CC-BY-SA 4.0" /> <meta diff --git a/src/articles/rootless-container.html b/src/articles/rootless-container.html index 1f7484753e12b1249f1fb2e4a51bb2e7ad180da1..82c6e1d70b860b3ec21a96496b72b369d4145405 100644 --- a/src/articles/rootless-container.html +++ b/src/articles/rootless-container.html @@ -43,6 +43,7 @@ <meta name="author-name" content="Adrien Dorsaz" /> <meta name="author-url" content="https://adorsaz.ch" /> <meta name="author-email" content="adrien@adorsaz.ch" /> + <meta name="fediverse:creator" content="@adrien@adorsaz.ch" /> <meta name="lang" content="fr" /> <meta name="license-name" content="CC-BY-SA 4.0" /> <meta diff --git a/src/articles/transformer-vim-en-ide-avec-lsp-et-dap.html b/src/articles/transformer-vim-en-ide-avec-lsp-et-dap.html index e133178046985504067ff7af154d7ace66cc3e58..d7d751308cb493e44cc66898e898407be0b40ee2 100644 --- a/src/articles/transformer-vim-en-ide-avec-lsp-et-dap.html +++ b/src/articles/transformer-vim-en-ide-avec-lsp-et-dap.html @@ -15,12 +15,6 @@ media="screen" href="../css/screen.css" /> - <link - rel="stylesheet" - type="text/css" - media="screen" - href="../css/comment.css" - /> <link rel="stylesheet" type="text/css" @@ -46,6 +40,7 @@ <meta name="author-name" content="Adrien Dorsaz" /> <meta name="author-url" content="https://adorsaz.ch" /> <meta name="author-email" content="adrien@adorsaz.ch" /> + <meta name="fediverse:creator" content="@adrien@adorsaz.ch" /> <meta name="lang" content="fr" /> <meta name="license-name" content="CC-BY-SA 4.0" /> <meta @@ -62,11 +57,10 @@ content="https://gitlab.adorsaz.ch/adrien/adorsaz.ch/-/commits/main/src/articles/transformer-vim-en-ide-avec-lsp-et-dap.html" /> <meta - name="mastodon-comment-url" + name="mastodon-share-url" content="https://mastodon.adorsaz.ch/@adrien/111693530165472878" /> <script type="module" src="../javascript/article.js"></script> - <script type="module" src="../javascript/comment.js"></script> <script type="module" src="../javascript/header.js"></script> </head> @@ -325,26 +319,29 @@ git clone https://github.com/kien/ctrlp.vim</code></pre> si vous voulez tous les détails. </p> - <section id="comments"> - <h2>Commentaires</h2> - <p> - Répondez à - <a href="https://mastodon.adorsaz.ch/@adrien/111693530165472878" - >ce message</a - > - du - <a href="https://fr.wikipedia.org/wiki/Fediverse">Fediverse</a> pour - ajouter un commentaire sur cet article. - </p> - - <div id="mastodon-comments"> - <noscript - ><p> - Les réponses du Fediverse seront affichées ici si vous avctivez le - moteur JavaScript de votre navigateur web. - </p> - </noscript> - </div> + <section id="notes"> + <h2>Notes</h2> + <article class="note"> + <h3> + <time datetime="2024-01-03T19:12:26.524Z" + >3 janvier 2024 à 20:12</time + > + </h3> + <p> + Ça fait 3 ans que j'utilise vim comme ide, c'est toujours aussi bien + :) + </p> + <p> + Pour mon nouveau job, je suis en train d'utiliser PHP Storm, mais je + vais revenir à vim: l'indexation des fichiers est toujours lente et + l'ide consomme facilement 3-4 Gio de mémoire à la fin de la journée. + </p> + <p> + Il faudrait que j'écrive un petit article sur les quelques + configurations que j'ai faite en plus depuis, mais l'essentiel est + resté identique. + </p> + </article> </section> </article> </body> diff --git a/src/articles/vous-avez-dit-caractere.html b/src/articles/vous-avez-dit-caractere.html index 6dbd5b8619e429b967b0e16c7f5f91d606b6a2ad..b16bc0d5f14913eda403b68194a41c3639e1f7a5 100644 --- a/src/articles/vous-avez-dit-caractere.html +++ b/src/articles/vous-avez-dit-caractere.html @@ -40,6 +40,7 @@ <meta name="author-name" content="Adrien Dorsaz" /> <meta name="author-url" content="https://adorsaz.ch" /> <meta name="author-email" content="adrien@adorsaz.ch" /> + <meta name="fediverse:creator" content="@adrien@adorsaz.ch" /> <meta name="lang" content="fr" /> <meta name="license-name" content="CC-BY-SA 4.0" /> <meta diff --git a/src/css/comment.css b/src/css/comment.css deleted file mode 100644 index e1ea902b1d8c694f16bc4e598f8ee7ea21e9bcd6..0000000000000000000000000000000000000000 --- a/src/css/comment.css +++ /dev/null @@ -1,98 +0,0 @@ -/* template is defined in sized css files */ -#comments .comment { - display: grid; - column-gap: 1rem; - padding: 0.5rem; - border: solid 1px hsl(var(--text-color-hsl) / 40%); - margin-block: 1rem; -} - -#comments .comment-reply { - margin-inline-start: 2rem; - position: relative; - overflow: unset; -} - -#comments .comment-reply::before { - content: "⤷"; - font-size: 2rem; - position: absolute; - left: -1.5rem; -} - -#comments .comment .avatar-link { - height: 3rem; - aspect-ratio: 1/1; - grid-area: avatar; - position: relative; -} - -#comments .comment header { - grid-area: name; -} - -#comments .comment header .instance { - margin-inline-start: 0.5rem; -} - -#comments .comment aside { - grid-area: aside; - justify-self: end; - white-space: nowrap; -} - -#comments .comment aside .permalink { - margin-inline-start: 0.5rem; -} - -#comments .comment > div { - grid-area: post; -} - -#comments .comment footer { - grid-area: interactions; -} - -#comments .comment .avatar-link img.avatar { - width: 100%; - height: 100%; - object-fit: scale-down; -} - -#comments .comment.op .avatar-link::after { - content: "âœ"; - text-decoration: none; - color: black; - background-color: hsl(var(--background-color-hsl) / 100%); - border: solid 1px hsl(var(--accent-color-hsl) / 100%); - border-radius: 50%; - width: 1.5rem; - height: 1.5rem; - text-align: center; - font-size: 1rem; - padding-top: 0.1rem; - position: absolute; - bottom: -0.5rem; - right: -0.5rem; - display: block; -} - -#comments img.emoji { - height: 0.8em; - aspect-ratio: 1/1; -} - -#comments .faves { - color: unset; - text-decoration: none; -} - -@media (prefers-color-scheme: dark) { - #comments .comment { - background: color-mix( - in sRGB, - hsl(var(--background-color-hsl) / 100%) 95%, - hsl(var(--text-color-hsl) / 100%) - ); - } -} diff --git a/src/css/screen.css b/src/css/screen.css index 0b757a8e2c708a62ee82065d7ed8cc1a67dcd472..03ade15335be4671bfc81533d1d88e9adefc25b9 100644 --- a/src/css/screen.css +++ b/src/css/screen.css @@ -418,7 +418,7 @@ button .icon, } dialog > header button { - aspect-ratio: 1; + aspect-ratio: 1 / 1; padding: 0.2rem; font-size: 1rem; font-weight: 900; @@ -533,6 +533,14 @@ details[open] > summary::after { content: "⤴"; } +#notes .note { + display: grid; + column-gap: 1rem; + padding: 0.5rem; + border: solid 1px hsl(var(--text-color-hsl) / 40%); + margin-block: 1rem; +} + @media (prefers-color-scheme: dark) { :root { /* Main colors */ @@ -568,4 +576,12 @@ details[open] > summary::after { .button { background: no-repeat hsl(var(--accent-color-hsl) / 25%); } + + #notes .note { + background: color-mix( + in sRGB, + hsl(var(--background-color-hsl) / 100%) 95%, + hsl(var(--text-color-hsl) / 100%) + ); + } } diff --git a/src/javascript/article.js b/src/javascript/article.js index 0d1954492e7307f385c249a35f11ecce5cbc51ca..a3730754431e45145b3aba8cbcfb60ba408cf0b3 100644 --- a/src/javascript/article.js +++ b/src/javascript/article.js @@ -192,6 +192,13 @@ async function addMetadataInArticle() { } } + if (metadata["mastodon-share-url"]) { + linkSpan.append(", ") + linkSpan.appendChild( + createLink(metadata["mastodon-share-url"], "Mastodon"), + ) + } + aside.appendChild(linkSpan) } articleTitle.parentNode.insertBefore(aside, articleTitle.nextSibling) diff --git a/src/javascript/comment.js b/src/javascript/comment.js deleted file mode 100644 index 95e0af4593fbfaf1fcecd7bf827e8943ae5038b5..0000000000000000000000000000000000000000 --- a/src/javascript/comment.js +++ /dev/null @@ -1,219 +0,0 @@ -import DOMPurify from "../vendor/javascript/purify.es.js" -import Http from "./http.js" -import { getLocalizations } from "./localization.js" - -/* - * Licensed under CC BY-SA 4.0 - * - * Original code created by Carl Schwan, Cassidy James Blaede and Veronica Olsen: - * * https://carlschwan.eu/2020/12/29/adding-comments-to-your-static-blog-with-mastodon/ - */ - -function escapeHtml(unsafe) { - return unsafe - .replace(/&/g, "&") - .replace(/</g, "<") - .replace(/>/g, ">") - .replace(/"/g, """) - .replace(/'/g, "'") -} - -function emojify(input, emojis) { - let output = input - - emojis.forEach((emoji) => { - const picture = document.createElement("picture") - - const source = document.createElement("source") - source.setAttribute("srcset", new URL(emoji.url)) - source.setAttribute("media", "(prefers-reduced-motion: no-preference)") - - const img = new Image() - img.className = "emoji" - img.src = new URL(emoji.static_url) - img.alt = `:${emoji.shortcode}:` - img.title = `:${emoji.shortcode}:` - - picture.appendChild(source) - picture.appendChild(img) - - output = output.replace(`:${emoji.shortcode}:`, picture.outerHTML) - }) - - return output -} - -async function loadComments() { - const mastodonComments = document.getElementById("mastodon-comments") - const mastodonUrl = new URL( - document - .querySelector('meta[name="mastodon-comment-url"]') - .getAttribute("content"), - ) - const mastodonUser = mastodonUrl.pathname.split("/")[1].replace("@", "") - const mastodonId = mastodonUrl.pathname.split("/")[2] - - if (!(mastodonComments && mastodonUrl && mastodonUser && mastodonId)) { - console.warn("Mastodon URL is missing or malformed.") - return - } - - const data = await Http({ - url: new URL(`/api/v1/statuses/${mastodonId}/context`, mastodonUrl), - responseType: "json", - }) - - const descendants = data.descendants - if (descendants && Array.isArray(descendants) && descendants.length > 0) { - mastodonComments.innerHTML = "" - - const l10n = await getLocalizations("comment") - - descendants.forEach(function (status) { - if (status.account.display_name.length > 0) { - status.account.display_name = escapeHtml(status.account.display_name) - status.account.display_name = emojify( - status.account.display_name, - status.account.emojis, - ) - } else { - status.account.display_name = status.account.username - } - - let instance = mastodonUrl.hostname - if (status.account.acct.includes("@")) { - instance = status.account.acct.split("@")[1] - } - - const isReply = status.in_reply_to_id !== mastodonId - - const originalPoster = status.account.acct === mastodonUser - - status.content = emojify(status.content, status.emojis) - - const avatarSource = document.createElement("source") - avatarSource.setAttribute("srcset", new URL(status.account.avatar)) - avatarSource.setAttribute( - "media", - "(prefers-reduced-motion: no-preference)", - ) - - const avatarImg = new Image() - avatarImg.className = "avatar" - avatarImg.alt = `${l10n["avatar-of"]} @${status.account.username}@${instance}` - avatarImg.src = new URL(status.account.avatar_static) - - const avatarPicture = document.createElement("picture") - avatarPicture.appendChild(avatarSource) - avatarPicture.appendChild(avatarImg) - - const avatar = document.createElement("a") - avatar.className = "avatar-link" - avatar.setAttribute("href", status.account.url) - avatar.setAttribute("rel", "external nofollow") - avatar.setAttribute( - "title", - `${l10n["view-profile-at"]} @${status.account.username}@${instance}`, - ) - avatar.appendChild(avatarPicture) - - const instanceBadge = document.createElement("span") - instanceBadge.className = "instance tag" - - const instanceBadgeIcon = document.createElement("span") - instanceBadgeIcon.className = "icon" - instanceBadgeIcon.textContent = `ðŸŒ` - instanceBadgeIcon.setAttribute("arria-hidden", "true") - - const instanceBadgeText = document.createElement("span") - instanceBadgeText.textContent = instance - - instanceBadge.appendChild(instanceBadgeIcon) - instanceBadge.appendChild(instanceBadgeText) - - const name = document.createElement("a") - name.setAttribute("itemprop", "author") - name.setAttribute("itemtype", "http://schema.org/Person") - name.setAttribute("href", status.account.url) - name.setAttribute("title", `@${status.account.username}@${instance}`) - name.setAttribute("rel", "external nofollow") - name.innerHTML = status.account.display_name - - const header = document.createElement("header") - header.className = "author" - header.appendChild(name) - header.appendChild(instanceBadge) - - const aside = document.createElement("aside") - - const timestamp = document.createElement("time") - timestamp.setAttribute("datetime", status.created_at) - timestamp.innerText = new Date(status.created_at).toLocaleString( - document.querySelector("meta[name=lang]").getAttribute("content") ?? - (navigator.language || "fr-CH"), - { - dateStyle: "long", - timeStyle: "short", - }, - ) - aside.appendChild(timestamp) - - const permalink = document.createElement("a") - permalink.className = "permalink" - permalink.setAttribute("href", status.url) - permalink.setAttribute("itemprop", "url") - permalink.setAttribute("title", l10n["comment-permalink"]) - permalink.setAttribute("rel", "external nofollow") - permalink.textContent = "#" - aside.appendChild(permalink) - - const div = document.createElement("div") - div.setAttribute("itemprop", "text") - div.innerHTML = status.content - - const interactions = document.createElement("footer") - if (status.favourites_count > 0) { - const faves = document.createElement("a") - faves.className = "faves" - faves.setAttribute("href", `${status.url}/favourites`) - faves.setAttribute("title", `${l10n["favorites-from"]} ${instance}`) - faves.textContent = `🌟 ${status.favourites_count}` - - interactions.appendChild(faves) - } - - const comment = document.createElement("article") - comment.id = `comment-${status.id}` - comment.className = isReply ? "comment comment-reply" : "comment" - comment.setAttribute("itemprop", "comment") - comment.setAttribute("itemtype", "http://schema.org/Comment") - comment.appendChild(avatar) - comment.appendChild(header) - comment.appendChild(aside) - comment.appendChild(div) - comment.appendChild(interactions) - - if (originalPoster) { - comment.classList.add("op") - - avatar.classList.add("op") - avatar.setAttribute( - "title", - `${l10n["original-poster"]} ${avatar.getAttribute("title").toLowerCase()}`, - ) - - instanceBadge.classList.add("op") - instanceBadge.setAttribute( - "title", - `${l10n["original-poster"]} ${instanceBadge.innerText}`, - ) - } - - mastodonComments.innerHTML += DOMPurify.sanitize(comment.outerHTML) - }) - } -} - -document.addEventListener("DOMContentLoaded", () => { - loadComments() -}) diff --git a/src/vendor/javascript/purify.es.js b/src/vendor/javascript/purify.es.js deleted file mode 100644 index a872c1166bb381a07d4c2da86ce78ef2f46fe83a..0000000000000000000000000000000000000000 --- a/src/vendor/javascript/purify.es.js +++ /dev/null @@ -1,2443 +0,0 @@ -/*! @license DOMPurify 3.1.6 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.1.6/LICENSE */ - -const { - entries, - setPrototypeOf, - isFrozen, - getPrototypeOf, - getOwnPropertyDescriptor, -} = Object -let { freeze, seal, create } = Object // eslint-disable-line import/no-mutable-exports -let { apply, construct } = typeof Reflect !== "undefined" && Reflect -if (!freeze) { - freeze = function freeze(x) { - return x - } -} -if (!seal) { - seal = function seal(x) { - return x - } -} -if (!apply) { - apply = function apply(fun, thisValue, args) { - return fun.apply(thisValue, args) - } -} -if (!construct) { - construct = function construct(Func, args) { - return new Func(...args) - } -} -const arrayForEach = unapply(Array.prototype.forEach) -const arrayPop = unapply(Array.prototype.pop) -const arrayPush = unapply(Array.prototype.push) -const stringToLowerCase = unapply(String.prototype.toLowerCase) -const stringToString = unapply(String.prototype.toString) -const stringMatch = unapply(String.prototype.match) -const stringReplace = unapply(String.prototype.replace) -const stringIndexOf = unapply(String.prototype.indexOf) -const stringTrim = unapply(String.prototype.trim) -const objectHasOwnProperty = unapply(Object.prototype.hasOwnProperty) -const regExpTest = unapply(RegExp.prototype.test) -const typeErrorCreate = unconstruct(TypeError) - -/** - * Creates a new function that calls the given function with a specified thisArg and arguments. - * - * @param {Function} func - The function to be wrapped and called. - * @returns {Function} A new function that calls the given function with a specified thisArg and arguments. - */ -function unapply(func) { - return function (thisArg) { - for ( - var _len = arguments.length, - args = new Array(_len > 1 ? _len - 1 : 0), - _key = 1; - _key < _len; - _key++ - ) { - args[_key - 1] = arguments[_key] - } - return apply(func, thisArg, args) - } -} - -/** - * Creates a new function that constructs an instance of the given constructor function with the provided arguments. - * - * @param {Function} func - The constructor function to be wrapped and called. - * @returns {Function} A new function that constructs an instance of the given constructor function with the provided arguments. - */ -function unconstruct(func) { - return function () { - for ( - var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; - _key2 < _len2; - _key2++ - ) { - args[_key2] = arguments[_key2] - } - return construct(func, args) - } -} - -/** - * Add properties to a lookup table - * - * @param {Object} set - The set to which elements will be added. - * @param {Array} array - The array containing elements to be added to the set. - * @param {Function} transformCaseFunc - An optional function to transform the case of each element before adding to the set. - * @returns {Object} The modified set with added elements. - */ -function addToSet(set, array) { - let transformCaseFunc = - arguments.length > 2 && arguments[2] !== undefined - ? arguments[2] - : stringToLowerCase - if (setPrototypeOf) { - // Make 'in' and truthy checks like Boolean(set.constructor) - // independent of any properties defined on Object.prototype. - // Prevent prototype setters from intercepting set as a this value. - setPrototypeOf(set, null) - } - let l = array.length - while (l--) { - let element = array[l] - if (typeof element === "string") { - const lcElement = transformCaseFunc(element) - if (lcElement !== element) { - // Config presets (e.g. tags.js, attrs.js) are immutable. - if (!isFrozen(array)) { - array[l] = lcElement - } - element = lcElement - } - } - set[element] = true - } - return set -} - -/** - * Clean up an array to harden against CSPP - * - * @param {Array} array - The array to be cleaned. - * @returns {Array} The cleaned version of the array - */ -function cleanArray(array) { - for (let index = 0; index < array.length; index++) { - const isPropertyExist = objectHasOwnProperty(array, index) - if (!isPropertyExist) { - array[index] = null - } - } - return array -} - -/** - * Shallow clone an object - * - * @param {Object} object - The object to be cloned. - * @returns {Object} A new object that copies the original. - */ -function clone(object) { - const newObject = create(null) - for (const [property, value] of entries(object)) { - const isPropertyExist = objectHasOwnProperty(object, property) - if (isPropertyExist) { - if (Array.isArray(value)) { - newObject[property] = cleanArray(value) - } else if ( - value && - typeof value === "object" && - value.constructor === Object - ) { - newObject[property] = clone(value) - } else { - newObject[property] = value - } - } - } - return newObject -} - -/** - * This method automatically checks if the prop is function or getter and behaves accordingly. - * - * @param {Object} object - The object to look up the getter function in its prototype chain. - * @param {String} prop - The property name for which to find the getter function. - * @returns {Function} The getter function found in the prototype chain or a fallback function. - */ -function lookupGetter(object, prop) { - while (object !== null) { - const desc = getOwnPropertyDescriptor(object, prop) - if (desc) { - if (desc.get) { - return unapply(desc.get) - } - if (typeof desc.value === "function") { - return unapply(desc.value) - } - } - object = getPrototypeOf(object) - } - function fallbackValue() { - return null - } - return fallbackValue -} - -const html$1 = freeze([ - "a", - "abbr", - "acronym", - "address", - "area", - "article", - "aside", - "audio", - "b", - "bdi", - "bdo", - "big", - "blink", - "blockquote", - "body", - "br", - "button", - "canvas", - "caption", - "center", - "cite", - "code", - "col", - "colgroup", - "content", - "data", - "datalist", - "dd", - "decorator", - "del", - "details", - "dfn", - "dialog", - "dir", - "div", - "dl", - "dt", - "element", - "em", - "fieldset", - "figcaption", - "figure", - "font", - "footer", - "form", - "h1", - "h2", - "h3", - "h4", - "h5", - "h6", - "head", - "header", - "hgroup", - "hr", - "html", - "i", - "img", - "input", - "ins", - "kbd", - "label", - "legend", - "li", - "main", - "map", - "mark", - "marquee", - "menu", - "menuitem", - "meter", - "nav", - "nobr", - "ol", - "optgroup", - "option", - "output", - "p", - "picture", - "pre", - "progress", - "q", - "rp", - "rt", - "ruby", - "s", - "samp", - "section", - "select", - "shadow", - "small", - "source", - "spacer", - "span", - "strike", - "strong", - "style", - "sub", - "summary", - "sup", - "table", - "tbody", - "td", - "template", - "textarea", - "tfoot", - "th", - "thead", - "time", - "tr", - "track", - "tt", - "u", - "ul", - "var", - "video", - "wbr", -]) - -// SVG -const svg$1 = freeze([ - "svg", - "a", - "altglyph", - "altglyphdef", - "altglyphitem", - "animatecolor", - "animatemotion", - "animatetransform", - "circle", - "clippath", - "defs", - "desc", - "ellipse", - "filter", - "font", - "g", - "glyph", - "glyphref", - "hkern", - "image", - "line", - "lineargradient", - "marker", - "mask", - "metadata", - "mpath", - "path", - "pattern", - "polygon", - "polyline", - "radialgradient", - "rect", - "stop", - "style", - "switch", - "symbol", - "text", - "textpath", - "title", - "tref", - "tspan", - "view", - "vkern", -]) -const svgFilters = freeze([ - "feBlend", - "feColorMatrix", - "feComponentTransfer", - "feComposite", - "feConvolveMatrix", - "feDiffuseLighting", - "feDisplacementMap", - "feDistantLight", - "feDropShadow", - "feFlood", - "feFuncA", - "feFuncB", - "feFuncG", - "feFuncR", - "feGaussianBlur", - "feImage", - "feMerge", - "feMergeNode", - "feMorphology", - "feOffset", - "fePointLight", - "feSpecularLighting", - "feSpotLight", - "feTile", - "feTurbulence", -]) - -// List of SVG elements that are disallowed by default. -// We still need to know them so that we can do namespace -// checks properly in case one wants to add them to -// allow-list. -const svgDisallowed = freeze([ - "animate", - "color-profile", - "cursor", - "discard", - "font-face", - "font-face-format", - "font-face-name", - "font-face-src", - "font-face-uri", - "foreignobject", - "hatch", - "hatchpath", - "mesh", - "meshgradient", - "meshpatch", - "meshrow", - "missing-glyph", - "script", - "set", - "solidcolor", - "unknown", - "use", -]) -const mathMl$1 = freeze([ - "math", - "menclose", - "merror", - "mfenced", - "mfrac", - "mglyph", - "mi", - "mlabeledtr", - "mmultiscripts", - "mn", - "mo", - "mover", - "mpadded", - "mphantom", - "mroot", - "mrow", - "ms", - "mspace", - "msqrt", - "mstyle", - "msub", - "msup", - "msubsup", - "mtable", - "mtd", - "mtext", - "mtr", - "munder", - "munderover", - "mprescripts", -]) - -// Similarly to SVG, we want to know all MathML elements, -// even those that we disallow by default. -const mathMlDisallowed = freeze([ - "maction", - "maligngroup", - "malignmark", - "mlongdiv", - "mscarries", - "mscarry", - "msgroup", - "mstack", - "msline", - "msrow", - "semantics", - "annotation", - "annotation-xml", - "mprescripts", - "none", -]) -const text = freeze(["#text"]) - -const html = freeze([ - "accept", - "action", - "align", - "alt", - "autocapitalize", - "autocomplete", - "autopictureinpicture", - "autoplay", - "background", - "bgcolor", - "border", - "capture", - "cellpadding", - "cellspacing", - "checked", - "cite", - "class", - "clear", - "color", - "cols", - "colspan", - "controls", - "controlslist", - "coords", - "crossorigin", - "datetime", - "decoding", - "default", - "dir", - "disabled", - "disablepictureinpicture", - "disableremoteplayback", - "download", - "draggable", - "enctype", - "enterkeyhint", - "face", - "for", - "headers", - "height", - "hidden", - "high", - "href", - "hreflang", - "id", - "inputmode", - "integrity", - "ismap", - "kind", - "label", - "lang", - "list", - "loading", - "loop", - "low", - "max", - "maxlength", - "media", - "method", - "min", - "minlength", - "multiple", - "muted", - "name", - "nonce", - "noshade", - "novalidate", - "nowrap", - "open", - "optimum", - "pattern", - "placeholder", - "playsinline", - "popover", - "popovertarget", - "popovertargetaction", - "poster", - "preload", - "pubdate", - "radiogroup", - "readonly", - "rel", - "required", - "rev", - "reversed", - "role", - "rows", - "rowspan", - "spellcheck", - "scope", - "selected", - "shape", - "size", - "sizes", - "span", - "srclang", - "start", - "src", - "srcset", - "step", - "style", - "summary", - "tabindex", - "title", - "translate", - "type", - "usemap", - "valign", - "value", - "width", - "wrap", - "xmlns", - "slot", -]) -const svg = freeze([ - "accent-height", - "accumulate", - "additive", - "alignment-baseline", - "ascent", - "attributename", - "attributetype", - "azimuth", - "basefrequency", - "baseline-shift", - "begin", - "bias", - "by", - "class", - "clip", - "clippathunits", - "clip-path", - "clip-rule", - "color", - "color-interpolation", - "color-interpolation-filters", - "color-profile", - "color-rendering", - "cx", - "cy", - "d", - "dx", - "dy", - "diffuseconstant", - "direction", - "display", - "divisor", - "dur", - "edgemode", - "elevation", - "end", - "fill", - "fill-opacity", - "fill-rule", - "filter", - "filterunits", - "flood-color", - "flood-opacity", - "font-family", - "font-size", - "font-size-adjust", - "font-stretch", - "font-style", - "font-variant", - "font-weight", - "fx", - "fy", - "g1", - "g2", - "glyph-name", - "glyphref", - "gradientunits", - "gradienttransform", - "height", - "href", - "id", - "image-rendering", - "in", - "in2", - "k", - "k1", - "k2", - "k3", - "k4", - "kerning", - "keypoints", - "keysplines", - "keytimes", - "lang", - "lengthadjust", - "letter-spacing", - "kernelmatrix", - "kernelunitlength", - "lighting-color", - "local", - "marker-end", - "marker-mid", - "marker-start", - "markerheight", - "markerunits", - "markerwidth", - "maskcontentunits", - "maskunits", - "max", - "mask", - "media", - "method", - "mode", - "min", - "name", - "numoctaves", - "offset", - "operator", - "opacity", - "order", - "orient", - "orientation", - "origin", - "overflow", - "paint-order", - "path", - "pathlength", - "patterncontentunits", - "patterntransform", - "patternunits", - "points", - "preservealpha", - "preserveaspectratio", - "primitiveunits", - "r", - "rx", - "ry", - "radius", - "refx", - "refy", - "repeatcount", - "repeatdur", - "restart", - "result", - "rotate", - "scale", - "seed", - "shape-rendering", - "specularconstant", - "specularexponent", - "spreadmethod", - "startoffset", - "stddeviation", - "stitchtiles", - "stop-color", - "stop-opacity", - "stroke-dasharray", - "stroke-dashoffset", - "stroke-linecap", - "stroke-linejoin", - "stroke-miterlimit", - "stroke-opacity", - "stroke", - "stroke-width", - "style", - "surfacescale", - "systemlanguage", - "tabindex", - "targetx", - "targety", - "transform", - "transform-origin", - "text-anchor", - "text-decoration", - "text-rendering", - "textlength", - "type", - "u1", - "u2", - "unicode", - "values", - "viewbox", - "visibility", - "version", - "vert-adv-y", - "vert-origin-x", - "vert-origin-y", - "width", - "word-spacing", - "wrap", - "writing-mode", - "xchannelselector", - "ychannelselector", - "x", - "x1", - "x2", - "xmlns", - "y", - "y1", - "y2", - "z", - "zoomandpan", -]) -const mathMl = freeze([ - "accent", - "accentunder", - "align", - "bevelled", - "close", - "columnsalign", - "columnlines", - "columnspan", - "denomalign", - "depth", - "dir", - "display", - "displaystyle", - "encoding", - "fence", - "frame", - "height", - "href", - "id", - "largeop", - "length", - "linethickness", - "lspace", - "lquote", - "mathbackground", - "mathcolor", - "mathsize", - "mathvariant", - "maxsize", - "minsize", - "movablelimits", - "notation", - "numalign", - "open", - "rowalign", - "rowlines", - "rowspacing", - "rowspan", - "rspace", - "rquote", - "scriptlevel", - "scriptminsize", - "scriptsizemultiplier", - "selection", - "separator", - "separators", - "stretchy", - "subscriptshift", - "supscriptshift", - "symmetric", - "voffset", - "width", - "xmlns", -]) -const xml = freeze([ - "xlink:href", - "xml:id", - "xlink:title", - "xml:space", - "xmlns:xlink", -]) - -// eslint-disable-next-line unicorn/better-regex -const MUSTACHE_EXPR = seal(/\{\{[\w\W]*|[\w\W]*\}\}/gm) // Specify template detection regex for SAFE_FOR_TEMPLATES mode -const ERB_EXPR = seal(/<%[\w\W]*|[\w\W]*%>/gm) -const TMPLIT_EXPR = seal(/\${[\w\W]*}/gm) -const DATA_ATTR = seal(/^data-[\-\w.\u00B7-\uFFFF]/) // eslint-disable-line no-useless-escape -const ARIA_ATTR = seal(/^aria-[\-\w]+$/) // eslint-disable-line no-useless-escape -const IS_ALLOWED_URI = seal( - /^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i, // eslint-disable-line no-useless-escape -) -const IS_SCRIPT_OR_DATA = seal(/^(?:\w+script|data):/i) -const ATTR_WHITESPACE = seal( - /[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g, // eslint-disable-line no-control-regex -) -const DOCTYPE_NAME = seal(/^html$/i) -const CUSTOM_ELEMENT = seal(/^[a-z][.\w]*(-[.\w]+)+$/i) - -var EXPRESSIONS = /*#__PURE__*/ Object.freeze({ - __proto__: null, - MUSTACHE_EXPR: MUSTACHE_EXPR, - ERB_EXPR: ERB_EXPR, - TMPLIT_EXPR: TMPLIT_EXPR, - DATA_ATTR: DATA_ATTR, - ARIA_ATTR: ARIA_ATTR, - IS_ALLOWED_URI: IS_ALLOWED_URI, - IS_SCRIPT_OR_DATA: IS_SCRIPT_OR_DATA, - ATTR_WHITESPACE: ATTR_WHITESPACE, - DOCTYPE_NAME: DOCTYPE_NAME, - CUSTOM_ELEMENT: CUSTOM_ELEMENT, -}) - -// https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType -const NODE_TYPE = { - element: 1, - attribute: 2, - text: 3, - cdataSection: 4, - entityReference: 5, - // Deprecated - entityNode: 6, - // Deprecated - progressingInstruction: 7, - comment: 8, - document: 9, - documentType: 10, - documentFragment: 11, - notation: 12, // Deprecated -} -const getGlobal = function getGlobal() { - return typeof window === "undefined" ? null : window -} - -/** - * Creates a no-op policy for internal use only. - * Don't export this function outside this module! - * @param {TrustedTypePolicyFactory} trustedTypes The policy factory. - * @param {HTMLScriptElement} purifyHostElement The Script element used to load DOMPurify (to determine policy name suffix). - * @return {TrustedTypePolicy} The policy created (or null, if Trusted Types - * are not supported or creating the policy failed). - */ -const _createTrustedTypesPolicy = function _createTrustedTypesPolicy( - trustedTypes, - purifyHostElement, -) { - if ( - typeof trustedTypes !== "object" || - typeof trustedTypes.createPolicy !== "function" - ) { - return null - } - - // Allow the callers to control the unique policy name - // by adding a data-tt-policy-suffix to the script element with the DOMPurify. - // Policy creation with duplicate names throws in Trusted Types. - let suffix = null - const ATTR_NAME = "data-tt-policy-suffix" - if (purifyHostElement && purifyHostElement.hasAttribute(ATTR_NAME)) { - suffix = purifyHostElement.getAttribute(ATTR_NAME) - } - const policyName = "dompurify" + (suffix ? "#" + suffix : "") - try { - return trustedTypes.createPolicy(policyName, { - createHTML(html) { - return html - }, - createScriptURL(scriptUrl) { - return scriptUrl - }, - }) - } catch (_) { - // Policy creation failed (most likely another DOMPurify script has - // already run). Skip creating the policy, as this will only cause errors - // if TT are enforced. - console.warn("TrustedTypes policy " + policyName + " could not be created.") - return null - } -} -function createDOMPurify() { - let window = - arguments.length > 0 && arguments[0] !== undefined - ? arguments[0] - : getGlobal() - const DOMPurify = (root) => createDOMPurify(root) - - /** - * Version label, exposed for easier checks - * if DOMPurify is up to date or not - */ - DOMPurify.version = "3.1.6" - - /** - * Array of elements that DOMPurify removed during sanitation. - * Empty if nothing was removed. - */ - DOMPurify.removed = [] - if ( - !window || - !window.document || - window.document.nodeType !== NODE_TYPE.document - ) { - // Not running in a browser, provide a factory function - // so that you can pass your own Window - DOMPurify.isSupported = false - return DOMPurify - } - let { document } = window - const originalDocument = document - const currentScript = originalDocument.currentScript - const { - DocumentFragment, - HTMLTemplateElement, - Node, - Element, - NodeFilter, - NamedNodeMap = window.NamedNodeMap || window.MozNamedAttrMap, - HTMLFormElement, - DOMParser, - trustedTypes, - } = window - const ElementPrototype = Element.prototype - const cloneNode = lookupGetter(ElementPrototype, "cloneNode") - const remove = lookupGetter(ElementPrototype, "remove") - const getNextSibling = lookupGetter(ElementPrototype, "nextSibling") - const getChildNodes = lookupGetter(ElementPrototype, "childNodes") - const getParentNode = lookupGetter(ElementPrototype, "parentNode") - - // As per issue #47, the web-components registry is inherited by a - // new document created via createHTMLDocument. As per the spec - // (http://w3c.github.io/webcomponents/spec/custom/#creating-and-passing-registries) - // a new empty registry is used when creating a template contents owner - // document, so we use that as our parent document to ensure nothing - // is inherited. - if (typeof HTMLTemplateElement === "function") { - const template = document.createElement("template") - if (template.content && template.content.ownerDocument) { - document = template.content.ownerDocument - } - } - let trustedTypesPolicy - let emptyHTML = "" - const { - implementation, - createNodeIterator, - createDocumentFragment, - getElementsByTagName, - } = document - const { importNode } = originalDocument - let hooks = {} - - /** - * Expose whether this browser supports running the full DOMPurify. - */ - DOMPurify.isSupported = - typeof entries === "function" && - typeof getParentNode === "function" && - implementation && - implementation.createHTMLDocument !== undefined - const { - MUSTACHE_EXPR, - ERB_EXPR, - TMPLIT_EXPR, - DATA_ATTR, - ARIA_ATTR, - IS_SCRIPT_OR_DATA, - ATTR_WHITESPACE, - CUSTOM_ELEMENT, - } = EXPRESSIONS - let { IS_ALLOWED_URI: IS_ALLOWED_URI$1 } = EXPRESSIONS - - /** - * We consider the elements and attributes below to be safe. Ideally - * don't add any new ones but feel free to remove unwanted ones. - */ - - /* allowed element names */ - let ALLOWED_TAGS = null - const DEFAULT_ALLOWED_TAGS = addToSet({}, [ - ...html$1, - ...svg$1, - ...svgFilters, - ...mathMl$1, - ...text, - ]) - - /* Allowed attribute names */ - let ALLOWED_ATTR = null - const DEFAULT_ALLOWED_ATTR = addToSet({}, [ - ...html, - ...svg, - ...mathMl, - ...xml, - ]) - - /* - * Configure how DOMPUrify should handle custom elements and their attributes as well as customized built-in elements. - * @property {RegExp|Function|null} tagNameCheck one of [null, regexPattern, predicate]. Default: `null` (disallow any custom elements) - * @property {RegExp|Function|null} attributeNameCheck one of [null, regexPattern, predicate]. Default: `null` (disallow any attributes not on the allow list) - * @property {boolean} allowCustomizedBuiltInElements allow custom elements derived from built-ins if they pass CUSTOM_ELEMENT_HANDLING.tagNameCheck. Default: `false`. - */ - let CUSTOM_ELEMENT_HANDLING = Object.seal( - create(null, { - tagNameCheck: { - writable: true, - configurable: false, - enumerable: true, - value: null, - }, - attributeNameCheck: { - writable: true, - configurable: false, - enumerable: true, - value: null, - }, - allowCustomizedBuiltInElements: { - writable: true, - configurable: false, - enumerable: true, - value: false, - }, - }), - ) - - /* Explicitly forbidden tags (overrides ALLOWED_TAGS/ADD_TAGS) */ - let FORBID_TAGS = null - - /* Explicitly forbidden attributes (overrides ALLOWED_ATTR/ADD_ATTR) */ - let FORBID_ATTR = null - - /* Decide if ARIA attributes are okay */ - let ALLOW_ARIA_ATTR = true - - /* Decide if custom data attributes are okay */ - let ALLOW_DATA_ATTR = true - - /* Decide if unknown protocols are okay */ - let ALLOW_UNKNOWN_PROTOCOLS = false - - /* Decide if self-closing tags in attributes are allowed. - * Usually removed due to a mXSS issue in jQuery 3.0 */ - let ALLOW_SELF_CLOSE_IN_ATTR = true - - /* Output should be safe for common template engines. - * This means, DOMPurify removes data attributes, mustaches and ERB - */ - let SAFE_FOR_TEMPLATES = false - - /* Output should be safe even for XML used within HTML and alike. - * This means, DOMPurify removes comments when containing risky content. - */ - let SAFE_FOR_XML = true - - /* Decide if document with <html>... should be returned */ - let WHOLE_DOCUMENT = false - - /* Track whether config is already set on this instance of DOMPurify. */ - let SET_CONFIG = false - - /* Decide if all elements (e.g. style, script) must be children of - * document.body. By default, browsers might move them to document.head */ - let FORCE_BODY = false - - /* Decide if a DOM `HTMLBodyElement` should be returned, instead of a html - * string (or a TrustedHTML object if Trusted Types are supported). - * If `WHOLE_DOCUMENT` is enabled a `HTMLHtmlElement` will be returned instead - */ - let RETURN_DOM = false - - /* Decide if a DOM `DocumentFragment` should be returned, instead of a html - * string (or a TrustedHTML object if Trusted Types are supported) */ - let RETURN_DOM_FRAGMENT = false - - /* Try to return a Trusted Type object instead of a string, return a string in - * case Trusted Types are not supported */ - let RETURN_TRUSTED_TYPE = false - - /* Output should be free from DOM clobbering attacks? - * This sanitizes markups named with colliding, clobberable built-in DOM APIs. - */ - let SANITIZE_DOM = true - - /* Achieve full DOM Clobbering protection by isolating the namespace of named - * properties and JS variables, mitigating attacks that abuse the HTML/DOM spec rules. - * - * HTML/DOM spec rules that enable DOM Clobbering: - * - Named Access on Window (§7.3.3) - * - DOM Tree Accessors (§3.1.5) - * - Form Element Parent-Child Relations (§4.10.3) - * - Iframe srcdoc / Nested WindowProxies (§4.8.5) - * - HTMLCollection (§4.2.10.2) - * - * Namespace isolation is implemented by prefixing `id` and `name` attributes - * with a constant string, i.e., `user-content-` - */ - let SANITIZE_NAMED_PROPS = false - const SANITIZE_NAMED_PROPS_PREFIX = "user-content-" - - /* Keep element content when removing element? */ - let KEEP_CONTENT = true - - /* If a `Node` is passed to sanitize(), then performs sanitization in-place instead - * of importing it into a new Document and returning a sanitized copy */ - let IN_PLACE = false - - /* Allow usage of profiles like html, svg and mathMl */ - let USE_PROFILES = {} - - /* Tags to ignore content of when KEEP_CONTENT is true */ - let FORBID_CONTENTS = null - const DEFAULT_FORBID_CONTENTS = addToSet({}, [ - "annotation-xml", - "audio", - "colgroup", - "desc", - "foreignobject", - "head", - "iframe", - "math", - "mi", - "mn", - "mo", - "ms", - "mtext", - "noembed", - "noframes", - "noscript", - "plaintext", - "script", - "style", - "svg", - "template", - "thead", - "title", - "video", - "xmp", - ]) - - /* Tags that are safe for data: URIs */ - let DATA_URI_TAGS = null - const DEFAULT_DATA_URI_TAGS = addToSet({}, [ - "audio", - "video", - "img", - "source", - "image", - "track", - ]) - - /* Attributes safe for values like "javascript:" */ - let URI_SAFE_ATTRIBUTES = null - const DEFAULT_URI_SAFE_ATTRIBUTES = addToSet({}, [ - "alt", - "class", - "for", - "id", - "label", - "name", - "pattern", - "placeholder", - "role", - "summary", - "title", - "value", - "style", - "xmlns", - ]) - const MATHML_NAMESPACE = "http://www.w3.org/1998/Math/MathML" - const SVG_NAMESPACE = "http://www.w3.org/2000/svg" - const HTML_NAMESPACE = "http://www.w3.org/1999/xhtml" - /* Document namespace */ - let NAMESPACE = HTML_NAMESPACE - let IS_EMPTY_INPUT = false - - /* Allowed XHTML+XML namespaces */ - let ALLOWED_NAMESPACES = null - const DEFAULT_ALLOWED_NAMESPACES = addToSet( - {}, - [MATHML_NAMESPACE, SVG_NAMESPACE, HTML_NAMESPACE], - stringToString, - ) - - /* Parsing of strict XHTML documents */ - let PARSER_MEDIA_TYPE = null - const SUPPORTED_PARSER_MEDIA_TYPES = ["application/xhtml+xml", "text/html"] - const DEFAULT_PARSER_MEDIA_TYPE = "text/html" - let transformCaseFunc = null - - /* Keep a reference to config to pass to hooks */ - let CONFIG = null - - /* Ideally, do not touch anything below this line */ - /* ______________________________________________ */ - - const formElement = document.createElement("form") - const isRegexOrFunction = function isRegexOrFunction(testValue) { - return testValue instanceof RegExp || testValue instanceof Function - } - - /** - * _parseConfig - * - * @param {Object} cfg optional config literal - */ - // eslint-disable-next-line complexity - const _parseConfig = function _parseConfig() { - let cfg = - arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {} - if (CONFIG && CONFIG === cfg) { - return - } - - /* Shield configuration object from tampering */ - if (!cfg || typeof cfg !== "object") { - cfg = {} - } - - /* Shield configuration object from prototype pollution */ - cfg = clone(cfg) - PARSER_MEDIA_TYPE = - // eslint-disable-next-line unicorn/prefer-includes - SUPPORTED_PARSER_MEDIA_TYPES.indexOf(cfg.PARSER_MEDIA_TYPE) === -1 - ? DEFAULT_PARSER_MEDIA_TYPE - : cfg.PARSER_MEDIA_TYPE - - // HTML tags and attributes are not case-sensitive, converting to lowercase. Keeping XHTML as is. - transformCaseFunc = - PARSER_MEDIA_TYPE === "application/xhtml+xml" - ? stringToString - : stringToLowerCase - - /* Set configuration parameters */ - ALLOWED_TAGS = objectHasOwnProperty(cfg, "ALLOWED_TAGS") - ? addToSet({}, cfg.ALLOWED_TAGS, transformCaseFunc) - : DEFAULT_ALLOWED_TAGS - ALLOWED_ATTR = objectHasOwnProperty(cfg, "ALLOWED_ATTR") - ? addToSet({}, cfg.ALLOWED_ATTR, transformCaseFunc) - : DEFAULT_ALLOWED_ATTR - ALLOWED_NAMESPACES = objectHasOwnProperty(cfg, "ALLOWED_NAMESPACES") - ? addToSet({}, cfg.ALLOWED_NAMESPACES, stringToString) - : DEFAULT_ALLOWED_NAMESPACES - URI_SAFE_ATTRIBUTES = objectHasOwnProperty(cfg, "ADD_URI_SAFE_ATTR") - ? addToSet( - clone(DEFAULT_URI_SAFE_ATTRIBUTES), - // eslint-disable-line indent - cfg.ADD_URI_SAFE_ATTR, - // eslint-disable-line indent - transformCaseFunc, // eslint-disable-line indent - ) // eslint-disable-line indent - : DEFAULT_URI_SAFE_ATTRIBUTES - DATA_URI_TAGS = objectHasOwnProperty(cfg, "ADD_DATA_URI_TAGS") - ? addToSet( - clone(DEFAULT_DATA_URI_TAGS), - // eslint-disable-line indent - cfg.ADD_DATA_URI_TAGS, - // eslint-disable-line indent - transformCaseFunc, // eslint-disable-line indent - ) // eslint-disable-line indent - : DEFAULT_DATA_URI_TAGS - FORBID_CONTENTS = objectHasOwnProperty(cfg, "FORBID_CONTENTS") - ? addToSet({}, cfg.FORBID_CONTENTS, transformCaseFunc) - : DEFAULT_FORBID_CONTENTS - FORBID_TAGS = objectHasOwnProperty(cfg, "FORBID_TAGS") - ? addToSet({}, cfg.FORBID_TAGS, transformCaseFunc) - : {} - FORBID_ATTR = objectHasOwnProperty(cfg, "FORBID_ATTR") - ? addToSet({}, cfg.FORBID_ATTR, transformCaseFunc) - : {} - USE_PROFILES = objectHasOwnProperty(cfg, "USE_PROFILES") - ? cfg.USE_PROFILES - : false - ALLOW_ARIA_ATTR = cfg.ALLOW_ARIA_ATTR !== false // Default true - ALLOW_DATA_ATTR = cfg.ALLOW_DATA_ATTR !== false // Default true - ALLOW_UNKNOWN_PROTOCOLS = cfg.ALLOW_UNKNOWN_PROTOCOLS || false // Default false - ALLOW_SELF_CLOSE_IN_ATTR = cfg.ALLOW_SELF_CLOSE_IN_ATTR !== false // Default true - SAFE_FOR_TEMPLATES = cfg.SAFE_FOR_TEMPLATES || false // Default false - SAFE_FOR_XML = cfg.SAFE_FOR_XML !== false // Default true - WHOLE_DOCUMENT = cfg.WHOLE_DOCUMENT || false // Default false - RETURN_DOM = cfg.RETURN_DOM || false // Default false - RETURN_DOM_FRAGMENT = cfg.RETURN_DOM_FRAGMENT || false // Default false - RETURN_TRUSTED_TYPE = cfg.RETURN_TRUSTED_TYPE || false // Default false - FORCE_BODY = cfg.FORCE_BODY || false // Default false - SANITIZE_DOM = cfg.SANITIZE_DOM !== false // Default true - SANITIZE_NAMED_PROPS = cfg.SANITIZE_NAMED_PROPS || false // Default false - KEEP_CONTENT = cfg.KEEP_CONTENT !== false // Default true - IN_PLACE = cfg.IN_PLACE || false // Default false - IS_ALLOWED_URI$1 = cfg.ALLOWED_URI_REGEXP || IS_ALLOWED_URI - NAMESPACE = cfg.NAMESPACE || HTML_NAMESPACE - CUSTOM_ELEMENT_HANDLING = cfg.CUSTOM_ELEMENT_HANDLING || {} - if ( - cfg.CUSTOM_ELEMENT_HANDLING && - isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck) - ) { - CUSTOM_ELEMENT_HANDLING.tagNameCheck = - cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck - } - if ( - cfg.CUSTOM_ELEMENT_HANDLING && - isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck) - ) { - CUSTOM_ELEMENT_HANDLING.attributeNameCheck = - cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck - } - if ( - cfg.CUSTOM_ELEMENT_HANDLING && - typeof cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements === - "boolean" - ) { - CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements = - cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements - } - if (SAFE_FOR_TEMPLATES) { - ALLOW_DATA_ATTR = false - } - if (RETURN_DOM_FRAGMENT) { - RETURN_DOM = true - } - - /* Parse profile info */ - if (USE_PROFILES) { - ALLOWED_TAGS = addToSet({}, text) - ALLOWED_ATTR = [] - if (USE_PROFILES.html === true) { - addToSet(ALLOWED_TAGS, html$1) - addToSet(ALLOWED_ATTR, html) - } - if (USE_PROFILES.svg === true) { - addToSet(ALLOWED_TAGS, svg$1) - addToSet(ALLOWED_ATTR, svg) - addToSet(ALLOWED_ATTR, xml) - } - if (USE_PROFILES.svgFilters === true) { - addToSet(ALLOWED_TAGS, svgFilters) - addToSet(ALLOWED_ATTR, svg) - addToSet(ALLOWED_ATTR, xml) - } - if (USE_PROFILES.mathMl === true) { - addToSet(ALLOWED_TAGS, mathMl$1) - addToSet(ALLOWED_ATTR, mathMl) - addToSet(ALLOWED_ATTR, xml) - } - } - - /* Merge configuration parameters */ - if (cfg.ADD_TAGS) { - if (ALLOWED_TAGS === DEFAULT_ALLOWED_TAGS) { - ALLOWED_TAGS = clone(ALLOWED_TAGS) - } - addToSet(ALLOWED_TAGS, cfg.ADD_TAGS, transformCaseFunc) - } - if (cfg.ADD_ATTR) { - if (ALLOWED_ATTR === DEFAULT_ALLOWED_ATTR) { - ALLOWED_ATTR = clone(ALLOWED_ATTR) - } - addToSet(ALLOWED_ATTR, cfg.ADD_ATTR, transformCaseFunc) - } - if (cfg.ADD_URI_SAFE_ATTR) { - addToSet(URI_SAFE_ATTRIBUTES, cfg.ADD_URI_SAFE_ATTR, transformCaseFunc) - } - if (cfg.FORBID_CONTENTS) { - if (FORBID_CONTENTS === DEFAULT_FORBID_CONTENTS) { - FORBID_CONTENTS = clone(FORBID_CONTENTS) - } - addToSet(FORBID_CONTENTS, cfg.FORBID_CONTENTS, transformCaseFunc) - } - - /* Add #text in case KEEP_CONTENT is set to true */ - if (KEEP_CONTENT) { - ALLOWED_TAGS["#text"] = true - } - - /* Add html, head and body to ALLOWED_TAGS in case WHOLE_DOCUMENT is true */ - if (WHOLE_DOCUMENT) { - addToSet(ALLOWED_TAGS, ["html", "head", "body"]) - } - - /* Add tbody to ALLOWED_TAGS in case tables are permitted, see #286, #365 */ - if (ALLOWED_TAGS.table) { - addToSet(ALLOWED_TAGS, ["tbody"]) - delete FORBID_TAGS.tbody - } - if (cfg.TRUSTED_TYPES_POLICY) { - if (typeof cfg.TRUSTED_TYPES_POLICY.createHTML !== "function") { - throw typeErrorCreate( - 'TRUSTED_TYPES_POLICY configuration option must provide a "createHTML" hook.', - ) - } - if (typeof cfg.TRUSTED_TYPES_POLICY.createScriptURL !== "function") { - throw typeErrorCreate( - 'TRUSTED_TYPES_POLICY configuration option must provide a "createScriptURL" hook.', - ) - } - - // Overwrite existing TrustedTypes policy. - trustedTypesPolicy = cfg.TRUSTED_TYPES_POLICY - - // Sign local variables required by `sanitize`. - emptyHTML = trustedTypesPolicy.createHTML("") - } else { - // Uninitialized policy, attempt to initialize the internal dompurify policy. - if (trustedTypesPolicy === undefined) { - trustedTypesPolicy = _createTrustedTypesPolicy( - trustedTypes, - currentScript, - ) - } - - // If creating the internal policy succeeded sign internal variables. - if (trustedTypesPolicy !== null && typeof emptyHTML === "string") { - emptyHTML = trustedTypesPolicy.createHTML("") - } - } - - // Prevent further manipulation of configuration. - // Not available in IE8, Safari 5, etc. - if (freeze) { - freeze(cfg) - } - CONFIG = cfg - } - const MATHML_TEXT_INTEGRATION_POINTS = addToSet({}, [ - "mi", - "mo", - "mn", - "ms", - "mtext", - ]) - const HTML_INTEGRATION_POINTS = addToSet({}, [ - "foreignobject", - "annotation-xml", - ]) - - // Certain elements are allowed in both SVG and HTML - // namespace. We need to specify them explicitly - // so that they don't get erroneously deleted from - // HTML namespace. - const COMMON_SVG_AND_HTML_ELEMENTS = addToSet({}, [ - "title", - "style", - "font", - "a", - "script", - ]) - - /* Keep track of all possible SVG and MathML tags - * so that we can perform the namespace checks - * correctly. */ - const ALL_SVG_TAGS = addToSet({}, [...svg$1, ...svgFilters, ...svgDisallowed]) - const ALL_MATHML_TAGS = addToSet({}, [...mathMl$1, ...mathMlDisallowed]) - - /** - * @param {Element} element a DOM element whose namespace is being checked - * @returns {boolean} Return false if the element has a - * namespace that a spec-compliant parser would never - * return. Return true otherwise. - */ - const _checkValidNamespace = function _checkValidNamespace(element) { - let parent = getParentNode(element) - - // In JSDOM, if we're inside shadow DOM, then parentNode - // can be null. We just simulate parent in this case. - if (!parent || !parent.tagName) { - parent = { - namespaceURI: NAMESPACE, - tagName: "template", - } - } - const tagName = stringToLowerCase(element.tagName) - const parentTagName = stringToLowerCase(parent.tagName) - if (!ALLOWED_NAMESPACES[element.namespaceURI]) { - return false - } - if (element.namespaceURI === SVG_NAMESPACE) { - // The only way to switch from HTML namespace to SVG - // is via <svg>. If it happens via any other tag, then - // it should be killed. - if (parent.namespaceURI === HTML_NAMESPACE) { - return tagName === "svg" - } - - // The only way to switch from MathML to SVG is via` - // svg if parent is either <annotation-xml> or MathML - // text integration points. - if (parent.namespaceURI === MATHML_NAMESPACE) { - return ( - tagName === "svg" && - (parentTagName === "annotation-xml" || - MATHML_TEXT_INTEGRATION_POINTS[parentTagName]) - ) - } - - // We only allow elements that are defined in SVG - // spec. All others are disallowed in SVG namespace. - return Boolean(ALL_SVG_TAGS[tagName]) - } - if (element.namespaceURI === MATHML_NAMESPACE) { - // The only way to switch from HTML namespace to MathML - // is via <math>. If it happens via any other tag, then - // it should be killed. - if (parent.namespaceURI === HTML_NAMESPACE) { - return tagName === "math" - } - - // The only way to switch from SVG to MathML is via - // <math> and HTML integration points - if (parent.namespaceURI === SVG_NAMESPACE) { - return tagName === "math" && HTML_INTEGRATION_POINTS[parentTagName] - } - - // We only allow elements that are defined in MathML - // spec. All others are disallowed in MathML namespace. - return Boolean(ALL_MATHML_TAGS[tagName]) - } - if (element.namespaceURI === HTML_NAMESPACE) { - // The only way to switch from SVG to HTML is via - // HTML integration points, and from MathML to HTML - // is via MathML text integration points - if ( - parent.namespaceURI === SVG_NAMESPACE && - !HTML_INTEGRATION_POINTS[parentTagName] - ) { - return false - } - if ( - parent.namespaceURI === MATHML_NAMESPACE && - !MATHML_TEXT_INTEGRATION_POINTS[parentTagName] - ) { - return false - } - - // We disallow tags that are specific for MathML - // or SVG and should never appear in HTML namespace - return ( - !ALL_MATHML_TAGS[tagName] && - (COMMON_SVG_AND_HTML_ELEMENTS[tagName] || !ALL_SVG_TAGS[tagName]) - ) - } - - // For XHTML and XML documents that support custom namespaces - if ( - PARSER_MEDIA_TYPE === "application/xhtml+xml" && - ALLOWED_NAMESPACES[element.namespaceURI] - ) { - return true - } - - // The code should never reach this place (this means - // that the element somehow got namespace that is not - // HTML, SVG, MathML or allowed via ALLOWED_NAMESPACES). - // Return false just in case. - return false - } - - /** - * _forceRemove - * - * @param {Node} node a DOM node - */ - const _forceRemove = function _forceRemove(node) { - arrayPush(DOMPurify.removed, { - element: node, - }) - try { - // eslint-disable-next-line unicorn/prefer-dom-node-remove - getParentNode(node).removeChild(node) - } catch (_) { - remove(node) - } - } - - /** - * _removeAttribute - * - * @param {String} name an Attribute name - * @param {Node} node a DOM node - */ - const _removeAttribute = function _removeAttribute(name, node) { - try { - arrayPush(DOMPurify.removed, { - attribute: node.getAttributeNode(name), - from: node, - }) - } catch (_) { - arrayPush(DOMPurify.removed, { - attribute: null, - from: node, - }) - } - node.removeAttribute(name) - - // We void attribute values for unremovable "is"" attributes - if (name === "is" && !ALLOWED_ATTR[name]) { - if (RETURN_DOM || RETURN_DOM_FRAGMENT) { - try { - _forceRemove(node) - } catch (_) {} - } else { - try { - node.setAttribute(name, "") - } catch (_) {} - } - } - } - - /** - * _initDocument - * - * @param {String} dirty a string of dirty markup - * @return {Document} a DOM, filled with the dirty markup - */ - const _initDocument = function _initDocument(dirty) { - /* Create a HTML document */ - let doc = null - let leadingWhitespace = null - if (FORCE_BODY) { - dirty = "<remove></remove>" + dirty - } else { - /* If FORCE_BODY isn't used, leading whitespace needs to be preserved manually */ - const matches = stringMatch(dirty, /^[\r\n\t ]+/) - leadingWhitespace = matches && matches[0] - } - if ( - PARSER_MEDIA_TYPE === "application/xhtml+xml" && - NAMESPACE === HTML_NAMESPACE - ) { - // Root of XHTML doc must contain xmlns declaration (see https://www.w3.org/TR/xhtml1/normative.html#strict) - dirty = - '<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body>' + - dirty + - "</body></html>" - } - const dirtyPayload = trustedTypesPolicy - ? trustedTypesPolicy.createHTML(dirty) - : dirty - /* - * Use the DOMParser API by default, fallback later if needs be - * DOMParser not work for svg when has multiple root element. - */ - if (NAMESPACE === HTML_NAMESPACE) { - try { - doc = new DOMParser().parseFromString(dirtyPayload, PARSER_MEDIA_TYPE) - } catch (_) {} - } - - /* Use createHTMLDocument in case DOMParser is not available */ - if (!doc || !doc.documentElement) { - doc = implementation.createDocument(NAMESPACE, "template", null) - try { - doc.documentElement.innerHTML = IS_EMPTY_INPUT - ? emptyHTML - : dirtyPayload - } catch (_) { - // Syntax error if dirtyPayload is invalid xml - } - } - const body = doc.body || doc.documentElement - if (dirty && leadingWhitespace) { - body.insertBefore( - document.createTextNode(leadingWhitespace), - body.childNodes[0] || null, - ) - } - - /* Work on whole document or just its body */ - if (NAMESPACE === HTML_NAMESPACE) { - return getElementsByTagName.call(doc, WHOLE_DOCUMENT ? "html" : "body")[0] - } - return WHOLE_DOCUMENT ? doc.documentElement : body - } - - /** - * Creates a NodeIterator object that you can use to traverse filtered lists of nodes or elements in a document. - * - * @param {Node} root The root element or node to start traversing on. - * @return {NodeIterator} The created NodeIterator - */ - const _createNodeIterator = function _createNodeIterator(root) { - return createNodeIterator.call( - root.ownerDocument || root, - root, - // eslint-disable-next-line no-bitwise - NodeFilter.SHOW_ELEMENT | - NodeFilter.SHOW_COMMENT | - NodeFilter.SHOW_TEXT | - NodeFilter.SHOW_PROCESSING_INSTRUCTION | - NodeFilter.SHOW_CDATA_SECTION, - null, - ) - } - - /** - * _isClobbered - * - * @param {Node} elm element to check for clobbering attacks - * @return {Boolean} true if clobbered, false if safe - */ - const _isClobbered = function _isClobbered(elm) { - return ( - elm instanceof HTMLFormElement && - (typeof elm.nodeName !== "string" || - typeof elm.textContent !== "string" || - typeof elm.removeChild !== "function" || - !(elm.attributes instanceof NamedNodeMap) || - typeof elm.removeAttribute !== "function" || - typeof elm.setAttribute !== "function" || - typeof elm.namespaceURI !== "string" || - typeof elm.insertBefore !== "function" || - typeof elm.hasChildNodes !== "function") - ) - } - - /** - * Checks whether the given object is a DOM node. - * - * @param {Node} object object to check whether it's a DOM node - * @return {Boolean} true is object is a DOM node - */ - const _isNode = function _isNode(object) { - return typeof Node === "function" && object instanceof Node - } - - /** - * _executeHook - * Execute user configurable hooks - * - * @param {String} entryPoint Name of the hook's entry point - * @param {Node} currentNode node to work on with the hook - * @param {Object} data additional hook parameters - */ - const _executeHook = function _executeHook(entryPoint, currentNode, data) { - if (!hooks[entryPoint]) { - return - } - arrayForEach(hooks[entryPoint], (hook) => { - hook.call(DOMPurify, currentNode, data, CONFIG) - }) - } - - /** - * _sanitizeElements - * - * @protect nodeName - * @protect textContent - * @protect removeChild - * - * @param {Node} currentNode to check for permission to exist - * @return {Boolean} true if node was killed, false if left alive - */ - const _sanitizeElements = function _sanitizeElements(currentNode) { - let content = null - - /* Execute a hook if present */ - _executeHook("beforeSanitizeElements", currentNode, null) - - /* Check if element is clobbered or can clobber */ - if (_isClobbered(currentNode)) { - _forceRemove(currentNode) - return true - } - - /* Now let's check the element's type and name */ - const tagName = transformCaseFunc(currentNode.nodeName) - - /* Execute a hook if present */ - _executeHook("uponSanitizeElement", currentNode, { - tagName, - allowedTags: ALLOWED_TAGS, - }) - - /* Detect mXSS attempts abusing namespace confusion */ - if ( - currentNode.hasChildNodes() && - !_isNode(currentNode.firstElementChild) && - regExpTest(/<[/\w]/g, currentNode.innerHTML) && - regExpTest(/<[/\w]/g, currentNode.textContent) - ) { - _forceRemove(currentNode) - return true - } - - /* Remove any occurrence of processing instructions */ - if (currentNode.nodeType === NODE_TYPE.progressingInstruction) { - _forceRemove(currentNode) - return true - } - - /* Remove any kind of possibly harmful comments */ - if ( - SAFE_FOR_XML && - currentNode.nodeType === NODE_TYPE.comment && - regExpTest(/<[/\w]/g, currentNode.data) - ) { - _forceRemove(currentNode) - return true - } - - /* Remove element if anything forbids its presence */ - if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) { - /* Check if we have a custom element to handle */ - if (!FORBID_TAGS[tagName] && _isBasicCustomElement(tagName)) { - if ( - CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && - regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, tagName) - ) { - return false - } - if ( - CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && - CUSTOM_ELEMENT_HANDLING.tagNameCheck(tagName) - ) { - return false - } - } - - /* Keep content except for bad-listed elements */ - if (KEEP_CONTENT && !FORBID_CONTENTS[tagName]) { - const parentNode = getParentNode(currentNode) || currentNode.parentNode - const childNodes = getChildNodes(currentNode) || currentNode.childNodes - if (childNodes && parentNode) { - const childCount = childNodes.length - for (let i = childCount - 1; i >= 0; --i) { - const childClone = cloneNode(childNodes[i], true) - childClone.__removalCount = (currentNode.__removalCount || 0) + 1 - parentNode.insertBefore(childClone, getNextSibling(currentNode)) - } - } - } - _forceRemove(currentNode) - return true - } - - /* Check whether element has a valid namespace */ - if (currentNode instanceof Element && !_checkValidNamespace(currentNode)) { - _forceRemove(currentNode) - return true - } - - /* Make sure that older browsers don't get fallback-tag mXSS */ - if ( - (tagName === "noscript" || - tagName === "noembed" || - tagName === "noframes") && - regExpTest(/<\/no(script|embed|frames)/i, currentNode.innerHTML) - ) { - _forceRemove(currentNode) - return true - } - - /* Sanitize element content to be template-safe */ - if (SAFE_FOR_TEMPLATES && currentNode.nodeType === NODE_TYPE.text) { - /* Get the element's text content */ - content = currentNode.textContent - arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], (expr) => { - content = stringReplace(content, expr, " ") - }) - if (currentNode.textContent !== content) { - arrayPush(DOMPurify.removed, { - element: currentNode.cloneNode(), - }) - currentNode.textContent = content - } - } - - /* Execute a hook if present */ - _executeHook("afterSanitizeElements", currentNode, null) - return false - } - - /** - * _isValidAttribute - * - * @param {string} lcTag Lowercase tag name of containing element. - * @param {string} lcName Lowercase attribute name. - * @param {string} value Attribute value. - * @return {Boolean} Returns true if `value` is valid, otherwise false. - */ - // eslint-disable-next-line complexity - const _isValidAttribute = function _isValidAttribute(lcTag, lcName, value) { - /* Make sure attribute cannot clobber */ - if ( - SANITIZE_DOM && - (lcName === "id" || lcName === "name") && - (value in document || value in formElement) - ) { - return false - } - - /* Allow valid data-* attributes: At least one character after "-" - (https://html.spec.whatwg.org/multipage/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes) - XML-compatible (https://html.spec.whatwg.org/multipage/infrastructure.html#xml-compatible and http://www.w3.org/TR/xml/#d0e804) - We don't need to check the value; it's always URI safe. */ - if ( - ALLOW_DATA_ATTR && - !FORBID_ATTR[lcName] && - regExpTest(DATA_ATTR, lcName) - ); - else if (ALLOW_ARIA_ATTR && regExpTest(ARIA_ATTR, lcName)); - else if (!ALLOWED_ATTR[lcName] || FORBID_ATTR[lcName]) { - if ( - // First condition does a very basic check if a) it's basically a valid custom element tagname AND - // b) if the tagName passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.tagNameCheck - // and c) if the attribute name passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.attributeNameCheck - (_isBasicCustomElement(lcTag) && - ((CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && - regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, lcTag)) || - (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && - CUSTOM_ELEMENT_HANDLING.tagNameCheck(lcTag))) && - ((CUSTOM_ELEMENT_HANDLING.attributeNameCheck instanceof RegExp && - regExpTest(CUSTOM_ELEMENT_HANDLING.attributeNameCheck, lcName)) || - (CUSTOM_ELEMENT_HANDLING.attributeNameCheck instanceof Function && - CUSTOM_ELEMENT_HANDLING.attributeNameCheck(lcName)))) || - // Alternative, second condition checks if it's an `is`-attribute, AND - // the value passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.tagNameCheck - (lcName === "is" && - CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements && - ((CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && - regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, value)) || - (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && - CUSTOM_ELEMENT_HANDLING.tagNameCheck(value)))) - ); - else { - return false - } - /* Check value is safe. First, is attr inert? If so, is safe */ - } else if (URI_SAFE_ATTRIBUTES[lcName]); - else if ( - regExpTest(IS_ALLOWED_URI$1, stringReplace(value, ATTR_WHITESPACE, "")) - ); - else if ( - (lcName === "src" || lcName === "xlink:href" || lcName === "href") && - lcTag !== "script" && - stringIndexOf(value, "data:") === 0 && - DATA_URI_TAGS[lcTag] - ); - else if ( - ALLOW_UNKNOWN_PROTOCOLS && - !regExpTest(IS_SCRIPT_OR_DATA, stringReplace(value, ATTR_WHITESPACE, "")) - ); - else if (value) { - return false - } else; - return true - } - - /** - * _isBasicCustomElement - * checks if at least one dash is included in tagName, and it's not the first char - * for more sophisticated checking see https://github.com/sindresorhus/validate-element-name - * - * @param {string} tagName name of the tag of the node to sanitize - * @returns {boolean} Returns true if the tag name meets the basic criteria for a custom element, otherwise false. - */ - const _isBasicCustomElement = function _isBasicCustomElement(tagName) { - return tagName !== "annotation-xml" && stringMatch(tagName, CUSTOM_ELEMENT) - } - - /** - * _sanitizeAttributes - * - * @protect attributes - * @protect nodeName - * @protect removeAttribute - * @protect setAttribute - * - * @param {Node} currentNode to sanitize - */ - const _sanitizeAttributes = function _sanitizeAttributes(currentNode) { - /* Execute a hook if present */ - _executeHook("beforeSanitizeAttributes", currentNode, null) - const { attributes } = currentNode - - /* Check if we have attributes; if not we might have a text node */ - if (!attributes) { - return - } - const hookEvent = { - attrName: "", - attrValue: "", - keepAttr: true, - allowedAttributes: ALLOWED_ATTR, - } - let l = attributes.length - - /* Go backwards over all attributes; safely remove bad ones */ - while (l--) { - const attr = attributes[l] - const { name, namespaceURI, value: attrValue } = attr - const lcName = transformCaseFunc(name) - let value = name === "value" ? attrValue : stringTrim(attrValue) - - /* Execute a hook if present */ - hookEvent.attrName = lcName - hookEvent.attrValue = value - hookEvent.keepAttr = true - hookEvent.forceKeepAttr = undefined // Allows developers to see this is a property they can set - _executeHook("uponSanitizeAttribute", currentNode, hookEvent) - value = hookEvent.attrValue - - /* Work around a security issue with comments inside attributes */ - if (SAFE_FOR_XML && regExpTest(/((--!?|])>)|<\/(style|title)/i, value)) { - _removeAttribute(name, currentNode) - continue - } - - /* Did the hooks approve of the attribute? */ - if (hookEvent.forceKeepAttr) { - continue - } - - /* Remove attribute */ - _removeAttribute(name, currentNode) - - /* Did the hooks approve of the attribute? */ - if (!hookEvent.keepAttr) { - continue - } - - /* Work around a security issue in jQuery 3.0 */ - if (!ALLOW_SELF_CLOSE_IN_ATTR && regExpTest(/\/>/i, value)) { - _removeAttribute(name, currentNode) - continue - } - - /* Sanitize attribute content to be template-safe */ - if (SAFE_FOR_TEMPLATES) { - arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], (expr) => { - value = stringReplace(value, expr, " ") - }) - } - - /* Is `value` valid for this attribute? */ - const lcTag = transformCaseFunc(currentNode.nodeName) - if (!_isValidAttribute(lcTag, lcName, value)) { - continue - } - - /* Full DOM Clobbering protection via namespace isolation, - * Prefix id and name attributes with `user-content-` - */ - if (SANITIZE_NAMED_PROPS && (lcName === "id" || lcName === "name")) { - // Remove the attribute with this value - _removeAttribute(name, currentNode) - - // Prefix the value and later re-create the attribute with the sanitized value - value = SANITIZE_NAMED_PROPS_PREFIX + value - } - - /* Handle attributes that require Trusted Types */ - if ( - trustedTypesPolicy && - typeof trustedTypes === "object" && - typeof trustedTypes.getAttributeType === "function" - ) { - if (namespaceURI); - else { - switch (trustedTypes.getAttributeType(lcTag, lcName)) { - case "TrustedHTML": { - value = trustedTypesPolicy.createHTML(value) - break - } - case "TrustedScriptURL": { - value = trustedTypesPolicy.createScriptURL(value) - break - } - } - } - } - - /* Handle invalid data-* attribute set by try-catching it */ - try { - if (namespaceURI) { - currentNode.setAttributeNS(namespaceURI, name, value) - } else { - /* Fallback to setAttribute() for browser-unrecognized namespaces e.g. "x-schema". */ - currentNode.setAttribute(name, value) - } - if (_isClobbered(currentNode)) { - _forceRemove(currentNode) - } else { - arrayPop(DOMPurify.removed) - } - } catch (_) {} - } - - /* Execute a hook if present */ - _executeHook("afterSanitizeAttributes", currentNode, null) - } - - /** - * _sanitizeShadowDOM - * - * @param {DocumentFragment} fragment to iterate over recursively - */ - const _sanitizeShadowDOM = function _sanitizeShadowDOM(fragment) { - let shadowNode = null - const shadowIterator = _createNodeIterator(fragment) - - /* Execute a hook if present */ - _executeHook("beforeSanitizeShadowDOM", fragment, null) - while ((shadowNode = shadowIterator.nextNode())) { - /* Execute a hook if present */ - _executeHook("uponSanitizeShadowNode", shadowNode, null) - - /* Sanitize tags and elements */ - if (_sanitizeElements(shadowNode)) { - continue - } - - /* Deep shadow DOM detected */ - if (shadowNode.content instanceof DocumentFragment) { - _sanitizeShadowDOM(shadowNode.content) - } - - /* Check attributes, sanitize if necessary */ - _sanitizeAttributes(shadowNode) - } - - /* Execute a hook if present */ - _executeHook("afterSanitizeShadowDOM", fragment, null) - } - - /** - * Sanitize - * Public method providing core sanitation functionality - * - * @param {String|Node} dirty string or DOM node - * @param {Object} cfg object - */ - // eslint-disable-next-line complexity - DOMPurify.sanitize = function (dirty) { - let cfg = - arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {} - let body = null - let importedNode = null - let currentNode = null - let returnNode = null - /* Make sure we have a string to sanitize. - DO NOT return early, as this will return the wrong type if - the user has requested a DOM object rather than a string */ - IS_EMPTY_INPUT = !dirty - if (IS_EMPTY_INPUT) { - dirty = "<!-->" - } - - /* Stringify, in case dirty is an object */ - if (typeof dirty !== "string" && !_isNode(dirty)) { - if (typeof dirty.toString === "function") { - dirty = dirty.toString() - if (typeof dirty !== "string") { - throw typeErrorCreate("dirty is not a string, aborting") - } - } else { - throw typeErrorCreate("toString is not a function") - } - } - - /* Return dirty HTML if DOMPurify cannot run */ - if (!DOMPurify.isSupported) { - return dirty - } - - /* Assign config vars */ - if (!SET_CONFIG) { - _parseConfig(cfg) - } - - /* Clean up removed elements */ - DOMPurify.removed = [] - - /* Check if dirty is correctly typed for IN_PLACE */ - if (typeof dirty === "string") { - IN_PLACE = false - } - if (IN_PLACE) { - /* Do some early pre-sanitization to avoid unsafe root nodes */ - if (dirty.nodeName) { - const tagName = transformCaseFunc(dirty.nodeName) - if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) { - throw typeErrorCreate( - "root node is forbidden and cannot be sanitized in-place", - ) - } - } - } else if (dirty instanceof Node) { - /* If dirty is a DOM element, append to an empty document to avoid - elements being stripped by the parser */ - body = _initDocument("<!---->") - importedNode = body.ownerDocument.importNode(dirty, true) - if ( - importedNode.nodeType === NODE_TYPE.element && - importedNode.nodeName === "BODY" - ) { - /* Node is already a body, use as is */ - body = importedNode - } else if (importedNode.nodeName === "HTML") { - body = importedNode - } else { - // eslint-disable-next-line unicorn/prefer-dom-node-append - body.appendChild(importedNode) - } - } else { - /* Exit directly if we have nothing to do */ - if ( - !RETURN_DOM && - !SAFE_FOR_TEMPLATES && - !WHOLE_DOCUMENT && - // eslint-disable-next-line unicorn/prefer-includes - dirty.indexOf("<") === -1 - ) { - return trustedTypesPolicy && RETURN_TRUSTED_TYPE - ? trustedTypesPolicy.createHTML(dirty) - : dirty - } - - /* Initialize the document to work on */ - body = _initDocument(dirty) - - /* Check we have a DOM node from the data */ - if (!body) { - return RETURN_DOM ? null : RETURN_TRUSTED_TYPE ? emptyHTML : "" - } - } - - /* Remove first element node (ours) if FORCE_BODY is set */ - if (body && FORCE_BODY) { - _forceRemove(body.firstChild) - } - - /* Get node iterator */ - const nodeIterator = _createNodeIterator(IN_PLACE ? dirty : body) - - /* Now start iterating over the created document */ - while ((currentNode = nodeIterator.nextNode())) { - /* Sanitize tags and elements */ - if (_sanitizeElements(currentNode)) { - continue - } - - /* Shadow DOM detected, sanitize it */ - if (currentNode.content instanceof DocumentFragment) { - _sanitizeShadowDOM(currentNode.content) - } - - /* Check attributes, sanitize if necessary */ - _sanitizeAttributes(currentNode) - } - - /* If we sanitized `dirty` in-place, return it. */ - if (IN_PLACE) { - return dirty - } - - /* Return sanitized string or DOM */ - if (RETURN_DOM) { - if (RETURN_DOM_FRAGMENT) { - returnNode = createDocumentFragment.call(body.ownerDocument) - while (body.firstChild) { - // eslint-disable-next-line unicorn/prefer-dom-node-append - returnNode.appendChild(body.firstChild) - } - } else { - returnNode = body - } - if (ALLOWED_ATTR.shadowroot || ALLOWED_ATTR.shadowrootmode) { - /* - AdoptNode() is not used because internal state is not reset - (e.g. the past names map of a HTMLFormElement), this is safe - in theory but we would rather not risk another attack vector. - The state that is cloned by importNode() is explicitly defined - by the specs. - */ - returnNode = importNode.call(originalDocument, returnNode, true) - } - return returnNode - } - let serializedHTML = WHOLE_DOCUMENT ? body.outerHTML : body.innerHTML - - /* Serialize doctype if allowed */ - if ( - WHOLE_DOCUMENT && - ALLOWED_TAGS["!doctype"] && - body.ownerDocument && - body.ownerDocument.doctype && - body.ownerDocument.doctype.name && - regExpTest(DOCTYPE_NAME, body.ownerDocument.doctype.name) - ) { - serializedHTML = - "<!DOCTYPE " + body.ownerDocument.doctype.name + ">\n" + serializedHTML - } - - /* Sanitize final string template-safe */ - if (SAFE_FOR_TEMPLATES) { - arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], (expr) => { - serializedHTML = stringReplace(serializedHTML, expr, " ") - }) - } - return trustedTypesPolicy && RETURN_TRUSTED_TYPE - ? trustedTypesPolicy.createHTML(serializedHTML) - : serializedHTML - } - - /** - * Public method to set the configuration once - * setConfig - * - * @param {Object} cfg configuration object - */ - DOMPurify.setConfig = function () { - let cfg = - arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {} - _parseConfig(cfg) - SET_CONFIG = true - } - - /** - * Public method to remove the configuration - * clearConfig - * - */ - DOMPurify.clearConfig = function () { - CONFIG = null - SET_CONFIG = false - } - - /** - * Public method to check if an attribute value is valid. - * Uses last set config, if any. Otherwise, uses config defaults. - * isValidAttribute - * - * @param {String} tag Tag name of containing element. - * @param {String} attr Attribute name. - * @param {String} value Attribute value. - * @return {Boolean} Returns true if `value` is valid. Otherwise, returns false. - */ - DOMPurify.isValidAttribute = function (tag, attr, value) { - /* Initialize shared config vars if necessary. */ - if (!CONFIG) { - _parseConfig({}) - } - const lcTag = transformCaseFunc(tag) - const lcName = transformCaseFunc(attr) - return _isValidAttribute(lcTag, lcName, value) - } - - /** - * AddHook - * Public method to add DOMPurify hooks - * - * @param {String} entryPoint entry point for the hook to add - * @param {Function} hookFunction function to execute - */ - DOMPurify.addHook = function (entryPoint, hookFunction) { - if (typeof hookFunction !== "function") { - return - } - hooks[entryPoint] = hooks[entryPoint] || [] - arrayPush(hooks[entryPoint], hookFunction) - } - - /** - * RemoveHook - * Public method to remove a DOMPurify hook at a given entryPoint - * (pops it from the stack of hooks if more are present) - * - * @param {String} entryPoint entry point for the hook to remove - * @return {Function} removed(popped) hook - */ - DOMPurify.removeHook = function (entryPoint) { - if (hooks[entryPoint]) { - return arrayPop(hooks[entryPoint]) - } - } - - /** - * RemoveHooks - * Public method to remove all DOMPurify hooks at a given entryPoint - * - * @param {String} entryPoint entry point for the hooks to remove - */ - DOMPurify.removeHooks = function (entryPoint) { - if (hooks[entryPoint]) { - hooks[entryPoint] = [] - } - } - - /** - * RemoveAllHooks - * Public method to remove all DOMPurify hooks - */ - DOMPurify.removeAllHooks = function () { - hooks = {} - } - return DOMPurify -} -var purify = createDOMPurify() - -export { purify as default } -//# sourceMappingURL=purify.es.mjs.map diff --git a/tools/create_article.mjs b/tools/create_article.mjs index cadbb360ca3e253280b639820b2baea93c9ddd8a..32b26bc26f03c7d3cdfa9f386e8238a26742f45b 100644 --- a/tools/create_article.mjs +++ b/tools/create_article.mjs @@ -27,7 +27,7 @@ try { license: config.blog.license, tags: [], options: { - mastodonCommentUrl: "", + mastodonShareUrl: "", }, blog: config.blog, } @@ -63,7 +63,7 @@ try { "no" if (enableMastodon.match(/y(es)?/i)) { - context.options.mastodonCommentUrl = "https://mastodon.example.com" + context.options.mastodonShareUrl = "https://mastodon.example.com" } const articleLocales = new I18n({ diff --git a/tools/locales/article/en.json b/tools/locales/article/en.json index 70f1cbd9d8e5d81c43bb53119748641b87833897..faa66004d308615bd4cd6019a0b56d6ae4dd5923 100644 --- a/tools/locales/article/en.json +++ b/tools/locales/article/en.json @@ -1,7 +1,4 @@ { "Publication data for this article are avaialable in the page source code (see tags <meta />).": "Publication data for this article are avaialable in the page source code (see tags <meta />).", - "If you enable the JavaScript engine in your web browser, they will be displayed here.": "If you enable the JavaScript engine in your web browser, they will be displayed here.", - "Comments": "Comments", - "Respond to <a href=\"{mastodonCommentUrl}\">this post</a> on the <a href=\"https://en.wikipedia.org/wiki/Fediverse\">Fediverse</a> to add a comment on this article.": "Respond to <a href=\"{mastodonCommentUrl}\">this post</a> on the <a href=\"https://en.wikipedia.org/wiki/Fediverse\">Fediverse</a> to add a comment on this article.", - "Fediverse's replies will be displayed here if you enable the JavaScript engine in your web browser.": "Fediverse's replies will be displayed here if you enable the JavaScript engine in your web browser." + "If you enable the JavaScript engine in your web browser, they will be displayed here.": "If you enable the JavaScript engine in your web browser, they will be displayed here." } diff --git a/tools/locales/article/fr.json b/tools/locales/article/fr.json index af018b5e3a4bdd0a441c7e11ff7d2630f65c06f5..47e415dca9cf4db78b8d7582acb48426c13eed63 100644 --- a/tools/locales/article/fr.json +++ b/tools/locales/article/fr.json @@ -1,7 +1,4 @@ { "Publication data for this article are avaialable in the page source code (see tags <meta />).": "Les données de publications de cet article sont disponibles dans le code source de la page (voire les balises <meta>)", - "If you enable the JavaScript engine in your web browser, they will be displayed here.": "Si vous activez le moteur JavaScript de votre navigateur web, elles seront affichées ici.", - "Comments": "Commentaires", - "Respond to <a href=\"{mastodonCommentUrl}\">this post</a> on the <a href=\"https://en.wikipedia.org/wiki/Fediverse\">Fediverse</a> to add a comment on this article.": "Répondez à <a href=\"{mastodonCommentUrl}\">ce message</a> du <a href=\"https://fr.wikipedia.org/wiki/Fediverse\">Fediverse</a> pour ajouter un commentaire sur cet article.", - "Fediverse's replies will be displayed here if you enable the JavaScript engine in your web browser.": "Les réponses du Fediverse seront affichées ici si vous avctivez le moteur JavaScript de votre navigateur web." + "If you enable the JavaScript engine in your web browser, they will be displayed here.": "Si vous activez le moteur JavaScript de votre navigateur web, elles seront affichées ici." } diff --git a/tools/templates/article.html b/tools/templates/article.html index 9081568cf8592eef5cd06e9da10280ff93945853..3cd1e55489ffd08fcdf26cb24c9cc059e79ca64d 100644 --- a/tools/templates/article.html +++ b/tools/templates/article.html @@ -15,14 +15,6 @@ media="screen" href="../css/screen.css" /> - {{#if options.mastodonCommentUrl}} - <link - rel="stylesheet" - type="text/css" - media="screen" - href="../css/comment.css" - /> - {{/if}} <link rel="stylesheet" type="text/css" @@ -40,6 +32,7 @@ <meta name="author-name" content="{{author.name}}" /> <meta name="author-url" content="{{{author.url}}}" /> <meta name="author-email" content="{{author.email}}" /> + <meta name="fediverse:creator" content="{{author.fediverse}}" /> <meta name="lang" content="{{lang}}" /> <meta name="license-name" content="{{license.name}}" /> <meta name="license-url" content="{{{license.url}}}" /> @@ -49,16 +42,10 @@ name="history-url" content="{{{blog.csv_history_url}}}/src/articles/{{{fileName}}}" /> - {{#if options.mastodonCommentUrl}} - <meta - name="mastodon-comment-url" - content="{{{options.mastodonCommentUrl}}}" - /> + {{#if options.mastodonShareUrl}} + <meta name="mastodon-share-url" content="{{{options.mastodonShareUrl}}}" /> {{/if}} <script type="module" src="../javascript/article.js"></script> - {{#if options.mastodonCommentUrl}} - <script type="module" src="../javascript/comment.js"></script> - {{/if}} <script type="module" src="../javascript/header.js"></script> </head> @@ -80,27 +67,6 @@ </header> <p>Lorem ipsum.</p> - - {{#if options.mastodonCommentUrl}} - <section id="comments"> - <h2>{{translate "Comments"}}</h2> - <!-- prettier-ignore --> - <p> - {{#with options}} - {{{translate 'Respond to <a href="{mastodonCommentUrl}">this post</a> on the <a href="https://en.wikipedia.org/wiki/Fediverse">Fediverse</a> to add a comment on this article.'}}} - {{/with}} - </p> - - <div id="mastodon-comments"> - <noscript> - <!-- prettier-ignore --> - <p> - {{translate "Fediverse's replies will be displayed here if you enable the JavaScript engine in your web browser."}} - </p> - </noscript> - </div> - </section> - {{/if}} </article> </body> </html>