From f52b42d844498097508d2173c101aa2fb93dd57c Mon Sep 17 00:00:00 2001 From: sharevb Date: Fri, 23 Aug 2024 21:37:18 +0200 Subject: [PATCH] feat(new tool): Passphrase Generator Fix #1242 and #1228 --- components.d.ts | 2 + package.json | 1 + pnpm-lock.yaml | 28 ++++-- src/composable/queryParams.ts | 33 ++++++- src/tools/index.ts | 16 +++- src/tools/passphrase-generator/index.ts | 12 +++ .../passphrase-generator.vue | 85 +++++++++++++++++++ 7 files changed, 168 insertions(+), 9 deletions(-) create mode 100644 src/tools/passphrase-generator/index.ts create mode 100644 src/tools/passphrase-generator/passphrase-generator.vue diff --git a/components.d.ts b/components.d.ts index 89f41f80..5dbc8ffd 100644 --- a/components.d.ts +++ b/components.d.ts @@ -144,9 +144,11 @@ declare module '@vue/runtime-core' { NMenu: typeof import('naive-ui')['NMenu'] NScrollbar: typeof import('naive-ui')['NScrollbar'] NSlider: typeof import('naive-ui')['NSlider'] + NSpace: typeof import('naive-ui')['NSpace'] NSwitch: typeof import('naive-ui')['NSwitch'] NumeronymGenerator: typeof import('./src/tools/numeronym-generator/numeronym-generator.vue')['default'] OtpCodeGeneratorAndValidator: typeof import('./src/tools/otp-code-generator-and-validator/otp-code-generator-and-validator.vue')['default'] + PassphraseGenerator: typeof import('./src/tools/passphrase-generator/passphrase-generator.vue')['default'] PasswordStrengthAnalyser: typeof import('./src/tools/password-strength-analyser/password-strength-analyser.vue')['default'] PdfSignatureChecker: typeof import('./src/tools/pdf-signature-checker/pdf-signature-checker.vue')['default'] PdfSignatureDetails: typeof import('./src/tools/pdf-signature-checker/components/pdf-signature-details.vue')['default'] diff --git a/package.json b/package.json index 6191f702..4b920375 100644 --- a/package.json +++ b/package.json @@ -82,6 +82,7 @@ "pinia": "^2.0.34", "plausible-tracker": "^0.3.8", "qrcode": "^1.5.1", + "silly-password-generator": "^1.0.28", "sql-formatter": "^13.0.0", "ua-parser-js": "^1.0.35", "ulid": "^2.3.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3044541a..af02a6ed 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -146,6 +146,9 @@ dependencies: qrcode: specifier: ^1.5.1 version: 1.5.1 + silly-password-generator: + specifier: ^1.0.28 + version: 1.0.28 sql-formatter: specifier: ^13.0.0 version: 13.0.0 @@ -3360,7 +3363,7 @@ packages: dependencies: '@unhead/dom': 0.5.1 '@unhead/schema': 0.5.1 - '@vueuse/shared': 10.11.1(vue@3.3.4) + '@vueuse/shared': 11.0.1(vue@3.3.4) unhead: 0.5.1 vue: 3.3.4 transitivePeerDependencies: @@ -3993,19 +3996,19 @@ packages: - vue dev: false - /@vueuse/shared@10.11.1(vue@3.3.4): - resolution: {integrity: sha512-LHpC8711VFZlDaYUXEBbFBCQ7GS3dVU9mjOhhMhXP6txTV4EhYQg/KGnQuvt/sPAtoUKq7VVUnL6mVtFoL42sA==} + /@vueuse/shared@10.3.0(vue@3.3.4): + resolution: {integrity: sha512-kGqCTEuFPMK4+fNWy6dUOiYmxGcUbtznMwBZLC1PubidF4VZY05B+Oht7Jh7/6x4VOWGpvu3R37WHi81cKpiqg==} dependencies: - vue-demi: 0.14.10(vue@3.3.4) + vue-demi: 0.14.5(vue@3.3.4) transitivePeerDependencies: - '@vue/composition-api' - vue dev: false - /@vueuse/shared@10.3.0(vue@3.3.4): - resolution: {integrity: sha512-kGqCTEuFPMK4+fNWy6dUOiYmxGcUbtznMwBZLC1PubidF4VZY05B+Oht7Jh7/6x4VOWGpvu3R37WHi81cKpiqg==} + /@vueuse/shared@11.0.1(vue@3.3.4): + resolution: {integrity: sha512-eAPf5CQB3HR0S76HqrhjBqFYstZfiHWZq8xF9EQmobGBkrhPfErJEhr8aMNQMqd6MkENIx2pblIEfJGlHpClug==} dependencies: - vue-demi: 0.14.5(vue@3.3.4) + vue-demi: 0.14.10(vue@3.3.4) transitivePeerDependencies: - '@vue/composition-api' - vue @@ -8106,6 +8109,13 @@ packages: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} dev: true + /silly-password-generator@1.0.28: + resolution: {integrity: sha512-wan9blB6e/5jVmfHDiXRRuwaoA2xnEtA9kZSvOnC7xwbLo+nFjyUm5JaN1MDA0vmuxJ5hoVbVxonkpPIWlipdg==} + dependencies: + lodash: 4.17.21 + zxcvbn: 4.4.2 + dev: false + /sirv@2.0.3: resolution: {integrity: sha512-O9jm9BsID1P+0HOi81VpXPoDxYP374pkOLzACAoyUQ/3OUVndNpsz6wMnY2z+yOxzbllCKZrM+9QrWsv4THnyA==} engines: {node: '>= 10'} @@ -9680,3 +9690,7 @@ packages: which: 3.0.0 yaml: 2.2.1 dev: true + + /zxcvbn@4.4.2: + resolution: {integrity: sha512-Bq0B+ixT/DMyG8kgX2xWcI5jUvCwqrMxSFam7m0lAf78nf04hv6lNCsyLYdyYTrCVMqNDY/206K7eExYCeSyUQ==} + dev: false diff --git a/src/composable/queryParams.ts b/src/composable/queryParams.ts index 9699abbc..7cc8cc0d 100644 --- a/src/composable/queryParams.ts +++ b/src/composable/queryParams.ts @@ -1,7 +1,8 @@ import { useRouteQuery } from '@vueuse/router'; import { computed } from 'vue'; +import { useStorage } from '@vueuse/core'; -export { useQueryParam }; +export { useQueryParam, useQueryParamOrStorage }; const transformers = { number: { @@ -16,6 +17,12 @@ const transformers = { fromQuery: (value: string) => value.toLowerCase() === 'true', toQuery: (value: boolean) => (value ? 'true' : 'false'), }, + object: { + fromQuery: (value: string) => { + return JSON.parse(value); + }, + toQuery: (value: object) => JSON.stringify(value), + }, }; function useQueryParam({ name, defaultValue }: { name: string; defaultValue: T }) { @@ -33,3 +40,27 @@ function useQueryParam({ name, defaultValue }: { name: string; defaultValue: }, }); } + +function useQueryParamOrStorage({ name, storageName, defaultValue }: { name: string; storageName: string; defaultValue: T }) { + const type = typeof defaultValue; + const transformer = transformers[type as keyof typeof transformers] ?? transformers.string; + + const storageRef = useStorage(storageName, defaultValue); + const proxyDefaultValue = transformer.toQuery(defaultValue as never); + const proxy = useRouteQuery(name, proxyDefaultValue); + + const r = ref(defaultValue); + + watch(r, + (value) => { + proxy.value = transformer.toQuery(value as never); + storageRef.value = value as never; + }, + { deep: true }); + + r.value = (proxy.value && proxy.value !== proxyDefaultValue + ? transformer.fromQuery(proxy.value) as unknown as T + : storageRef.value as T) as never; + + return r; +} diff --git a/src/tools/index.ts b/src/tools/index.ts index b4c161ef..d2c28e11 100644 --- a/src/tools/index.ts +++ b/src/tools/index.ts @@ -2,6 +2,7 @@ import { tool as base64FileConverter } from './base64-file-converter'; import { tool as base64StringConverter } from './base64-string-converter'; import { tool as basicAuthGenerator } from './basic-auth-generator'; import { tool as emailNormalizer } from './email-normalizer'; +import { tool as passphraseGenerator } from './passphrase-generator'; import { tool as asciiTextDrawer } from './ascii-text-drawer'; @@ -88,7 +89,20 @@ import { tool as yamlViewer } from './yaml-viewer'; export const toolsByCategory: ToolCategory[] = [ { name: 'Crypto', - components: [tokenGenerator, hashText, bcrypt, uuidGenerator, ulidGenerator, cypher, bip39, hmacGenerator, rsaKeyPairGenerator, passwordStrengthAnalyser, pdfSignatureChecker], + components: [ + tokenGenerator, + passphraseGenerator, + hashText, + bcrypt, + uuidGenerator, + ulidGenerator, + cypher, + bip39, + hmacGenerator, + rsaKeyPairGenerator, + passwordStrengthAnalyser, + pdfSignatureChecker, + ], }, { name: 'Converter', diff --git a/src/tools/passphrase-generator/index.ts b/src/tools/passphrase-generator/index.ts new file mode 100644 index 00000000..92aed52d --- /dev/null +++ b/src/tools/passphrase-generator/index.ts @@ -0,0 +1,12 @@ +import { ArrowsShuffle } from '@vicons/tabler'; +import { defineTool } from '../tool'; + +export const tool = defineTool({ + name: 'Passphrase Generator', + path: '/passphrase-generator', + description: 'Generate random memoizable Passphrases', + keywords: ['passphrase', 'random', 'password', 'generator'], + component: () => import('./passphrase-generator.vue'), + icon: ArrowsShuffle, + createdAt: new Date('2024-08-15'), +}); diff --git a/src/tools/passphrase-generator/passphrase-generator.vue b/src/tools/passphrase-generator/passphrase-generator.vue new file mode 100644 index 00000000..0bf6a625 --- /dev/null +++ b/src/tools/passphrase-generator/passphrase-generator.vue @@ -0,0 +1,85 @@ + + + + +