get import maps working, add JSDoc ish to modules, let EJS import them
This commit is contained in:
parent
2b63dc62fc
commit
0a73555174
|
@ -3,3 +3,4 @@ processes.config.js
|
||||||
node_modules
|
node_modules
|
||||||
coverage
|
coverage
|
||||||
vitest.config.mts
|
vitest.config.mts
|
||||||
|
es-module-shims.js
|
||||||
|
|
|
@ -58,3 +58,5 @@ test/**/*.js.map
|
||||||
.envrc
|
.envrc
|
||||||
|
|
||||||
database.sqlite
|
database.sqlite
|
||||||
|
|
||||||
|
es-module-shims.js
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
"": {
|
"": {
|
||||||
"name": "intended-server",
|
"name": "intended-server",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
|
"hasInstallScript": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tsed/ajv": "^7.83.0",
|
"@tsed/ajv": "^7.83.0",
|
||||||
"@tsed/common": "^7.83.0",
|
"@tsed/common": "^7.83.0",
|
||||||
|
@ -41,6 +42,7 @@
|
||||||
"dotenv": "^16.4.5",
|
"dotenv": "^16.4.5",
|
||||||
"dotenv-expand": "^11.0.6",
|
"dotenv-expand": "^11.0.6",
|
||||||
"dotenv-flow": "^4.1.0",
|
"dotenv-flow": "^4.1.0",
|
||||||
|
"es-module-shims": "^1.10.0",
|
||||||
"express": "^4.20.0",
|
"express": "^4.20.0",
|
||||||
"express-session": "^1.18.0",
|
"express-session": "^1.18.0",
|
||||||
"method-override": "^3.0.0",
|
"method-override": "^3.0.0",
|
||||||
|
@ -76,6 +78,7 @@
|
||||||
"@vitest/coverage-v8": "^2.0.5",
|
"@vitest/coverage-v8": "^2.0.5",
|
||||||
"eslint": "^8.57.0",
|
"eslint": "^8.57.0",
|
||||||
"eslint-config-prettier": "^9.1.0",
|
"eslint-config-prettier": "^9.1.0",
|
||||||
|
"eslint-plugin-jsdoc": "^50.3.1",
|
||||||
"eslint-plugin-prettier": "^5.2.1",
|
"eslint-plugin-prettier": "^5.2.1",
|
||||||
"prettier": "^3.3.3",
|
"prettier": "^3.3.3",
|
||||||
"rimraf": "^6.0.1",
|
"rimraf": "^6.0.1",
|
||||||
|
@ -182,6 +185,21 @@
|
||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@es-joy/jsdoccomment": {
|
||||||
|
"version": "0.48.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.48.0.tgz",
|
||||||
|
"integrity": "sha512-G6QUWIcC+KvSwXNsJyDTHvqUdNoAVJPPgkc3+Uk4WBKqZvoXhlvazOgm9aL0HwihJLQf0l+tOE2UFzXBqCqgDw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"comment-parser": "1.4.1",
|
||||||
|
"esquery": "^1.6.0",
|
||||||
|
"jsdoc-type-pratt-parser": "~4.1.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=16"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@esbuild/aix-ppc64": {
|
"node_modules/@esbuild/aix-ppc64": {
|
||||||
"version": "0.21.5",
|
"version": "0.21.5",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz",
|
||||||
|
@ -3434,6 +3452,16 @@
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
|
"node_modules/are-docs-informative": {
|
||||||
|
"version": "0.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/are-docs-informative/-/are-docs-informative-0.0.2.tgz",
|
||||||
|
"integrity": "sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/are-we-there-yet": {
|
"node_modules/are-we-there-yet": {
|
||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz",
|
||||||
|
@ -4136,6 +4164,16 @@
|
||||||
"node": ">= 0.8"
|
"node": ">= 0.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/comment-parser": {
|
||||||
|
"version": "1.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.1.tgz",
|
||||||
|
"integrity": "sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 12.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/component-emitter": {
|
"node_modules/component-emitter": {
|
||||||
"version": "1.3.1",
|
"version": "1.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz",
|
||||||
|
@ -4765,6 +4803,19 @@
|
||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/es-module-lexer": {
|
||||||
|
"version": "1.5.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.4.tgz",
|
||||||
|
"integrity": "sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/es-module-shims": {
|
||||||
|
"version": "1.10.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/es-module-shims/-/es-module-shims-1.10.0.tgz",
|
||||||
|
"integrity": "sha512-3PmuShQBd9d8pulTFx6L7HKgncnZ1oeSSbrEfnUasb3Tv974BAvyFtW1HLPJSkh5fCaU9JNZbBzPdbxSwg2zqA==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/esbuild": {
|
"node_modules/esbuild": {
|
||||||
"version": "0.21.5",
|
"version": "0.21.5",
|
||||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz",
|
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz",
|
||||||
|
@ -4897,6 +4948,101 @@
|
||||||
"eslint": ">=7.0.0"
|
"eslint": ">=7.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/eslint-plugin-jsdoc": {
|
||||||
|
"version": "50.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-50.3.1.tgz",
|
||||||
|
"integrity": "sha512-SY9oUuTMr6aWoJggUS40LtMjsRzJPB5ZT7F432xZIHK3EfHF+8i48GbUBpwanrtlL9l1gILNTHK9o8gEhYLcKA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "BSD-3-Clause",
|
||||||
|
"dependencies": {
|
||||||
|
"@es-joy/jsdoccomment": "~0.48.0",
|
||||||
|
"are-docs-informative": "^0.0.2",
|
||||||
|
"comment-parser": "1.4.1",
|
||||||
|
"debug": "^4.3.6",
|
||||||
|
"escape-string-regexp": "^4.0.0",
|
||||||
|
"espree": "^10.1.0",
|
||||||
|
"esquery": "^1.6.0",
|
||||||
|
"parse-imports": "^2.1.1",
|
||||||
|
"semver": "^7.6.3",
|
||||||
|
"spdx-expression-parse": "^4.0.0",
|
||||||
|
"synckit": "^0.9.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"eslint": "^7.0.0 || ^8.0.0 || ^9.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/eslint-plugin-jsdoc/node_modules/debug": {
|
||||||
|
"version": "4.3.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
|
||||||
|
"integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"ms": "^2.1.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"supports-color": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/eslint-plugin-jsdoc/node_modules/escape-string-regexp": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/eslint-plugin-jsdoc/node_modules/eslint-visitor-keys": {
|
||||||
|
"version": "4.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.1.0.tgz",
|
||||||
|
"integrity": "sha512-Q7lok0mqMUSf5a/AdAZkA5a/gHcO6snwQClVNNvFKCAVlxXucdU8pKydU5ZVZjBx5xr37vGbFFWtLQYreLzrZg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"engines": {
|
||||||
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/eslint"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/eslint-plugin-jsdoc/node_modules/espree": {
|
||||||
|
"version": "10.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/espree/-/espree-10.2.0.tgz",
|
||||||
|
"integrity": "sha512-upbkBJbckcCNBDBDXEbuhjbP68n+scUd3k/U2EkyM9nw+I/jPiL4cLF/Al06CF96wRltFda16sxDFrxsI1v0/g==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "BSD-2-Clause",
|
||||||
|
"dependencies": {
|
||||||
|
"acorn": "^8.12.0",
|
||||||
|
"acorn-jsx": "^5.3.2",
|
||||||
|
"eslint-visitor-keys": "^4.1.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/eslint"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/eslint-plugin-jsdoc/node_modules/ms": {
|
||||||
|
"version": "2.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||||
|
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/eslint-plugin-prettier": {
|
"node_modules/eslint-plugin-prettier": {
|
||||||
"version": "5.2.1",
|
"version": "5.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.2.1.tgz",
|
||||||
|
@ -6540,6 +6686,16 @@
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
|
"node_modules/jsdoc-type-pratt-parser": {
|
||||||
|
"version": "4.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.1.0.tgz",
|
||||||
|
"integrity": "sha512-Hicd6JK5Njt2QB6XYFS7ok9e37O8AYk3jTcppG4YVQnYjOemymvTcmc7OWsmq/Qqj5TdRFO5/x/tIPmBeRtGHg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/json-buffer": {
|
"node_modules/json-buffer": {
|
||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
|
||||||
|
@ -7488,6 +7644,20 @@
|
||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/parse-imports": {
|
||||||
|
"version": "2.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/parse-imports/-/parse-imports-2.2.1.tgz",
|
||||||
|
"integrity": "sha512-OL/zLggRp8mFhKL0rNORUTR4yBYujK/uU+xZL+/0Rgm2QE4nLO9v8PzEweSJEbMGKmDRjJE4R3IMJlL2di4JeQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "Apache-2.0 AND MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"es-module-lexer": "^1.5.3",
|
||||||
|
"slashes": "^3.0.12"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 18"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/parse-json": {
|
"node_modules/parse-json": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
|
||||||
|
@ -8731,6 +8901,13 @@
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/slashes": {
|
||||||
|
"version": "3.0.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/slashes/-/slashes-3.0.12.tgz",
|
||||||
|
"integrity": "sha512-Q9VME8WyGkc7pJf6QEkj3wE+2CnvZMI+XJhwdTPR8Z/kWQRXi7boAWLDibRPyHRTUTPx5FaU7MsyrjI3yLB4HA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "ISC"
|
||||||
|
},
|
||||||
"node_modules/smart-buffer": {
|
"node_modules/smart-buffer": {
|
||||||
"version": "4.2.0",
|
"version": "4.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz",
|
||||||
|
@ -8836,6 +9013,31 @@
|
||||||
"source-map": "^0.6.0"
|
"source-map": "^0.6.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/spdx-exceptions": {
|
||||||
|
"version": "2.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz",
|
||||||
|
"integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "CC-BY-3.0"
|
||||||
|
},
|
||||||
|
"node_modules/spdx-expression-parse": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"spdx-exceptions": "^2.1.0",
|
||||||
|
"spdx-license-ids": "^3.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/spdx-license-ids": {
|
||||||
|
"version": "3.0.20",
|
||||||
|
"resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.20.tgz",
|
||||||
|
"integrity": "sha512-jg25NiDV/1fLtSgEgyvVyDunvaNHbuwF9lfNV17gSmPFAlYzdfNBlLtLzXTevwkPj7DhGbmN9VnmJIgLnhvaBw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "CC0-1.0"
|
||||||
|
},
|
||||||
"node_modules/sprintf-js": {
|
"node_modules/sprintf-js": {
|
||||||
"version": "1.1.3",
|
"version": "1.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz",
|
||||||
|
|
|
@ -14,7 +14,8 @@
|
||||||
"typeorm": "typeorm-ts-node-commonjs",
|
"typeorm": "typeorm-ts-node-commonjs",
|
||||||
"test:lint": "eslint '**/*.{ts,js}'",
|
"test:lint": "eslint '**/*.{ts,js}'",
|
||||||
"test:lint:fix": "eslint '**/*.{ts,js}' --fix",
|
"test:lint:fix": "eslint '**/*.{ts,js}' --fix",
|
||||||
"prettier": "prettier '**/*.{ts,js,json,md,yml,yaml}' --write"
|
"prettier": "prettier '**/*.{ts,js,json,md,yml,yaml}' --write",
|
||||||
|
"postinstall": "cp node_modules/es-module-shims/dist/es-module-shims.js static/"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tsed/ajv": "^7.83.0",
|
"@tsed/ajv": "^7.83.0",
|
||||||
|
@ -50,6 +51,7 @@
|
||||||
"dotenv": "^16.4.5",
|
"dotenv": "^16.4.5",
|
||||||
"dotenv-expand": "^11.0.6",
|
"dotenv-expand": "^11.0.6",
|
||||||
"dotenv-flow": "^4.1.0",
|
"dotenv-flow": "^4.1.0",
|
||||||
|
"es-module-shims": "^1.10.0",
|
||||||
"express": "^4.20.0",
|
"express": "^4.20.0",
|
||||||
"express-session": "^1.18.0",
|
"express-session": "^1.18.0",
|
||||||
"method-override": "^3.0.0",
|
"method-override": "^3.0.0",
|
||||||
|
@ -85,6 +87,7 @@
|
||||||
"@vitest/coverage-v8": "^2.0.5",
|
"@vitest/coverage-v8": "^2.0.5",
|
||||||
"eslint": "^8.57.0",
|
"eslint": "^8.57.0",
|
||||||
"eslint-config-prettier": "^9.1.0",
|
"eslint-config-prettier": "^9.1.0",
|
||||||
|
"eslint-plugin-jsdoc": "^50.3.1",
|
||||||
"eslint-plugin-prettier": "^5.2.1",
|
"eslint-plugin-prettier": "^5.2.1",
|
||||||
"prettier": "^3.3.3",
|
"prettier": "^3.3.3",
|
||||||
"rimraf": "^6.0.1",
|
"rimraf": "^6.0.1",
|
||||||
|
|
|
@ -0,0 +1,110 @@
|
||||||
|
import { HexMix } from "/utils";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the send page functionality.
|
||||||
|
* This function sets up event listeners and handles the form submission process.
|
||||||
|
*/
|
||||||
|
export function initializeSendPage() {
|
||||||
|
const copyButton = document.getElementById("copyButton");
|
||||||
|
const fileInput = document.getElementById("file");
|
||||||
|
const form = document.getElementById("secretForm");
|
||||||
|
const resultInput = document.getElementById("result");
|
||||||
|
const encryptedDataTextarea = document.getElementById("encryptedData");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copies the result URL to the clipboard.
|
||||||
|
*/
|
||||||
|
copyButton.addEventListener("click", async () => {
|
||||||
|
resultInput.select();
|
||||||
|
await navigator.clipboard.writeText(resultInput.value);
|
||||||
|
alert("URL copied to clipboard!");
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Toggles the text input based on file selection.
|
||||||
|
* @param {Event} e - The change event.
|
||||||
|
*/
|
||||||
|
fileInput.addEventListener("change", (e) => {
|
||||||
|
const file = e.target.files[0];
|
||||||
|
document.getElementById("text").disabled = !!file;
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the form submission.
|
||||||
|
* @param {Event} e - The submit event.
|
||||||
|
*/
|
||||||
|
form.addEventListener("submit", async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
const formData = new FormData(form);
|
||||||
|
const text = formData.get("text");
|
||||||
|
const file = formData.get("file");
|
||||||
|
const serviceIdentifier = formData.get("serviceIdentifier");
|
||||||
|
const service = formData.get("service");
|
||||||
|
|
||||||
|
let plaintext = text;
|
||||||
|
let filetype = "text/plain";
|
||||||
|
let filename = "secret.txt";
|
||||||
|
|
||||||
|
if (file.size > 0) {
|
||||||
|
if (file.size > 2097152) {
|
||||||
|
alert("Error: Max file size is 2mb.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
plaintext = await file.arrayBuffer();
|
||||||
|
filetype = file.type;
|
||||||
|
filename = file.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a new AES-GCM key.
|
||||||
|
* @type {CryptoKey}
|
||||||
|
*/
|
||||||
|
const key = await window.crypto.subtle.generateKey({ name: "AES-GCM", length: 256 }, true, ["encrypt", "decrypt"]);
|
||||||
|
|
||||||
|
const iv = window.crypto.getRandomValues(new Uint8Array(16));
|
||||||
|
const exported = await window.crypto.subtle.exportKey("raw", key);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encrypts the plaintext.
|
||||||
|
* @type {ArrayBuffer}
|
||||||
|
*/
|
||||||
|
const encrypted = await window.crypto.subtle.encrypt(
|
||||||
|
{ name: "AES-GCM", iv },
|
||||||
|
key,
|
||||||
|
typeof plaintext === "string" ? HexMix.stringToArrayBuffer(plaintext) : plaintext
|
||||||
|
);
|
||||||
|
|
||||||
|
// Convert the encrypted ArrayBuffer to a Base64 string
|
||||||
|
const encryptedBase64 = HexMix.arrayBufferToBase64(encrypted);
|
||||||
|
encryptedDataTextarea.value = encryptedBase64;
|
||||||
|
|
||||||
|
const keyHex = HexMix.uint8ToHex(new Uint8Array(exported));
|
||||||
|
const ivHex = HexMix.uint8ToHex(iv);
|
||||||
|
const keyParams = { key: keyHex, iv: ivHex };
|
||||||
|
|
||||||
|
const params = JSON.stringify({
|
||||||
|
service: service,
|
||||||
|
serviceIdentifier: serviceIdentifier,
|
||||||
|
text: encryptedBase64,
|
||||||
|
iv: ivHex,
|
||||||
|
filetype: filetype,
|
||||||
|
filename: filename
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch("/rest/links", {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json"
|
||||||
|
},
|
||||||
|
body: params
|
||||||
|
});
|
||||||
|
const data = await response.json();
|
||||||
|
const url = `http://${window.location.host}/rest/links/${data.id}#${btoa(JSON.stringify(keyParams))}`;
|
||||||
|
resultInput.value = url;
|
||||||
|
} catch (err) {
|
||||||
|
alert(`Error: ${err.message}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
/**
|
||||||
|
* Utility object for handling hexadecimal and binary data conversions.
|
||||||
|
* @namespace
|
||||||
|
*/
|
||||||
|
export const HexMix = {
|
||||||
|
/**
|
||||||
|
* Converts a Uint8Array to a hexadecimal string.
|
||||||
|
* @param {Uint8Array} data - The input Uint8Array.
|
||||||
|
* @returns {string} The hexadecimal representation of the input data.
|
||||||
|
*/
|
||||||
|
uint8ToHex(data) {
|
||||||
|
return Array.from(data, (byte) => ("00" + byte.toString(16)).slice(-2)).join("");
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a hexadecimal string to a Uint8Array.
|
||||||
|
* @param {string} data - The input hexadecimal string.
|
||||||
|
* @returns {Uint8Array} The Uint8Array representation of the input data.
|
||||||
|
*/
|
||||||
|
hexToUint8(data) {
|
||||||
|
const hexArray = data.match(/.{1,2}/g);
|
||||||
|
return hexArray ? new Uint8Array(hexArray.map((char) => parseInt(char, 16))) : new Uint8Array(0);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts an ArrayBuffer to a Base64 string.
|
||||||
|
* @param {ArrayBuffer} buf - The input ArrayBuffer.
|
||||||
|
* @returns {string} The Base64 representation of the input data.
|
||||||
|
*/
|
||||||
|
arrayBufferToBase64(buf) {
|
||||||
|
return btoa(String.fromCharCode.apply(null, new Uint8Array(buf)));
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a string to an ArrayBuffer.
|
||||||
|
* @param {string} str - The input string.
|
||||||
|
* @returns {ArrayBuffer} The ArrayBuffer representation of the input string.
|
||||||
|
*/
|
||||||
|
stringToArrayBuffer(str) {
|
||||||
|
const array = new Uint8Array(str.length);
|
||||||
|
for (let i = 0; i < str.length; i++) {
|
||||||
|
array[i] = str.charCodeAt(i);
|
||||||
|
}
|
||||||
|
return array.buffer;
|
||||||
|
}
|
||||||
|
};
|
|
@ -26,8 +26,8 @@
|
||||||
"typeRoots": ["./node_modules/@types"],
|
"typeRoots": ["./node_modules/@types"],
|
||||||
"noEmitHelpers": false
|
"noEmitHelpers": false
|
||||||
},
|
},
|
||||||
"include": ["src"],
|
"include": ["src", "static/**/*.js"],
|
||||||
"linterOptions": {
|
"linterOptions": {
|
||||||
"exclude": []
|
"exclude": ["static/es-module-shims.js"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,8 +2,17 @@
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
|
|
||||||
<%- include('../layout/head.ejs', { title: 'Intended Link' }) %>
|
<%- include('../layout/head.ejs', { title: 'Intended Link' }) %>
|
||||||
|
<script async src="/static/js/es-module-shims.js"></script>
|
||||||
|
<script type="importmap">
|
||||||
|
{
|
||||||
|
"imports": {
|
||||||
|
"/utils": "/static/js/utils.js",
|
||||||
|
"/send": "/static/js/send.js"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
<body>
|
<body id="send-page">
|
||||||
<%- include('../layout/header.ejs') %>
|
<%- include('../layout/header.ejs') %>
|
||||||
<main class="f-col">
|
<main class="f-col">
|
||||||
<div class="page-wrapper">
|
<div class="page-wrapper">
|
||||||
|
@ -50,126 +59,9 @@
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<script>
|
<script type="module">
|
||||||
const HexMix = {
|
import { initializeSendPage } from '/send';
|
||||||
uint8ToHex(data) {
|
initializeSendPage();
|
||||||
return Array.from(data, byte => ('00' + byte.toString(16)).slice(-2)).join('');
|
|
||||||
},
|
|
||||||
hexToUint8(data) {
|
|
||||||
const hexArray = data.match(/.{1,2}/g);
|
|
||||||
return hexArray ? new Uint8Array(hexArray.map(char => parseInt(char, 16))) : new Uint8Array(0);
|
|
||||||
},
|
|
||||||
arrayBufferToString(buf, callback) {
|
|
||||||
const reader = new FileReader();
|
|
||||||
reader.onload = event => callback(event.target.result);
|
|
||||||
reader.onerror = event => alert(event.target.error);
|
|
||||||
reader.readAsBinaryString(new Blob([buf], { type: 'application/octet-stream' }));
|
|
||||||
},
|
|
||||||
stringToArrayBuffer(str) {
|
|
||||||
const array = new Uint8Array(str.length);
|
|
||||||
for (let i = 0; i < str.length; i++) {
|
|
||||||
array[i] = str.charCodeAt(i);
|
|
||||||
}
|
|
||||||
return array.buffer;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const copyButton = document.getElementById('copyButton');
|
|
||||||
const fileInput = document.getElementById('file');
|
|
||||||
|
|
||||||
copyButton.addEventListener('click', () => {
|
|
||||||
resultInput.select();
|
|
||||||
document.execCommand('copy');
|
|
||||||
alert('URL copied to clipboard!');
|
|
||||||
});
|
|
||||||
|
|
||||||
fileInput.addEventListener('change', (e) => {
|
|
||||||
const file = e.target.files[0];
|
|
||||||
if (file) {
|
|
||||||
document.getElementById('text').disabled = true;
|
|
||||||
} else {
|
|
||||||
document.getElementById('text').disabled = false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const form = document.getElementById('secretForm');
|
|
||||||
const resultInput = document.getElementById('result');
|
|
||||||
const encryptedDataTextarea = document.getElementById('encryptedData');
|
|
||||||
|
|
||||||
|
|
||||||
form.addEventListener('submit', async (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
|
|
||||||
const formData = new FormData(form);
|
|
||||||
const text = formData.get('text');
|
|
||||||
const file = formData.get('file');
|
|
||||||
const serviceIdentifier = formData.get('serviceIdentifier');
|
|
||||||
const service = formData.get('service');
|
|
||||||
|
|
||||||
let plaintext = text;
|
|
||||||
let filetype = 'text/plain';
|
|
||||||
let filename = 'secret.txt';
|
|
||||||
|
|
||||||
if (file.size > 0) {
|
|
||||||
if (file.size > 2097152) {
|
|
||||||
alert('Error: Max file size is 2mb.');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
plaintext = await file.arrayBuffer();
|
|
||||||
filetype = file.type;
|
|
||||||
filename = file.name;
|
|
||||||
}
|
|
||||||
|
|
||||||
const key = await window.crypto.subtle.generateKey(
|
|
||||||
{ name: 'AES-GCM', length: 256 },
|
|
||||||
true,
|
|
||||||
['encrypt', 'decrypt']
|
|
||||||
);
|
|
||||||
|
|
||||||
const iv = window.crypto.getRandomValues(new Uint8Array(16));
|
|
||||||
const exported = await window.crypto.subtle.exportKey('raw', key);
|
|
||||||
const encrypted = await window.crypto.subtle.encrypt(
|
|
||||||
{ name: 'AES-GCM', iv },
|
|
||||||
key,
|
|
||||||
typeof plaintext === 'string' ? HexMix.stringToArrayBuffer(plaintext) : plaintext
|
|
||||||
);
|
|
||||||
|
|
||||||
HexMix.arrayBufferToString(encrypted, async (encryptedText) => {
|
|
||||||
encryptedDataTextarea.value = encryptedText;
|
|
||||||
|
|
||||||
|
|
||||||
const keyHex = HexMix.uint8ToHex(new Uint8Array(exported));
|
|
||||||
const ivHex = HexMix.uint8ToHex(iv);
|
|
||||||
const keyParams = { key: keyHex, iv: ivHex };
|
|
||||||
|
|
||||||
const params = JSON.stringify({
|
|
||||||
service: service,
|
|
||||||
serviceIdentifier: serviceIdentifier,
|
|
||||||
text: encryptedText,
|
|
||||||
iv: ivHex,
|
|
||||||
filetype: filetype,
|
|
||||||
filename: filename
|
|
||||||
});
|
|
||||||
|
|
||||||
try {
|
|
||||||
const response = await fetch('/rest/links', {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
},
|
|
||||||
body: params
|
|
||||||
});
|
|
||||||
const data = await response.json();
|
|
||||||
const url = `http://${window.location.host}/rest/links/${data.id}#${btoa(JSON.stringify(keyParams))}`;
|
|
||||||
resultInput.value = url;
|
|
||||||
} catch (err) {
|
|
||||||
alert(`Error: ${err.message}`);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<%- include('../layout/footer.ejs') %>
|
<%- include('../layout/footer.ejs') %>
|
||||||
|
|
Loading…
Reference in New Issue