From f1657b3f7c08af9b2430b0cbb6fe40ddf2d48516 Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Fri, 16 Aug 2024 15:55:10 +0200 Subject: [PATCH 1/5] make mocha run with ESM modules --- frontend/{.eslintrc.js => .eslintrc.cjs} | 0 frontend/package.json | 7 +++---- frontend/{postcss.config.js => postcss.config.cjs} | 0 frontend/test/common/crypto.spec.ts | 3 ++- frontend/test/common/jwe.spec.ts | 3 ++- frontend/test/common/jwt.spec.ts | 3 ++- frontend/tsconfig.json | 7 +++---- 7 files changed, 12 insertions(+), 11 deletions(-) rename frontend/{.eslintrc.js => .eslintrc.cjs} (100%) rename frontend/{postcss.config.js => postcss.config.cjs} (100%) diff --git a/frontend/.eslintrc.js b/frontend/.eslintrc.cjs similarity index 100% rename from frontend/.eslintrc.js rename to frontend/.eslintrc.cjs diff --git a/frontend/package.json b/frontend/package.json index 2d6ab5704..0d18445e8 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,4 +1,5 @@ { + "type": "module", "name": "cryptomator-hub", "version": "1.4.0", "description": "Web-Frontend for Cryptomator Hub", @@ -9,7 +10,7 @@ "scripts": { "dev": "vite", "build": "vue-tsc --noEmit && vite build", - "lint": "eslint -c .eslintrc.js", + "lint": "eslint -c .eslintrc.cjs", "test": "nyc --reporter lcov mocha", "serve": "vite preview", "dist": "vue-tsc --noEmit && vite build --sourcemap --outDir=\"../backend/src/main/resources/META-INF/resources\" --emptyOutDir" @@ -19,9 +20,7 @@ "test": "./test" }, "mocha": { - "require": [ - "ts-node/register" - ], + "loader": "ts-node/esm", "spec": "test/**/*.spec.ts", "timeout": 60000 }, diff --git a/frontend/postcss.config.js b/frontend/postcss.config.cjs similarity index 100% rename from frontend/postcss.config.js rename to frontend/postcss.config.cjs diff --git a/frontend/test/common/crypto.spec.ts b/frontend/test/common/crypto.spec.ts index c767e6353..639fba7f0 100644 --- a/frontend/test/common/crypto.spec.ts +++ b/frontend/test/common/crypto.spec.ts @@ -3,6 +3,7 @@ import chaiAsPromised from 'chai-as-promised'; import { before, describe } from 'mocha'; import { base64, base64url } from 'rfc4648'; import { UnwrapKeyError, UserKeys, VaultKeys, getJwkThumbprint } from '../../src/common/crypto'; +import { webcrypto } from 'node:crypto'; chaiUse(chaiAsPromised); @@ -36,7 +37,7 @@ describe('crypto', () => { before(async () => { // since this test runs on Node, we need to replace window.crypto: // @ts-ignore: global not defined (but will be available within Node) - Object.defineProperty(global, 'crypto', { value: require('node:crypto').webcrypto }); + Object.defineProperty(global, 'crypto', { value: webcrypto }); // @ts-ignore: global not defined (but will be available within Node) global.window = { crypto: global.crypto }; diff --git a/frontend/test/common/jwe.spec.ts b/frontend/test/common/jwe.spec.ts index 5977b87f6..f8b43a906 100644 --- a/frontend/test/common/jwe.spec.ts +++ b/frontend/test/common/jwe.spec.ts @@ -2,12 +2,13 @@ import { expect } from 'chai'; import { describe } from 'mocha'; import { base64url } from 'rfc4648'; import { ConcatKDF, ECDH_ES, ECDH_P384, JWEBuilder, JWEHeader, JWEParser, PBES2 } from '../../src/common/jwe'; +import { webcrypto } from 'node:crypto'; describe('JWE', () => { before(done => { // since this test runs on Node, we need to replace window.crypto: // @ts-ignore: global not defined (but will be available within Node) - Object.defineProperty(global, 'crypto', { value: require('node:crypto').webcrypto }); + Object.defineProperty(global, 'crypto', { value: webcrypto }); // @ts-ignore: global not defined (but will be available within Node) global.window = { crypto: global.crypto }; done(); diff --git a/frontend/test/common/jwt.spec.ts b/frontend/test/common/jwt.spec.ts index dfc64a975..0a548bfde 100644 --- a/frontend/test/common/jwt.spec.ts +++ b/frontend/test/common/jwt.spec.ts @@ -1,12 +1,13 @@ import { expect } from 'chai'; import { describe } from 'mocha'; import { JWT, JWTHeader } from '../../src/common/jwt'; +import { webcrypto } from 'node:crypto'; describe('JWT', () => { before(done => { // since this test runs on Node, we need to replace window.crypto: // @ts-ignore: global not defined (but will be available within Node) - Object.defineProperty(global, 'crypto', { value: require('node:crypto').webcrypto }); + Object.defineProperty(global, 'crypto', { value: webcrypto }); // @ts-ignore: global not defined (but will be available within Node) global.window = { crypto: global.crypto }; done(); diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json index 381b7738e..e9073f959 100644 --- a/frontend/tsconfig.json +++ b/frontend/tsconfig.json @@ -14,9 +14,8 @@ "useUnknownInCatchVariables": false, // Workaround for `node_modules/miscreant/src/providers/webcrypto.ts:21:11 - error TS18046: 'e' is of type 'unknown'.` }, "ts-node": { - "compilerOptions": { - "module": "CommonJS" - } + "esm": true, + "experimentalSpecifierResolution": "node" }, - "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"] + "include": ["src/**/*.ts", "src/**/*.vue", "test/**/*.ts"] } From 9e8f82f2f016555f51f2ec91174d72a92116c620 Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Fri, 16 Aug 2024 15:56:56 +0200 Subject: [PATCH 2/5] update chai to 5.x --- frontend/package-lock.json | 84 +++++++++++++++----------------------- frontend/package.json | 4 +- 2 files changed, 35 insertions(+), 53 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 7da4faef6..fc2531fb3 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -39,8 +39,8 @@ "@vitejs/plugin-vue": "^5.1.2", "@vue/compiler-sfc": "^3.4.37", "autoprefixer": "^10.4.20", - "chai": "^4.5.0", - "chai-as-promised": "^7.1.2", + "chai": "^5.1.1", + "chai-as-promised": "^8.0.0", "eslint": "^8.57.0", "eslint-plugin-vue": "^9.25.0", "mocha": "^10.7.3", @@ -1819,13 +1819,13 @@ } }, "node_modules/assertion-error": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", - "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", "dev": true, "license": "MIT", "engines": { - "node": "*" + "node": ">=12" } }, "node_modules/asynckit": { @@ -2045,32 +2045,30 @@ } }, "node_modules/chai": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.5.0.tgz", - "integrity": "sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/chai/-/chai-5.1.1.tgz", + "integrity": "sha512-pT1ZgP8rPNqUgieVaEY+ryQr6Q4HXNg8Ei9UnLUrjN4IA7dvQC5JB+/kxVcPNDHyBcc/26CXPkbNzq3qwrOEKA==", "dev": true, "license": "MIT", "dependencies": { - "assertion-error": "^1.1.0", - "check-error": "^1.0.3", - "deep-eql": "^4.1.3", - "get-func-name": "^2.0.2", - "loupe": "^2.3.6", - "pathval": "^1.1.1", - "type-detect": "^4.1.0" + "assertion-error": "^2.0.1", + "check-error": "^2.1.1", + "deep-eql": "^5.0.1", + "loupe": "^3.1.0", + "pathval": "^2.0.0" }, "engines": { - "node": ">=4" + "node": ">=12" } }, "node_modules/chai-as-promised": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-7.1.2.tgz", - "integrity": "sha512-aBDHZxRzYnUYuIAIPBH2s511DjlKPzXNlXSGFC8CwmroWQLfrW0LtE1nK3MAwwNhJPa9raEjNCmRoFpG0Hurdw==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-8.0.0.tgz", + "integrity": "sha512-sMsGXTrS3FunP/wbqh/KxM8Kj/aLPXQGkNtvE5wPfSToq8wkkvBpTZo1LIiEVmC4BwkKpag+l5h/20lBMk6nUg==", "dev": true, "license": "WTFPL", "dependencies": { - "check-error": "^1.0.2" + "check-error": "^2.0.0" }, "peerDependencies": { "chai": ">= 2.1.2 < 6" @@ -2094,16 +2092,13 @@ } }, "node_modules/check-error": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", - "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz", + "integrity": "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==", "dev": true, "license": "MIT", - "dependencies": { - "get-func-name": "^2.0.2" - }, "engines": { - "node": "*" + "node": ">= 16" } }, "node_modules/chokidar": { @@ -2319,14 +2314,11 @@ } }, "node_modules/deep-eql": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.4.tgz", - "integrity": "sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", + "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", "dev": true, "license": "MIT", - "dependencies": { - "type-detect": "^4.0.0" - }, "engines": { "node": ">=6" } @@ -3817,9 +3809,9 @@ } }, "node_modules/loupe": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", - "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.1.tgz", + "integrity": "sha512-edNu/8D5MKVfGVFRhFf8aAxiTM6Wumfz5XsaatSxlD3w4R1d/WEKUTydCdPGbl9K7QG/Ca3GnDV2sIKIpXRQcw==", "dev": true, "license": "MIT", "dependencies": { @@ -4597,13 +4589,13 @@ "license": "MIT" }, "node_modules/pathval": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", - "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.0.tgz", + "integrity": "sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==", "dev": true, "license": "MIT", "engines": { - "node": "*" + "node": ">= 14.16" } }, "node_modules/picocolors": { @@ -5728,16 +5720,6 @@ "node": ">= 0.8.0" } }, - "node_modules/type-detect": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.1.0.tgz", - "integrity": "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, "node_modules/type-fest": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", diff --git a/frontend/package.json b/frontend/package.json index 0d18445e8..b4bed4b02 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -39,8 +39,8 @@ "@vitejs/plugin-vue": "^5.1.2", "@vue/compiler-sfc": "^3.4.37", "autoprefixer": "^10.4.20", - "chai": "^4.5.0", - "chai-as-promised": "^7.1.2", + "chai": "^5.1.1", + "chai-as-promised": "^8.0.0", "eslint": "^8.57.0", "eslint-plugin-vue": "^9.25.0", "mocha": "^10.7.3", From 82465061c444278c15867d0a84af145d5f64169b Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Thu, 22 Aug 2024 12:45:20 +0200 Subject: [PATCH 3/5] upgrade eslint, migrate to esm and flat config --- frontend/.eslintrc.cjs | 51 ---- frontend/.vscode/settings.json | 10 +- frontend/eslint.config.js | 97 ++++++++ frontend/package-lock.json | 417 +++++++++++++++++++++------------ frontend/package.json | 9 +- 5 files changed, 374 insertions(+), 210 deletions(-) delete mode 100644 frontend/.eslintrc.cjs create mode 100644 frontend/eslint.config.js diff --git a/frontend/.eslintrc.cjs b/frontend/.eslintrc.cjs deleted file mode 100644 index 753bfdaad..000000000 --- a/frontend/.eslintrc.cjs +++ /dev/null @@ -1,51 +0,0 @@ -module.exports = { - plugins: ['@typescript-eslint'], - parserOptions: { - parser: require.resolve('@typescript-eslint/parser'), - extraFileExtensions: ['.vue'], - ecmaFeatures: { - jsx: true - } - }, - env: { - 'browser': true - }, - extends: [ - 'eslint:recommended', - 'plugin:vue/vue3-recommended', - ], - globals: { - defineProps: 'readonly', - defineEmits: 'readonly', - defineExpose: 'readonly', - }, - overrides: [ - { - files: ['*.vue'], - rules: { - 'vue/block-tag-newline': ['error', { 'singleline': 'consistent', 'multiline': 'consistent' }], - 'vue/html-closing-bracket-spacing': 'off', - 'vue/html-self-closing': 'off', - 'vue/max-attributes-per-line': 'off', - 'vue/padding-line-between-blocks': 'error', - 'vue/singleline-html-element-content-newline': 'off', - 'vue/space-infix-ops': 'error', - } - }, - ], - rules: { - 'keyword-spacing': ['error', { 'before': true, 'after': true }], - 'linebreak-style': ['error', 'unix'], - 'lines-between-class-members': ['error', 'always', { 'exceptAfterSingleLine': true }], - 'no-multiple-empty-lines': ['error', { 'max': 1, 'maxEOF': 0, 'maxBOF': 0 }], - 'no-unused-vars': 'off', - 'object-curly-spacing': ['error', 'always'], - 'padded-blocks': ['error', 'never'], - 'quotes': ['error', 'single'], - 'semi': ['error', 'always'], - 'space-infix-ops': 'error', - '@typescript-eslint/indent': ['error', 2], - '@typescript-eslint/no-unused-vars': 'off', // is checked by noUnusedLocals in tsconfig.json - 'no-undef': 'off' // types checked by typescript already - } -}; diff --git a/frontend/.vscode/settings.json b/frontend/.vscode/settings.json index 1c096d3bb..c22203ac4 100644 --- a/frontend/.vscode/settings.json +++ b/frontend/.vscode/settings.json @@ -20,11 +20,17 @@ "html.format.wrapLineLength": 0, "typescript.preferences.importModuleSpecifier": "relative", "typescript.preferences.quoteStyle": "single", + "mochaExplorer.nodeArgv": [ + "--loader=ts-node/esm", + "--no-warnings=ExperimentalWarning", + "--experimental-specifier-resolution=node" + ], "mochaExplorer.env": { - "TS_NODE_COMPILER_OPTIONS": "{\"module\": \"commonjs\" }", + //"TS_NODE_COMPILER_OPTIONS": "{\"module\": \"commonjs\" }", // "TS_NODE_PROJECT": "./test/tsconfig.json" }, "mochaExplorer.files": "test/**/*.spec.ts", "mochaExplorer.require": "ts-node/register", - "eslint.validate": ["typescript", "javascript", "vue"] + "eslint.validate": ["typescript", "javascript", "vue"], + "eslint.useFlatConfig": true } diff --git a/frontend/eslint.config.js b/frontend/eslint.config.js new file mode 100644 index 000000000..1904a7fe5 --- /dev/null +++ b/frontend/eslint.config.js @@ -0,0 +1,97 @@ +// @ts-check +import eslint from "@eslint/js"; +import pluginVue from 'eslint-plugin-vue'; +import tseslint from 'typescript-eslint'; + +export default tseslint.config( +{ + files: ['src/**/*.ts', 'test/**/*.ts'], + extends: [ + eslint.configs.recommended, + ...tseslint.configs.recommended, + ], + plugins: { + '@typescript-eslint': tseslint.plugin, + }, + languageOptions: { + parser: tseslint.parser, + parserOptions: { + projectService: true, + tsconfigRootDir: import.meta.dirname, + ecmaVersion: 'latest', + sourceType: 'module', + }, + }, + rules: { + '@typescript-eslint/ban-ts-comment': 'warn', + '@typescript-eslint/no-explicit-any': 'warn', + '@typescript-eslint/no-unsafe-function-type': 'warn', + '@typescript-eslint/no-unused-vars': 'off', // is checked by noUnusedLocals in tsconfig.json // or use ['error', { 'ignoreRestSiblings': true }] + 'no-unused-vars': 'off', // is checked by noUnusedLocals in tsconfig.json + 'no-undef': 'off', // types checked by typescript already + 'keyword-spacing': ['error', { before: true, after: true}], + 'linebreak-style': ['error', 'unix'], + 'lines-between-class-members': ['error', 'always', { exceptAfterSingleLine: true, }], + 'no-multiple-empty-lines': ['error', { max: 1, maxEOF: 0, maxBOF: 0 }], + 'object-curly-spacing': ['error', 'always'], + 'padded-blocks': ['error', 'never'], + 'quotes': ['error', 'single'], + 'semi': ['error', 'always'], + 'space-infix-ops': 'error', + 'indent': ['error', 2, { SwitchCase: 1 }], + } +}, +{ + files: ['test/**/*.ts'], + rules: { + '@typescript-eslint/no-unused-expressions': 'off' + } +}, +{ + files: ['src/**/*.vue'], + extends: [ + eslint.configs.recommended, + ...tseslint.configs.recommended, + ...pluginVue.configs["flat/recommended"], + ], + plugins: { + '@typescript-eslint': tseslint.plugin, + }, + languageOptions: { + parserOptions: { + parser: tseslint.parser, + ecmaVersion: 'latest', + sourceType: 'module', + extraFileExtensions: ['.vue'], + ecmaFeatures: { + jsx: true + } + }, + }, + rules: { + '@typescript-eslint/ban-ts-comment': 'warn', + '@typescript-eslint/no-explicit-any': 'warn', + '@typescript-eslint/no-unsafe-function-type': 'warn', + '@typescript-eslint/no-unused-vars': 'off', // is checked by noUnusedLocals in tsconfig.json // or use ['error', { 'ignoreRestSiblings': true }] + 'no-unused-vars': 'off', // is checked by noUnusedLocals in tsconfig.json + 'no-undef': 'off', // types checked by typescript already + 'keyword-spacing': ['error', { before: true, after: true}], + 'linebreak-style': ['error', 'unix'], + 'lines-between-class-members': ['error', 'always', { exceptAfterSingleLine: true, }], + 'no-multiple-empty-lines': ['error', { max: 1, maxEOF: 0, maxBOF: 0 }], + 'object-curly-spacing': ['error', 'always'], + 'padded-blocks': ['error', 'never'], + 'quotes': ['error', 'single'], + 'semi': ['error', 'always'], + 'space-infix-ops': 'error', + 'indent': ['error', 2, { SwitchCase: 1 }], + 'vue/block-tag-newline': ['error', { singleline: 'consistent', multiline: 'consistent', }], + 'vue/html-closing-bracket-spacing': 'off', + 'vue/html-self-closing': 'off', + 'vue/max-attributes-per-line': 'off', + 'vue/padding-line-between-blocks': 'error', + 'vue/singleline-html-element-content-newline': 'off', + 'vue/space-infix-ops': 'error', + }, +} +); \ No newline at end of file diff --git a/frontend/package-lock.json b/frontend/package-lock.json index fc2531fb3..8a2e95188 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -34,21 +34,20 @@ "@types/mocha": "^10.0.7", "@types/node": "^20.12.7", "@types/semver": "^7.5.8", - "@typescript-eslint/eslint-plugin": "^8.1.0", - "@typescript-eslint/parser": "^8.1.0", "@vitejs/plugin-vue": "^5.1.2", "@vue/compiler-sfc": "^3.4.37", "autoprefixer": "^10.4.20", "chai": "^5.1.1", "chai-as-promised": "^8.0.0", - "eslint": "^8.57.0", - "eslint-plugin-vue": "^9.25.0", + "eslint": "^9.9.0", + "eslint-plugin-vue": "^9.27.0", "mocha": "^10.7.3", "nyc": "^17.0.0", "postcss": "^8.4.41", "tailwindcss": "^3.4.10", "ts-node": "^10.9.2", "typescript": "^5.5.4", + "typescript-eslint": "^8.2.0", "vite": "^5.4.0", "vue-tsc": "^2.0.29" }, @@ -520,17 +519,56 @@ "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, + "node_modules/@eslint/config-array": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.17.1.tgz", + "integrity": "sha512-BlYOpej8AQ8Ev9xVqroV7a02JK3SkBAaN9GfMMH9W6Ch8FlQlkjGw4Ir7+FgYwfirivAf4t+GtzuAxqfukmISA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.4", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-array/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/@eslint/eslintrc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz", + "integrity": "sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==", "dev": true, "license": "MIT", "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", + "espree": "^10.0.1", + "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", @@ -538,7 +576,7 @@ "strip-json-comments": "^3.1.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" @@ -555,6 +593,50 @@ "concat-map": "0.0.1" } }, + "node_modules/@eslint/eslintrc/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==", + "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/eslintrc/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==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.12.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@eslint/eslintrc/node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -569,13 +651,23 @@ } }, "node_modules/@eslint/js": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", - "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", + "version": "9.9.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.9.0.tgz", + "integrity": "sha512-hhetes6ZHP3BlXLxmd8K2SNgkhNSi+UcecbnwWKwpP7kyi/uC75DJ1lOOBO3xrC4jyojtGE3YxKZPHfk4yrgug==", "dev": true, "license": "MIT", "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "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==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, "node_modules/@headlessui/tailwindcss": { @@ -614,46 +706,6 @@ "vue": ">= 3" } }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.11.14", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", - "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", - "deprecated": "Use @eslint/config-array instead", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@humanwhocodes/object-schema": "^2.0.2", - "debug": "^4.3.1", - "minimatch": "^3.0.5" - }, - "engines": { - "node": ">=10.10.0" - } - }, - "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", @@ -668,13 +720,19 @@ "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", - "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", - "deprecated": "Use @eslint/object-schema instead", + "node_modules/@humanwhocodes/retry": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.0.tgz", + "integrity": "sha512-d2CGZR2o7fS6sWB7DG/3a95bGKQyHMACZ5aW8qGkkqQpUoZV6C0X7Pc7l4ZNMZkfNBf4VWNe9E1jRsf0G146Ew==", "dev": true, - "license": "BSD-3-Clause" + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } }, "node_modules/@intlify/bundle-utils": { "version": "8.0.0", @@ -1274,17 +1332,17 @@ "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.1.0.tgz", - "integrity": "sha512-LlNBaHFCEBPHyD4pZXb35mzjGkuGKXU5eeCA1SxvHfiRES0E82dOounfVpL4DCqYvJEKab0bZIA0gCRpdLKkCw==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.2.0.tgz", + "integrity": "sha512-02tJIs655em7fvt9gps/+4k4OsKULYGtLBPJfOsmOq1+3cdClYiF0+d6mHu6qDnTcg88wJBkcPLpQhq7FyDz0A==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.1.0", - "@typescript-eslint/type-utils": "8.1.0", - "@typescript-eslint/utils": "8.1.0", - "@typescript-eslint/visitor-keys": "8.1.0", + "@typescript-eslint/scope-manager": "8.2.0", + "@typescript-eslint/type-utils": "8.2.0", + "@typescript-eslint/utils": "8.2.0", + "@typescript-eslint/visitor-keys": "8.2.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", @@ -1308,16 +1366,16 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.1.0.tgz", - "integrity": "sha512-U7iTAtGgJk6DPX9wIWPPOlt1gO57097G06gIcl0N0EEnNw8RGD62c+2/DiP/zL7KrkqnnqF7gtFGR7YgzPllTA==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.2.0.tgz", + "integrity": "sha512-j3Di+o0lHgPrb7FxL3fdEy6LJ/j2NE8u+AP/5cQ9SKb+JLH6V6UHDqJ+e0hXBkHP1wn1YDFjYCS9LBQsZDlDEg==", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/scope-manager": "8.1.0", - "@typescript-eslint/types": "8.1.0", - "@typescript-eslint/typescript-estree": "8.1.0", - "@typescript-eslint/visitor-keys": "8.1.0", + "@typescript-eslint/scope-manager": "8.2.0", + "@typescript-eslint/types": "8.2.0", + "@typescript-eslint/typescript-estree": "8.2.0", + "@typescript-eslint/visitor-keys": "8.2.0", "debug": "^4.3.4" }, "engines": { @@ -1337,14 +1395,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.1.0.tgz", - "integrity": "sha512-DsuOZQji687sQUjm4N6c9xABJa7fjvfIdjqpSIIVOgaENf2jFXiM9hIBZOL3hb6DHK9Nvd2d7zZnoMLf9e0OtQ==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.2.0.tgz", + "integrity": "sha512-OFn80B38yD6WwpoHU2Tz/fTz7CgFqInllBoC3WP+/jLbTb4gGPTy9HBSTsbDWkMdN55XlVU0mMDYAtgvlUspGw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.1.0", - "@typescript-eslint/visitor-keys": "8.1.0" + "@typescript-eslint/types": "8.2.0", + "@typescript-eslint/visitor-keys": "8.2.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1355,14 +1413,14 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.1.0.tgz", - "integrity": "sha512-oLYvTxljVvsMnldfl6jIKxTaU7ok7km0KDrwOt1RHYu6nxlhN3TIx8k5Q52L6wR33nOwDgM7VwW1fT1qMNfFIA==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.2.0.tgz", + "integrity": "sha512-g1CfXGFMQdT5S+0PSO0fvGXUaiSkl73U1n9LTK5aRAFnPlJ8dLKkXr4AaLFvPedW8lVDoMgLLE3JN98ZZfsj0w==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "8.1.0", - "@typescript-eslint/utils": "8.1.0", + "@typescript-eslint/typescript-estree": "8.2.0", + "@typescript-eslint/utils": "8.2.0", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" }, @@ -1380,9 +1438,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.1.0.tgz", - "integrity": "sha512-q2/Bxa0gMOu/2/AKALI0tCKbG2zppccnRIRCW6BaaTlRVaPKft4oVYPp7WOPpcnsgbr0qROAVCVKCvIQ0tbWog==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.2.0.tgz", + "integrity": "sha512-6a9QSK396YqmiBKPkJtxsgZZZVjYQ6wQ/TlI0C65z7vInaETuC6HAHD98AGLC8DyIPqHytvNuS8bBVvNLKyqvQ==", "dev": true, "license": "MIT", "engines": { @@ -1394,14 +1452,14 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.1.0.tgz", - "integrity": "sha512-NTHhmufocEkMiAord/g++gWKb0Fr34e9AExBRdqgWdVBaKoei2dIyYKD9Q0jBnvfbEA5zaf8plUFMUH6kQ0vGg==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.2.0.tgz", + "integrity": "sha512-kiG4EDUT4dImplOsbh47B1QnNmXSoUqOjWDvCJw/o8LgfD0yr7k2uy54D5Wm0j4t71Ge1NkynGhpWdS0dEIAUA==", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/types": "8.1.0", - "@typescript-eslint/visitor-keys": "8.1.0", + "@typescript-eslint/types": "8.2.0", + "@typescript-eslint/visitor-keys": "8.2.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -1423,16 +1481,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.1.0.tgz", - "integrity": "sha512-ypRueFNKTIFwqPeJBfeIpxZ895PQhNyH4YID6js0UoBImWYoSjBsahUn9KMiJXh94uOjVBgHD9AmkyPsPnFwJA==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.2.0.tgz", + "integrity": "sha512-O46eaYKDlV3TvAVDNcoDzd5N550ckSe8G4phko++OCSC1dYIb9LTc3HDGYdWqWIAT5qDUKphO6sd9RrpIJJPfg==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.1.0", - "@typescript-eslint/types": "8.1.0", - "@typescript-eslint/typescript-estree": "8.1.0" + "@typescript-eslint/scope-manager": "8.2.0", + "@typescript-eslint/types": "8.2.0", + "@typescript-eslint/typescript-estree": "8.2.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1446,13 +1504,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.1.0.tgz", - "integrity": "sha512-ba0lNI19awqZ5ZNKh6wCModMwoZs457StTebQ0q1NP58zSi2F6MOZRXwfKZy+jB78JNJ/WH8GSh2IQNzXX8Nag==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.2.0.tgz", + "integrity": "sha512-sbgsPMW9yLvS7IhCi8IpuK1oBmtbWUNP+hBdwl/I9nzqVsszGnNGti5r9dUtF5RLivHUFFIdRvLiTsPhzSyJ3Q==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.1.0", + "@typescript-eslint/types": "8.2.0", "eslint-visitor-keys": "^3.4.3" }, "engines": { @@ -1463,13 +1521,6 @@ "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@ungap/structured-clone": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", - "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", - "dev": true, - "license": "ISC" - }, "node_modules/@vitejs/plugin-vue": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.1.2.tgz", @@ -2390,19 +2441,6 @@ "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", "license": "MIT" }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", @@ -2526,42 +2564,38 @@ } }, "node_modules/eslint": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", - "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", + "version": "9.9.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.9.0.tgz", + "integrity": "sha512-JfiKJrbx0506OEerjK2Y1QlldtBxkAlLxT5OEcRF8uaQ86noDe2k31Vw9rnSWv+MXZHj7OOUV/dA0AhdLFcyvA==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.57.0", - "@humanwhocodes/config-array": "^0.11.14", + "@eslint-community/regexpp": "^4.11.0", + "@eslint/config-array": "^0.17.1", + "@eslint/eslintrc": "^3.1.0", + "@eslint/js": "9.9.0", "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.3.0", "@nodelib/fs.walk": "^1.2.8", - "@ungap/structured-clone": "^1.2.0", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", "debug": "^4.3.2", - "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "esquery": "^1.4.2", + "eslint-scope": "^8.0.2", + "eslint-visitor-keys": "^4.0.0", + "espree": "^10.1.0", + "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", + "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", "lodash.merge": "^4.6.2", @@ -2575,10 +2609,18 @@ "eslint": "bin/eslint.js" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } } }, "node_modules/eslint-plugin-vue": { @@ -2645,6 +2687,54 @@ "concat-map": "0.0.1" } }, + "node_modules/eslint/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==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "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==", + "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/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==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.12.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/eslint/node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -2801,16 +2891,16 @@ } }, "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", "dev": true, "license": "MIT", "dependencies": { - "flat-cache": "^3.0.4" + "flat-cache": "^4.0.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=16.0.0" } }, "node_modules/file-saver": { @@ -2877,18 +2967,17 @@ } }, "node_modules/flat-cache": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", - "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", "dev": true, "license": "MIT", "dependencies": { "flatted": "^3.2.9", - "keyv": "^4.5.3", - "rimraf": "^3.0.2" + "keyv": "^4.5.4" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=16" } }, "node_modules/flatted": { @@ -5757,6 +5846,30 @@ "node": ">=14.17" } }, + "node_modules/typescript-eslint": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.2.0.tgz", + "integrity": "sha512-DmnqaPcML0xYwUzgNbM1XaKXpEb7BShYf2P1tkUmmcl8hyeG7Pj08Er7R9bNy6AufabywzJcOybQAtnD/c9DGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.2.0", + "@typescript-eslint/parser": "8.2.0", + "@typescript-eslint/utils": "8.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, "node_modules/ufo": { "version": "1.5.4", "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.5.4.tgz", diff --git a/frontend/package.json b/frontend/package.json index b4bed4b02..bd5382fc8 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -10,7 +10,7 @@ "scripts": { "dev": "vite", "build": "vue-tsc --noEmit && vite build", - "lint": "eslint -c .eslintrc.cjs", + "lint": "eslint", "test": "nyc --reporter lcov mocha", "serve": "vite preview", "dist": "vue-tsc --noEmit && vite build --sourcemap --outDir=\"../backend/src/main/resources/META-INF/resources\" --emptyOutDir" @@ -34,21 +34,20 @@ "@types/mocha": "^10.0.7", "@types/node": "^20.12.7", "@types/semver": "^7.5.8", - "@typescript-eslint/eslint-plugin": "^8.1.0", - "@typescript-eslint/parser": "^8.1.0", "@vitejs/plugin-vue": "^5.1.2", "@vue/compiler-sfc": "^3.4.37", "autoprefixer": "^10.4.20", "chai": "^5.1.1", "chai-as-promised": "^8.0.0", - "eslint": "^8.57.0", - "eslint-plugin-vue": "^9.25.0", + "eslint": "^9.9.0", + "eslint-plugin-vue": "^9.27.0", "mocha": "^10.7.3", "nyc": "^17.0.0", "postcss": "^8.4.41", "tailwindcss": "^3.4.10", "ts-node": "^10.9.2", "typescript": "^5.5.4", + "typescript-eslint": "^8.2.0", "vite": "^5.4.0", "vue-tsc": "^2.0.29" }, From cd5d146ab7b6cf19a7b82dbb6eb4dc929cf84035 Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Thu, 22 Aug 2024 12:46:09 +0200 Subject: [PATCH 4/5] fix various linter problems --- frontend/src/common/auditlog.ts | 6 +++--- frontend/src/common/backend.ts | 15 ++++++++------- frontend/src/common/crypto.ts | 5 ++--- frontend/src/common/jwe.ts | 6 +++--- frontend/src/common/jwt.ts | 6 +++--- frontend/src/common/updatecheck.ts | 2 +- frontend/src/common/userdata.ts | 2 -- frontend/src/common/util.ts | 7 ++++--- frontend/src/common/wot.ts | 4 ++-- frontend/src/components/AdminSettings.vue | 6 +++--- .../components/AuditLogDetailsSignedWotId.vue | 2 +- frontend/src/components/DeviceList.vue | 2 +- .../src/components/GrantPermissionDialog.vue | 3 +-- frontend/src/components/NavigationBar.vue | 10 ++++++---- frontend/src/components/SignUserKeysDialog.vue | 8 ++++---- frontend/src/components/TrustDetails.vue | 18 +++++++++--------- frontend/src/components/UserProfile.vue | 2 +- frontend/src/components/UserkeyFingerprint.vue | 3 +-- frontend/src/components/VaultDetails.vue | 4 ++-- frontend/src/components/VaultList.vue | 2 +- frontend/src/i18n/index.ts | 2 +- frontend/src/router/index.ts | 4 ++-- frontend/src/shims-vue.d.ts | 2 +- frontend/test/common/crypto.spec.ts | 16 ++++++---------- frontend/test/common/jwe.spec.ts | 7 +++---- frontend/test/common/jwt.spec.ts | 6 ++---- frontend/test/common/util.spec.ts | 4 ++-- 27 files changed, 73 insertions(+), 81 deletions(-) diff --git a/frontend/src/common/auditlog.ts b/frontend/src/common/auditlog.ts index 5ccdbdd95..c9531d260 100644 --- a/frontend/src/common/auditlog.ts +++ b/frontend/src/common/auditlog.ts @@ -116,7 +116,7 @@ export class AuditLogEntityCache { return this.getEntity(deviceId, this.devices, this.debouncedResolvePendingDevices); } - private async getEntity(entityId: string, entities: Map>, debouncedResolvePendingEntities: Function): Promise { + private async getEntity(entityId: string, entities: Map>, debouncedResolvePendingEntities: () => void): Promise { const cachedEntity = entities.get(entityId); if (!cachedEntity) { const deferredEntity = new Deferred(); @@ -133,8 +133,8 @@ export class AuditLogEntityCache { private debouncedResolvePendingDevices = debounce(async () => await this.resolvePendingEntities(this.devices, backend.devices.listSome), 100); private async resolvePendingEntities(entities: Map>, listSome: (ids: string[]) => Promise): Promise { - const pendingEntities = Array.from(entities.entries()).filter(([_, v]) => v.status === 'pending'); - const entitiesResult = await listSome(pendingEntities.map(([k, _]) => k)); + const pendingEntities = Array.from(entities.entries()).filter(([, v]) => v.status === 'pending'); + const entitiesResult = await listSome(pendingEntities.map(([k,]) => k)); for (const [entityId, deferredEntity] of pendingEntities) { const entity = entitiesResult.find(v => v.id === entityId); if (entity) { diff --git a/frontend/src/common/backend.ts b/frontend/src/common/backend.ts index b833e7541..47cbc11f3 100644 --- a/frontend/src/common/backend.ts +++ b/frontend/src/common/backend.ts @@ -27,7 +27,7 @@ axiosAuth.interceptors.request.use(async request => { request.headers = AxiosHeaders.from({ 'Authorization': `Bearer ${token}` }); } return request; - } catch (err: unknown) { + } catch { // only things from auth module can throw errors here throw new UnauthorizedError(); } @@ -160,7 +160,7 @@ class VaultService { public async get(vaultId: string): Promise { return axiosAuth.get(`/vaults/${vaultId}`) .then(response => { - let dateString = response.data.creationTime; + const dateString = response.data.creationTime; response.data.creationTime = new Date(dateString); return response.data; }) @@ -228,12 +228,12 @@ class DeviceService { return axiosAuth.get(`/devices?${query}`).then(response => response.data); } - public async removeDevice(deviceId: string): Promise> { + public async removeDevice(deviceId: string): Promise> { return axiosAuth.delete(`/devices/${deviceId}`) .catch((error) => rethrowAndConvertIfExpected(error, 404)); } - public async putDevice(device: DeviceDto): Promise> { + public async putDevice(device: DeviceDto): Promise> { return axiosAuth.put(`/devices/${device.id}`, device); } } @@ -260,6 +260,7 @@ class TrustService { public async trustUser(userId: string, signature: string): Promise { return axiosAuth.put(`/users/trusted/${userId}`, signature, { headers: { 'Content-Type': 'text/plain' } }); } + public async get(userId: string): Promise { return axiosAuth.get(`/users/trusted/${userId}`).then(response => response.data) .catch(e => { @@ -288,9 +289,9 @@ class AuthorityService { return { ...authority, pictureUrl: authority.pictureUrl - } + }; } else { - let cfg = AuthorityService.getJdenticonConfig(authority.type); + const cfg = AuthorityService.getJdenticonConfig(authority.type); const svg = toSvg(authority.id, 100, cfg); const bytes = new TextEncoder().encode(svg); const url = `data:image/svg+xml;base64,${base64.stringify(bytes)}`; @@ -407,7 +408,7 @@ function convertExpectedToBackendError(status: number): BackendError { * @param error A thrown object * @param expectedStatusCodes The expected http status codes of the backend call */ -export function rethrowAndConvertIfExpected(error: unknown, ...expectedStatusCodes: number[]): Promise { +export function rethrowAndConvertIfExpected(error: unknown, ...expectedStatusCodes: number[]): never { if (AxiosStatic.isAxiosError(error) && error.response != null && expectedStatusCodes.includes(error.response.status)) { throw convertExpectedToBackendError(error.response.status); } else { diff --git a/frontend/src/common/crypto.ts b/frontend/src/common/crypto.ts index 351741ff6..f7bd3a5b0 100644 --- a/frontend/src/common/crypto.ts +++ b/frontend/src/common/crypto.ts @@ -3,9 +3,9 @@ import { base16, base32, base64, base64url } from 'rfc4648'; import { JWEBuilder, JWEParser } from './jwe'; import { CRC32, DB, wordEncoder } from './util'; export class UnwrapKeyError extends Error { - readonly actualError: any; + readonly actualError: unknown; - constructor(actualError: any) { + constructor(actualError: unknown) { super('Unwrapping key failed'); this.actualError = actualError; } @@ -270,7 +270,6 @@ export class UserKeys { public static readonly ECDSA_KEY_DESIGNATION: EcKeyImportParams | EcKeyGenParams = { name: 'ECDSA', namedCurve: 'P-384' }; - protected constructor(readonly ecdhKeyPair: CryptoKeyPair, readonly ecdsaKeyPair: CryptoKeyPair) { } /** diff --git a/frontend/src/common/jwe.ts b/frontend/src/common/jwe.ts index b73cb8e8e..e4af50cd3 100644 --- a/frontend/src/common/jwe.ts +++ b/frontend/src/common/jwe.ts @@ -81,7 +81,7 @@ export class JWEParser { * @param recipientPrivateKey The recipient's private key * @returns Decrypted payload */ - public async decryptEcdhEs(recipientPrivateKey: CryptoKey): Promise { + public async decryptEcdhEs(recipientPrivateKey: CryptoKey): Promise { if (this.header.alg != 'ECDH-ES' || this.header.enc != 'A256GCM' || !this.header.epk) { throw new Error('unsupported alg or enc'); } @@ -96,7 +96,7 @@ export class JWEParser { * @returns Decrypted payload * @throws {UnwrapKeyError} if decryption failed (wrong password?) */ - public async decryptPbes2(password: string): Promise { + public async decryptPbes2(password: string): Promise { if (this.header.alg != 'PBES2-HS512+A256KW' || /* this.header.enc != 'A256GCM' || */ !this.header.p2s || !this.header.p2c) { throw new Error('unsupported alg or enc'); } @@ -110,7 +110,7 @@ export class JWEParser { } } - private async decrypt(cek: CryptoKey): Promise { + private async decrypt(cek: CryptoKey): Promise { const utf8enc = new TextEncoder(); const m = new Uint8Array(this.ciphertext.length + this.tag.length); m.set(this.ciphertext, 0); diff --git a/frontend/src/common/jwt.ts b/frontend/src/common/jwt.ts index f7a7d00a1..be174c899 100644 --- a/frontend/src/common/jwt.ts +++ b/frontend/src/common/jwt.ts @@ -18,7 +18,7 @@ export class JWT { * @param payload The payload * @param signerPrivateKey The signers's private key */ - public static async build(header: JWTHeader, payload: any, signerPrivateKey: CryptoKey): Promise { + public static async build(header: JWTHeader, payload: object, signerPrivateKey: CryptoKey): Promise { const encodedHeader = base64url.stringify(new TextEncoder().encode(JSON.stringify(header)), { pad: false }); const encodedPayload = base64url.stringify(new TextEncoder().encode(JSON.stringify(payload)), { pad: false }); const encodedSignature = await this.es384sign(encodedHeader, encodedPayload, signerPrivateKey); @@ -46,8 +46,8 @@ export class JWT { * @returns header and payload * @throws Error if the JWT is invalid */ - public static async parse(jwt: string, signerPublicKey: CryptoKey): Promise<[JWTHeader, any]> { - const [encodedHeader, encodedPayload, encodedSignature] = jwt.split('.'); + public static async parse(jwt: string, signerPublicKey: CryptoKey): Promise<[JWTHeader, object]> { + const [encodedHeader, encodedPayload] = jwt.split('.'); const header: JWTHeader = JSON.parse(new TextDecoder().decode(base64url.parse(encodedHeader, { loose: true }))); if (header.alg !== 'ES384') { throw new Error('Unsupported algorithm'); diff --git a/frontend/src/common/updatecheck.ts b/frontend/src/common/updatecheck.ts index 94bebbbdb..40810fafa 100644 --- a/frontend/src/common/updatecheck.ts +++ b/frontend/src/common/updatecheck.ts @@ -9,7 +9,7 @@ export type LatestVersionDto = { class UpdatesService { public async get(localVersion: string): Promise { - let config = { + const config = { headers: { 'Content-Type': 'application/json', 'Cryptomator-Hub-Version': localVersion, diff --git a/frontend/src/common/userdata.ts b/frontend/src/common/userdata.ts index 800f6c80b..2cb8cb694 100644 --- a/frontend/src/common/userdata.ts +++ b/frontend/src/common/userdata.ts @@ -4,7 +4,6 @@ import { BrowserKeys, UserKeys } from './crypto'; import { JWEParser } from './jwe'; class UserData { - #me?: Promise; #browserKeys?: Promise; @@ -136,7 +135,6 @@ class UserData { await backend.users.putMe(me); } } - } const instance = new UserData(); diff --git a/frontend/src/common/util.ts b/frontend/src/common/util.ts index 1eafa76fb..a0a731113 100644 --- a/frontend/src/common/util.ts +++ b/frontend/src/common/util.ts @@ -3,7 +3,7 @@ import { dictionary } from './4096words_en'; export class DB { private static readonly NAME = 'hub'; - public static async transaction(objectStore: string, mode: IDBTransactionMode, query: (transaction: IDBTransaction) => IDBRequest): Promise { + public static async transaction(objectStore: string, mode: IDBTransactionMode, query: (transaction: IDBTransaction) => IDBRequest): Promise { const db = await new Promise((resolve, reject) => { const req = indexedDB.open(DB.NAME); req.onsuccess = () => resolve(req.result); @@ -23,7 +23,7 @@ export class DB { export class Deferred { public promise: Promise; - public reject: (reason?: any) => void; + public reject: (reason?: unknown) => void; public resolve: (value: T) => void; public status: 'pending' | 'resolved' | 'rejected' = 'pending'; @@ -43,9 +43,10 @@ export class Deferred { * @param wait time to wait before calling function * @returns debounced function */ +// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type export const debounce = (func: Function, wait = 300) => { let timeoutId: ReturnType; - function debounceCore(this: any, ...args: any[]) { + function debounceCore(this: unknown, ...args: unknown[]) { cancel(); timeoutId = setTimeout(() => func.apply(this, args), wait); } diff --git a/frontend/src/common/wot.ts b/frontend/src/common/wot.ts index dcf5fb675..2fb89e6ea 100644 --- a/frontend/src/common/wot.ts +++ b/frontend/src/common/wot.ts @@ -48,7 +48,7 @@ async function sign(user: UserDto): Promise { * @param allegedSignedKey The public key that should be signed by the last signature in the chain */ async function verify(signatureChain: string[], allegedSignedKey: SignedKeys) { - let signerPublicKey = await userdata.decryptUserKeysWithBrowser().then(keys => keys.ecdsaKeyPair.publicKey); + const signerPublicKey = await userdata.decryptUserKeysWithBrowser().then(keys => keys.ecdsaKeyPair.publicKey); await verifyRescursive(signatureChain, signerPublicKey, allegedSignedKey); } @@ -62,7 +62,7 @@ async function verify(signatureChain: string[], allegedSignedKey: SignedKeys) { async function verifyRescursive(signatureChain: string[], signerPublicKey: CryptoKey, allegedSignedKey: SignedKeys) { // get first element of signature chain: const [signature, ...remainingChain] = signatureChain; - const [_, signedKeys] = await JWT.parse(signature, signerPublicKey) as [JWTHeader, SignedKeys]; + const [, signedKeys] = await JWT.parse(signature, signerPublicKey) as [JWTHeader, SignedKeys]; if (remainingChain.length === 0) { // last element in chain should match signed public key if (!deeplyEqual(signedKeys, allegedSignedKey)) { diff --git a/frontend/src/components/AdminSettings.vue b/frontend/src/components/AdminSettings.vue index 88724efab..cf264f5f2 100644 --- a/frontend/src/components/AdminSettings.vue +++ b/frontend/src/components/AdminSettings.vue @@ -238,7 +238,7 @@ const numberOfExceededSeats = computed(() => { }); onMounted(async () => { - let cfg = config.get(); + const cfg = config.get(); keycloakAdminRealmURL.value = `${cfg.keycloakUrl}/admin/${cfg.keycloakRealm}/console`; if (props.token) { await setToken(props.token); @@ -256,8 +256,8 @@ async function setToken(token: string) { async function fetchData() { try { - let versionDto = backend.version.get(); - let versionAvailable = versionDto.then(versionDto => updateChecker.get(versionDto.hubVersion)); + const versionDto = backend.version.get(); + const versionAvailable = versionDto.then(versionDto => updateChecker.get(versionDto.hubVersion)); admin.value = await backend.billing.get(); version.value = await versionDto; latestVersion.value = await versionAvailable; diff --git a/frontend/src/components/AuditLogDetailsSignedWotId.vue b/frontend/src/components/AuditLogDetailsSignedWotId.vue index a537e6fae..89f6de459 100644 --- a/frontend/src/components/AuditLogDetailsSignedWotId.vue +++ b/frontend/src/components/AuditLogDetailsSignedWotId.vue @@ -77,7 +77,7 @@ onMounted(async () => { try { const signerPublicKey = await asPublicKey(base64.parse(props.event.signerKey), UserKeys.ECDSA_KEY_DESIGNATION, UserKeys.ECDSA_PUB_KEY_USAGES); const [_, signedKeys] = await JWT.parse(props.event.signature, signerPublicKey) as [JWTHeader, SignedKeys]; - signedFingerprint.value = await wot.computeFingerprint({ecdhPublicKey: signedKeys.ecdhPublicKey, ecdsaPublicKey: signedKeys.ecdsaPublicKey}); + signedFingerprint.value = await wot.computeFingerprint({ ecdhPublicKey: signedKeys.ecdhPublicKey, ecdsaPublicKey: signedKeys.ecdsaPublicKey }); if (props.event.signerKey === signingUser?.ecdsaPublicKey && signedFingerprint.value === currentFingerprint.value) { signatureStatus.value = SignatureStatus.STILL_VALID; } else if (props.event.signerKey !== signingUser?.ecdsaPublicKey) { diff --git a/frontend/src/components/DeviceList.vue b/frontend/src/components/DeviceList.vue index abb6e7591..c11e6a976 100644 --- a/frontend/src/components/DeviceList.vue +++ b/frontend/src/components/DeviceList.vue @@ -120,7 +120,7 @@ async function removeDevice(device: DeviceDto) { if (error instanceof NotFoundError) { // if device is already missing in backend → ignore and proceed to then() } else { - let e = error instanceof Error ? error : new Error('Unknown Error'); + const e = error instanceof Error ? error : new Error('Unknown Error'); onRemoveDeviceError.value[device.id] = e; throw e; } diff --git a/frontend/src/components/GrantPermissionDialog.vue b/frontend/src/components/GrantPermissionDialog.vue index 224d71899..6da9e8557 100644 --- a/frontend/src/components/GrantPermissionDialog.vue +++ b/frontend/src/components/GrantPermissionDialog.vue @@ -73,7 +73,6 @@ import backend, { AccessGrant, ConflictError, NotFoundError, TrustDto, UserDto, import { VaultKeys } from '../common/crypto'; import TrustDetails from './TrustDetails.vue'; - const { t } = useI18n({ useScope: 'global' }); const open = ref(false); @@ -122,7 +121,7 @@ async function grantAccess() { } async function giveUsersAccess(users: UserDto[]) { - let tokens: AccessGrant[] = []; + const tokens: AccessGrant[] = []; for (const user of users) { if (user.ecdhPublicKey) { // some users might not have set up their key pair, so we can't share secrets with them yet const publicKey = base64.parse(user.ecdhPublicKey); diff --git a/frontend/src/components/NavigationBar.vue b/frontend/src/components/NavigationBar.vue index 8edd89672..d0225299f 100644 --- a/frontend/src/components/NavigationBar.vue +++ b/frontend/src/components/NavigationBar.vue @@ -68,8 +68,8 @@ diff --git a/frontend/src/components/VaultDetails.vue b/frontend/src/components/VaultDetails.vue index abcdb3ce8..2d944e1f7 100644 --- a/frontend/src/components/VaultDetails.vue +++ b/frontend/src/components/VaultDetails.vue @@ -364,7 +364,7 @@ async function reloadDevicesRequiringAccessGrant() { } } -function isAuthorityDto(toCheck: any): toCheck is AuthorityDto { +function isAuthorityDto(toCheck: unknown): toCheck is AuthorityDto { return (toCheck as AuthorityDto).type != null; } @@ -391,7 +391,7 @@ async function addAuthority(authority: AuthorityDto) { async function addAuthorityBackend(authority: AuthorityDto) { try { - switch(authority.type) { + switch (authority.type) { case 'USER': await backend.vaults.addUser(props.vaultId, authority.id); break; diff --git a/frontend/src/components/VaultList.vue b/frontend/src/components/VaultList.vue index 0efdf3285..a57981d6d 100644 --- a/frontend/src/components/VaultList.vue +++ b/frontend/src/components/VaultList.vue @@ -8,7 +8,7 @@ - +

{{ t('vaultList.title') }} diff --git a/frontend/src/i18n/index.ts b/frontend/src/i18n/index.ts index beea492c6..ce67dd38c 100644 --- a/frontend/src/i18n/index.ts +++ b/frontend/src/i18n/index.ts @@ -36,4 +36,4 @@ export const numberFormats: I18nOptions['numberFormats'] = { style: 'percent', useGrouping: false } } -} +}; diff --git a/frontend/src/router/index.ts b/frontend/src/router/index.ts index c422ee44d..8522fe71f 100644 --- a/frontend/src/router/index.ts +++ b/frontend/src/router/index.ts @@ -1,4 +1,4 @@ -import { createRouter, createWebHistory, RouteLocationRaw, RouteLocationResolvedGeneric, RouteRecordRaw } from 'vue-router'; +import { createRouter, createWebHistory, RouteLocationRaw, RouteRecordRaw } from 'vue-router'; import authPromise from '../common/auth'; import backend from '../common/backend'; import { baseURL } from '../common/config'; @@ -149,7 +149,7 @@ router.beforeEach((to, from, next) => { await backend.users.putMe(); } }).finally(() => { - let {sync_me: _, ...remainingQuery} = to.query; // remove sync_me query parameter to avoid endless recursion + const { sync_me: _, ...remainingQuery } = to.query; // remove sync_me query parameter to avoid endless recursion next({ path: to.path, query: remainingQuery, replace: true }); }); } else { diff --git a/frontend/src/shims-vue.d.ts b/frontend/src/shims-vue.d.ts index fe7917e04..b92e77e23 100644 --- a/frontend/src/shims-vue.d.ts +++ b/frontend/src/shims-vue.d.ts @@ -1,6 +1,6 @@ declare module '*.vue' { import { DefineComponent } from 'vue'; - // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types + // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-empty-object-type const component: DefineComponent<{}, {}, any>; export default component; } diff --git a/frontend/test/common/crypto.spec.ts b/frontend/test/common/crypto.spec.ts index 639fba7f0..d259c8992 100644 --- a/frontend/test/common/crypto.spec.ts +++ b/frontend/test/common/crypto.spec.ts @@ -1,9 +1,9 @@ import { use as chaiUse, expect } from 'chai'; import chaiAsPromised from 'chai-as-promised'; import { before, describe } from 'mocha'; +import { webcrypto } from 'node:crypto'; import { base64, base64url } from 'rfc4648'; import { UnwrapKeyError, UserKeys, VaultKeys, getJwkThumbprint } from '../../src/common/crypto'; -import { webcrypto } from 'node:crypto'; chaiUse(chaiAsPromised); @@ -36,14 +36,13 @@ describe('crypto', () => { before(async () => { // since this test runs on Node, we need to replace window.crypto: - // @ts-ignore: global not defined (but will be available within Node) Object.defineProperty(global, 'crypto', { value: webcrypto }); - // @ts-ignore: global not defined (but will be available within Node) + // @ts-expect-error: incomplete 'window' type global.window = { crypto: global.crypto }; // prepare some test key pairs: - let ecdhP384: EcKeyImportParams = { name: 'ECDH', namedCurve: 'P-384' }; - let ecdsaP384: EcKeyImportParams = { name: 'ECDSA', namedCurve: 'P-384' }; + const ecdhP384: EcKeyImportParams = { name: 'ECDH', namedCurve: 'P-384' }; + const ecdsaP384: EcKeyImportParams = { name: 'ECDSA', namedCurve: 'P-384' }; const aliceEcdhPrv = crypto.subtle.importKey('jwk', alicePrivate, ecdhP384, true, ['deriveKey', 'deriveBits']); const aliceEcdhPub = crypto.subtle.importKey('jwk', alicePublic, ecdhP384, true, []); const aliceEcdsaPrv = crypto.subtle.importKey('jwk', alicePrivate, ecdsaP384, true, ['sign']); @@ -63,7 +62,7 @@ describe('crypto', () => { }); it('recover() succeeds for valid key', async () => { - let recoveryKey = ` + const recoveryKey = ` pathway lift abuse plenty export texture gentleman landscape beyond ceiling around leaf cafe charity border breakdown victory surely computer cat linger restrict infer crowd live computer true written amazed investor boot depth left theory snow whereby terminal weekly reject happiness circuit partial cup ad @@ -239,12 +238,10 @@ describe('crypto', () => { }); }); - describe('JWK Thumbprint', () => { - // https://datatracker.ietf.org/doc/html/rfc7638#section-3.1 it('compute example thumbprint from RFC 7638, Section 3.1', async () => { - const input: JsonWebKey & any = { + const input: JsonWebKey & Record = { kty: 'RSA', n: '0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw', e: 'AQAB', @@ -256,7 +253,6 @@ describe('crypto', () => { expect(base64url.stringify(thumbprint, { pad: false })).to.eq('NzbLsXh8uDCcd-6MNwXF4W_7noWXFZAfHkxZsRGC9Xs'); }); - }); }); diff --git a/frontend/test/common/jwe.spec.ts b/frontend/test/common/jwe.spec.ts index f8b43a906..57c320332 100644 --- a/frontend/test/common/jwe.spec.ts +++ b/frontend/test/common/jwe.spec.ts @@ -1,15 +1,14 @@ import { expect } from 'chai'; import { describe } from 'mocha'; +import { webcrypto } from 'node:crypto'; import { base64url } from 'rfc4648'; import { ConcatKDF, ECDH_ES, ECDH_P384, JWEBuilder, JWEHeader, JWEParser, PBES2 } from '../../src/common/jwe'; -import { webcrypto } from 'node:crypto'; describe('JWE', () => { before(done => { // since this test runs on Node, we need to replace window.crypto: - // @ts-ignore: global not defined (but will be available within Node) Object.defineProperty(global, 'crypto', { value: webcrypto }); - // @ts-ignore: global not defined (but will be available within Node) + // @ts-expect-error: incomplete 'window' type global.window = { crypto: global.crypto }; done(); }); @@ -23,7 +22,7 @@ describe('JWE', () => { const suppPubInfo = new Uint8Array([0, 0, 0, 128]); const otherInfo = new Uint8Array([...algorithmId, ...partyUInfo, ...partyVInfo, ...new Uint8Array(suppPubInfo)]); - let derivedKey = await ConcatKDF.kdf(z, 16, otherInfo); + const derivedKey = await ConcatKDF.kdf(z, 16, otherInfo); expect(new Uint8Array(derivedKey), 'derived key').to.eql(new Uint8Array([86, 170, 141, 234, 248, 35, 109, 32, 92, 34, 40, 205, 113, 167, 16, 26])); }); }); diff --git a/frontend/test/common/jwt.spec.ts b/frontend/test/common/jwt.spec.ts index 0a548bfde..8d8a2b673 100644 --- a/frontend/test/common/jwt.spec.ts +++ b/frontend/test/common/jwt.spec.ts @@ -1,14 +1,13 @@ import { expect } from 'chai'; import { describe } from 'mocha'; -import { JWT, JWTHeader } from '../../src/common/jwt'; import { webcrypto } from 'node:crypto'; +import { JWT, JWTHeader } from '../../src/common/jwt'; describe('JWT', () => { before(done => { // since this test runs on Node, we need to replace window.crypto: - // @ts-ignore: global not defined (but will be available within Node) Object.defineProperty(global, 'crypto', { value: webcrypto }); - // @ts-ignore: global not defined (but will be available within Node) + // @ts-expect-error: incomplete 'window' type global.window = { crypto: global.crypto }; done(); }); @@ -86,6 +85,5 @@ describe('JWT', () => { expect(header).to.deep.equal({ alg: 'ES384', typ: 'JWT', b64: true }); expect(payload).to.deep.equal({ foo: 42, bar: 'lol', obj: { nested: true } }); }); - }); }); diff --git a/frontend/test/common/util.spec.ts b/frontend/test/common/util.spec.ts index d6865af83..2fedf3c59 100644 --- a/frontend/test/common/util.spec.ts +++ b/frontend/test/common/util.spec.ts @@ -22,9 +22,9 @@ describe('WordEncoder', () => { describe('CRC32', () => { it('crc32(\'123456789\') == 0xCBF43926', () => { - let input = new TextEncoder().encode('123456789'); + const input = new TextEncoder().encode('123456789'); - let result = CRC32.compute(input); + const result = CRC32.compute(input); expect(result).to.eql(0xCBF43926); }); From 22f82b739eaabe32fb3e4266caf4588122e321e9 Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Thu, 22 Aug 2024 12:50:41 +0200 Subject: [PATCH 5/5] remove dead config [ci skip] --- frontend/.vscode/settings.json | 4 ---- 1 file changed, 4 deletions(-) diff --git a/frontend/.vscode/settings.json b/frontend/.vscode/settings.json index c22203ac4..fbd6dd8c8 100644 --- a/frontend/.vscode/settings.json +++ b/frontend/.vscode/settings.json @@ -25,10 +25,6 @@ "--no-warnings=ExperimentalWarning", "--experimental-specifier-resolution=node" ], - "mochaExplorer.env": { - //"TS_NODE_COMPILER_OPTIONS": "{\"module\": \"commonjs\" }", - // "TS_NODE_PROJECT": "./test/tsconfig.json" - }, "mochaExplorer.files": "test/**/*.spec.ts", "mochaExplorer.require": "ts-node/register", "eslint.validate": ["typescript", "javascript", "vue"],