From 22b045b86ee4b26ffab68356814fff9174c7b6f5 Mon Sep 17 00:00:00 2001 From: jeyasankar Date: Sat, 4 Jan 2025 19:54:30 -0800 Subject: [PATCH 01/15] Upgraded tauri and mui packages --- justfile | 22 +- package.json | 18 +- src-js/package-lock.json | 2960 ++++++++++++++++++++++++++ src-js/yarn.lock | 408 ++-- src-tauri/Cargo.lock | 2429 +++++++++++++++++---- src-tauri/Cargo.toml | 14 +- src-tauri/src/commands.rs | 6 +- src-tauri/src/key_secure/macos.rs | 2 +- src-tauri/src/utils.rs | 2 +- src-tauri/swift-lib/Package.resolved | 4 +- src-tauri/swift-lib/Package.swift | 2 +- src-tauri/tauri.conf.json | 2 +- yarn.lock | 759 ++++--- 13 files changed, 5671 insertions(+), 957 deletions(-) create mode 100644 src-js/package-lock.json diff --git a/justfile b/justfile index 4e62b2b..b596ffc 100644 --- a/justfile +++ b/justfile @@ -2,14 +2,24 @@ alias r := run-repl alias acs := advanced-compile-start-server alias td := run-tauri-dev +# Using 'just run-repl' will start nrepl server and then we need to click jack-in or connect to the REPL server +# in MS Code to start the cljs compiling and connect to the REPL run-repl: clojure -M:frontend:fw:nrepl -# Run tauri dev always with onekeepass-dev enabled +# Before calling target 'run-tauri-dev', we need to do the above 'just run-repl' in a terminal and +# then do the following in another terminal + +# We need to use 'tauri dev' with feature 'onekeepass-dev' enabled +# Expecting the front end http server is running or will wait for it to start run-tauri-dev: cargo tauri dev -f onekeepass-dev -# Compiles the UI code in advanced mode and start the http server +# Compiles the UI code in advanced mode +# Bundles cljs compiled code and all dependent packages +# using webpack (--mode=production) to /desktop/target/public/cljs-out/dev/main_bundle.js +# And then starts the http server +# Once the http server starts, we can then use 'just td' to connect to this build advanced-compile-start-server: clojure -M:frontend:fw -m figwheel.main -O advanced -bo dev -s @@ -28,6 +38,8 @@ mac-aarch64-bundle-build-only: export BOTAN_CONFIGURE_DISABLE_MODULES='tls,pkcs11,sodium,filters' #cargo tauri build --verbose --target aarch64-apple-darwin + + # This will build "release" cargo tauri build --target aarch64-apple-darwin mac-x86_64-bundle-build-only: @@ -38,8 +50,14 @@ mac-x86_64-bundle-build-only: export BOTAN_CONFIGURE_CC='clang' export BOTAN_CONFIGURE_CPU='x86_64' export BOTAN_CONFIGURE_DISABLE_MODULES='"tls,pkcs11,sodium,filters"' + + # This will build "release" cargo tauri build --target x86_64-apple-darwin + ## This is for debug build and it happens only during 'dev' time + ## This requires cljs repl running. Last time the loading resource file did not work + # cargo tauri dev --target x86_64-apple-darwin + build-mac-x86_64-bundle:build-cljs-bundle just mac-x86_64-bundle-build-only diff --git a/package.json b/package.json index a393db9..b8a7f1a 100644 --- a/package.json +++ b/package.json @@ -1,24 +1,24 @@ { "name": "onekeepass-frontend", - "version": "0.12.0", + "version": "0.15.0", "private": true, "devDependencies": { "@fontsource/roboto": "^4.5.7", - "@tauri-apps/cli": "1.6.0", + "@tauri-apps/cli": "1.6.3", "trim-newlines": "^4.0.2", - "webpack": "^5.55.1", - "webpack-cli": "^4.8.0" + "webpack": "^5.97.1", + "webpack-cli": "^5.1.4" }, "scripts": { "tauri": "tauri" }, "dependencies": { "@date-io/date-fns": "^2.11.0", - "@emotion/react": "^11.13.0", - "@emotion/styled": "^11.13.0", - "@mui/icons-material": "^5.16.6", - "@mui/lab": "^5.0.0-alpha.173", - "@mui/material": "^5.16.6", + "@emotion/react": "^11.14.0", + "@emotion/styled": "^11.14.0", + "@mui/icons-material": "^5.16.13", + "@mui/lab": "^5.0.0-alpha.175", + "@mui/material": "^5.16.13", "@mui/x-date-pickers": "^6.20.2", "@mui/x-tree-view": "^6.17.0", "@tauri-apps/api": "^1.6.0", diff --git a/src-js/package-lock.json b/src-js/package-lock.json new file mode 100644 index 0000000..ec91697 --- /dev/null +++ b/src-js/package-lock.json @@ -0,0 +1,2960 @@ +{ + "name": "onekeepass-local", + "version": "0.0.1", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "onekeepass-local", + "version": "0.0.1", + "devDependencies": { + "@babel/cli": "^7.23.4", + "@babel/core": "^7.23.5", + "@babel/preset-env": "^7.23.5", + "@babel/preset-react": "^7.23.3" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", + "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/cli": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/cli/-/cli-7.23.4.tgz", + "integrity": "sha512-j3luA9xGKCXVyCa5R7lJvOMM+Kc2JEnAEIgz2ggtjQ/j5YUVgfsg/WsG95bbsgq7YLHuiCOzMnoSasuY16qiCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.17", + "commander": "^4.0.1", + "convert-source-map": "^2.0.0", + "fs-readdir-recursive": "^1.1.0", + "glob": "^7.2.0", + "make-dir": "^2.1.0", + "slash": "^2.0.0" + }, + "bin": { + "babel": "bin/babel.js", + "babel-external-helpers": "bin/babel-external-helpers.js" + }, + "engines": { + "node": ">=6.9.0" + }, + "optionalDependencies": { + "@nicolo-ribaudo/chokidar-2": "2.1.8-no-fsevents.3", + "chokidar": "^3.4.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", + "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/highlight": "^7.23.4", + "chalk": "^2.4.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.5.tgz", + "integrity": "sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.5.tgz", + "integrity": "sha512-Cwc2XjUrG4ilcfOw4wBAK+enbdgwAcAJCfGUItPBKR7Mjw4aEfAFYrLxeRp4jWgtNIKn3n2AlBOfwwafl+42/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.23.5", + "@babel/generator": "^7.23.5", + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helpers": "^7.23.5", + "@babel/parser": "^7.23.5", + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.5", + "@babel/types": "^7.23.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.5.tgz", + "integrity": "sha512-BPssCHrBD+0YrxviOa3QzpqwhNIXKEtOa2jQrm4FlmkC2apYgRnQcmPWiGZDlGxiNtltnUFolMe8497Esry+jA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.23.5", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", + "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.22.15.tgz", + "integrity": "sha512-QkBXwGgaoC2GtGZRoma6kv7Szfv06khvhFav67ZExau2RaXzy8MpHSMO2PNoP2XtmQphJQRHFfg77Bq731Yizw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz", + "integrity": "sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.22.9", + "@babel/helper-validator-option": "^7.22.15", + "browserslist": "^4.21.9", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.23.5.tgz", + "integrity": "sha512-QELlRWxSpgdwdJzSJn4WAhKC+hvw/AtHbbrIoncKHkhKKR/luAlKkgBDcri1EzWAo8f8VvYVryEHN4tax/V67A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-member-expression-to-functions": "^7.23.0", + "@babel/helper-optimise-call-expression": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.20", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.22.15.tgz", + "integrity": "sha512-29FkPLFjn4TPEa3RE7GpW+qbE8tlsu3jntNYNfcGsc49LphF1PQIiD+vMZ1z1xVOKt+93khA9tc2JBs3kBjA7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "regexpu-core": "^5.3.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.4.3.tgz", + "integrity": "sha512-WBrLmuPP47n7PNwsZ57pqam6G/RGo1vw/87b0Blc53tZNGZ4x7YvZ6HgQe2vo1W/FR20OgjeZuGXzudPiXHFug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.23.0.tgz", + "integrity": "sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.23.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", + "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", + "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-validator-identifier": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.22.5.tgz", + "integrity": "sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.22.20.tgz", + "integrity": "sha512-pBGyV4uBqOns+0UvhsTO8qgl8hO89PmiDYv+/COyp1aeMcmfrfruz+/nCMFiYyFF/Knn0yfrC85ZzNFjembFTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-wrap-function": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.22.20.tgz", + "integrity": "sha512-qsW0In3dbwQUbK8kejJ4R7IHVGwHJlV6lpG6UA7a9hSa2YEiAib+N1T2kr6PEeUT+Fl7najmSOS6SmAwCHK6Tw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-member-expression-to-functions": "^7.22.15", + "@babel/helper-optimise-call-expression": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", + "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.22.5.tgz", + "integrity": "sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", + "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz", + "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.22.20.tgz", + "integrity": "sha512-pms/UwkOpnQe/PDAEdV/d7dVCoBbB+R4FvYoHGZz+4VPcg7RtYy2KP7S2lbuWM6FCSgob5wshfGESbC/hzNXZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-function-name": "^7.22.5", + "@babel/template": "^7.22.15", + "@babel/types": "^7.22.19" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.5.tgz", + "integrity": "sha512-oO7us8FzTEsG3U6ag9MfdF1iA/7Z6dz+MtFhifZk8C8o453rGJFFWUP1t+ULM9TUIAzC9uxXEiXjOiVMyd7QPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.5", + "@babel/types": "^7.23.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", + "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.5.tgz", + "integrity": "sha512-hOOqoiNXrmGdFbhgCzu6GiURxUgM27Xwd/aPuu8RfHEZPBzL1Z54okAHAQjXfcQNwvrlkAmAp4SlRTZ45vlthQ==", + "dev": true, + "license": "MIT", + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.23.3.tgz", + "integrity": "sha512-iRkKcCqb7iGnq9+3G6rZ+Ciz5VywC4XNRHe57lKM+jOeYAoR0lVqdeeDRfh0tQcTfw/+vBhHn926FmQhLtlFLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.23.3.tgz", + "integrity": "sha512-WwlxbfMNdVEpQjZmK5mhm7oSwD3dS6eU+Iwsi4Knl9wAletWem7kaRsGOG+8UEbRyqxY4SS5zvtfXwX+jMxUwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/plugin-transform-optional-chaining": "^7.23.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.23.3.tgz", + "integrity": "sha512-XaJak1qcityzrX0/IU5nKHb34VaibwP3saKqG6a/tppelgllOH13LUann4ZCIBcVOeE6H18K4Vx9QKkVww3z/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-export-namespace-from": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", + "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.23.3.tgz", + "integrity": "sha512-lPgDSU+SJLK3xmFDTV2ZRQAiM7UuUjGidwBywFavObCiZc1BeAAcMtHJKUya92hPHO+at63JJPLygilZard8jw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.23.3.tgz", + "integrity": "sha512-pawnE0P9g10xgoP7yKr6CK63K2FMsTE+FZidZO/1PwRdzmAPVs+HS1mAURUsgaoxammTJvULUdIkEK0gOcU2tA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.23.3.tgz", + "integrity": "sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.23.3.tgz", + "integrity": "sha512-NzQcQrzaQPkaEwoTm4Mhyl8jI1huEL/WWIEvudjTCMJ9aBZNpsJbMASx7EQECtQQPS/DcnFpo0FIh3LvEO9cxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-generator-functions": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.23.4.tgz", + "integrity": "sha512-efdkfPhHYTtn0G6n2ddrESE91fgXxjlqLsnUtPWnJs4a4mZIbUaK7ffqKIIUKXSHwcDvaCVX6GXkaJJFqtX7jw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-remap-async-to-generator": "^7.22.20", + "@babel/plugin-syntax-async-generators": "^7.8.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.23.3.tgz", + "integrity": "sha512-A7LFsKi4U4fomjqXJlZg/u0ft/n8/7n7lpffUP/ZULx/DtV9SGlNKZolHH6PE8Xl1ngCc0M11OaeZptXVkfKSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-remap-async-to-generator": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.23.3.tgz", + "integrity": "sha512-vI+0sIaPIO6CNuM9Kk5VmXcMVRiOpDh7w2zZt9GXzmE/9KD70CUEVhvPR/etAeNK/FAEkhxQtXOzVF3EuRL41A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.23.4.tgz", + "integrity": "sha512-0QqbP6B6HOh7/8iNR4CQU2Th/bbRtBp4KS9vcaZd1fZ0wSh5Fyssg0UCIHwxh+ka+pNDREbVLQnHCMHKZfPwfw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.23.3.tgz", + "integrity": "sha512-uM+AN8yCIjDPccsKGlw271xjJtGii+xQIF/uMPS8H15L12jZTsLfF4o5vNO7d/oUguOyfdikHGc/yi9ge4SGIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-static-block": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.23.4.tgz", + "integrity": "sha512-nsWu/1M+ggti1SOALj3hfx5FXzAY06fwPJsUZD4/A5e1bWi46VUIWtD+kOX6/IdhXGsXBWllLFDSnqSCdUNydQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-class-static-block": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.23.5.tgz", + "integrity": "sha512-jvOTR4nicqYC9yzOHIhXG5emiFEOpappSJAl73SDSEDcybD+Puuze8Tnpb9p9qEyYup24tq891gkaygIFvWDqg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-optimise-call-expression": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.20", + "@babel/helper-split-export-declaration": "^7.22.6", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.23.3.tgz", + "integrity": "sha512-dTj83UVTLw/+nbiHqQSFdwO9CbTtwq1DsDqm3CUEtDrZNET5rT5E6bIdTlOftDTDLMYxvxHNEYO4B9SLl8SLZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/template": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.23.3.tgz", + "integrity": "sha512-n225npDqjDIr967cMScVKHXJs7rout1q+tt50inyBCPkyZ8KxeI6d+GIbSBTT/w/9WdlWDOej3V9HE5Lgk57gw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.23.3.tgz", + "integrity": "sha512-vgnFYDHAKzFaTVp+mneDsIEbnJ2Np/9ng9iviHw3P/KVcgONxpNULEW/51Z/BaFojG2GI2GwwXck5uV1+1NOYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.23.3.tgz", + "integrity": "sha512-RrqQ+BQmU3Oyav3J+7/myfvRCq7Tbz+kKLLshUmMwNlDHExbGL7ARhajvoBJEvc+fCguPPu887N+3RRXBVKZUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dynamic-import": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.23.4.tgz", + "integrity": "sha512-V6jIbLhdJK86MaLh4Jpghi8ho5fGzt3imHOBu/x0jlBaPYqDoWz4RDXjmMOfnh+JWNaQleEAByZLV0QzBT4YQQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.23.3.tgz", + "integrity": "sha512-5fhCsl1odX96u7ILKHBj4/Y8vipoqwsJMh4csSA8qFfxrZDEA4Ssku2DyNvMJSmZNOEBT750LfFPbtrnTP90BQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-export-namespace-from": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.23.4.tgz", + "integrity": "sha512-GzuSBcKkx62dGzZI1WVgTWvkkz84FZO5TC5T8dl/Tht/rAla6Dg/Mz9Yhypg+ezVACf/rgDuQt3kbWEv7LdUDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.23.3.tgz", + "integrity": "sha512-X8jSm8X1CMwxmK878qsUGJRmbysKNbdpTv/O1/v0LuY/ZkZrng5WYiekYSdg9m09OTmDDUWeEDsTE+17WYbAZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.23.3.tgz", + "integrity": "sha512-I1QXp1LxIvt8yLaib49dRW5Okt7Q4oaxao6tFVKS/anCdEOMtYwWVKoiOA1p34GOWIZjUK0E+zCp7+l1pfQyiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-json-strings": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.23.4.tgz", + "integrity": "sha512-81nTOqM1dMwZ/aRXQ59zVubN9wHGqk6UtqRK+/q+ciXmRy8fSolhGVvG09HHRGo4l6fr/c4ZhXUQH0uFW7PZbg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-json-strings": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.23.3.tgz", + "integrity": "sha512-wZ0PIXRxnwZvl9AYpqNUxpZ5BiTGrYt7kueGQ+N5FiQ7RCOD4cm8iShd6S6ggfVIWaJf2EMk8eRzAh52RfP4rQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-logical-assignment-operators": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.23.4.tgz", + "integrity": "sha512-Mc/ALf1rmZTP4JKKEhUwiORU+vcfarFVLfcFiolKUo6sewoxSEgl36ak5t+4WamRsNr6nzjZXQjM35WsU+9vbg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.23.3.tgz", + "integrity": "sha512-sC3LdDBDi5x96LA+Ytekz2ZPk8i/Ck+DEuDbRAll5rknJ5XRTSaPKEYwomLcs1AA8wg9b3KjIQRsnApj+q51Ag==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.23.3.tgz", + "integrity": "sha512-vJYQGxeKM4t8hYCKVBlZX/gtIY2I7mRGFNcm85sgXGMTBcoV3QdVtdpbcWEbzbfUIUZKwvgFT82mRvaQIebZzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.23.3.tgz", + "integrity": "sha512-aVS0F65LKsdNOtcz6FRCpE4OgsP2OFnW46qNxNIX9h3wuzaNcSQsJysuMwqSibC98HPrf2vCgtxKNwS0DAlgcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-simple-access": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.23.3.tgz", + "integrity": "sha512-ZxyKGTkF9xT9YJuKQRo19ewf3pXpopuYQd8cDXqNzc3mUNbOME0RKMoZxviQk74hwzfQsEe66dE92MaZbdHKNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.23.3.tgz", + "integrity": "sha512-zHsy9iXX2nIsCBFPud3jKn1IRPWg3Ing1qOZgeKV39m1ZgIdpJqvlWVeiHBZC6ITRG0MfskhYe9cLgntfSFPIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.22.5.tgz", + "integrity": "sha512-YgLLKmS3aUBhHaxp5hi1WJTgOUb/NCuDHzGT9z9WTt3YG+CPRhJs6nprbStx6DnWM4dh6gt7SU3sZodbZ08adQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.23.3.tgz", + "integrity": "sha512-YJ3xKqtJMAT5/TIZnpAR3I+K+WaDowYbN3xyxI8zxx/Gsypwf9B9h0VB+1Nh6ACAAPRS5NSRje0uVv5i79HYGQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.23.4.tgz", + "integrity": "sha512-jHE9EVVqHKAQx+VePv5LLGHjmHSJR76vawFPTdlxR/LVJPfOEGxREQwQfjuZEOPTwG92X3LINSh3M40Rv4zpVA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-numeric-separator": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.23.4.tgz", + "integrity": "sha512-mps6auzgwjRrwKEZA05cOwuDc9FAzoyFS4ZsG/8F43bTLf/TgkJg7QXOrPO1JO599iA3qgK9MXdMGOEC8O1h6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-rest-spread": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.23.4.tgz", + "integrity": "sha512-9x9K1YyeQVw0iOXJlIzwm8ltobIIv7j2iLyP2jIhEbqPRQ7ScNgwQufU2I0Gq11VjyG4gI4yMXt2VFags+1N3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.23.3", + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.23.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.23.3.tgz", + "integrity": "sha512-BwQ8q0x2JG+3lxCVFohg+KbQM7plfpBwThdW9A6TMtWwLsbDA01Ek2Zb/AgDN39BiZsExm4qrXxjk+P1/fzGrA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-catch-binding": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.23.4.tgz", + "integrity": "sha512-XIq8t0rJPHf6Wvmbn9nFxU6ao4c7WhghTR5WyV8SrJfUFzyxhCm4nhC+iAp3HFhbAKLfYpgzhJ6t4XCtVwqO5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.23.4.tgz", + "integrity": "sha512-ZU8y5zWOfjM5vZ+asjgAPwDaBjJzgufjES89Rs4Lpq63O300R/kOz30WCLo6BxxX6QVEilwSlpClnG5cZaikTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.23.3.tgz", + "integrity": "sha512-09lMt6UsUb3/34BbECKVbVwrT9bO6lILWln237z7sLaWnMsTi7Yc9fhX5DLpkJzAGfaReXI22wP41SZmnAA3Vw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.23.3.tgz", + "integrity": "sha512-UzqRcRtWsDMTLrRWFvUBDwmw06tCQH9Rl1uAjfh6ijMSmGYQ+fpdB+cnqRC8EMh5tuuxSv0/TejGL+7vyj+50g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-property-in-object": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.23.4.tgz", + "integrity": "sha512-9G3K1YqTq3F4Vt88Djx1UZ79PDyj+yKRnUy7cZGSMe+a7jkwD259uKKuUzQlPkGam7R+8RJwh5z4xO27fA1o2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-create-class-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.23.3.tgz", + "integrity": "sha512-jR3Jn3y7cZp4oEWPFAlRsSWjxKe4PZILGBSd4nis1TsC5qeSpb+nrtihJuDhNI7QHiVbUaiXa0X2RZY3/TI6Nw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-display-name": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.23.3.tgz", + "integrity": "sha512-GnvhtVfA2OAtzdX58FJxU19rhoGeQzyVndw3GgtdECQvQFXPEZIOVULHVZGAYmOgmqjXpVpfocAbSjh99V/Fqw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.23.4.tgz", + "integrity": "sha512-5xOpoPguCZCRbo/JeHlloSkTA8Bld1J/E1/kLfD1nsuiW1m8tduTA1ERCgIZokDflX/IBzKcqR3l7VlRgiIfHA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-jsx": "^7.23.3", + "@babel/types": "^7.23.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-development": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.22.5.tgz", + "integrity": "sha512-bDhuzwWMuInwCYeDeMzyi7TaBgRQei6DqxhbyniL7/VG4RSS7HtSL2QbY4eESy1KJqlWt8g3xeEBGPuo+XqC8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/plugin-transform-react-jsx": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-pure-annotations": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.23.3.tgz", + "integrity": "sha512-qMFdSS+TUhB7Q/3HVPnEdYJDQIk57jkntAwSuz9xfSE4n+3I+vHYCli3HoHawN1Z3RfCz/y1zXA/JXjG6cVImQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.23.3.tgz", + "integrity": "sha512-KP+75h0KghBMcVpuKisx3XTu9Ncut8Q8TuvGO4IhY+9D5DFEckQefOuIsB/gQ2tG71lCke4NMrtIPS8pOj18BQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "regenerator-transform": "^0.15.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.23.3.tgz", + "integrity": "sha512-QnNTazY54YqgGxwIexMZva9gqbPa15t/x9VS+0fsEFWplwVpXYZivtgl43Z1vMpc1bdPP2PP8siFeVcnFvA3Cg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.23.3.tgz", + "integrity": "sha512-ED2fgqZLmexWiN+YNFX26fx4gh5qHDhn1O2gvEhreLW2iI63Sqm4llRLCXALKrCnbN4Jy0VcMQZl/SAzqug/jg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-spread": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.23.3.tgz", + "integrity": "sha512-VvfVYlrlBVu+77xVTOAoxQ6mZbnIq5FM0aGBSFEcIh03qHf+zNqA4DC/3XMUozTg7bZV3e3mZQ0i13VB6v5yUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.23.3.tgz", + "integrity": "sha512-HZOyN9g+rtvnOU3Yh7kSxXrKbzgrm5X4GncPY1QOquu7epga5MxKHVpYu2hvQnry/H+JjckSYRb93iNfsioAGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.23.3.tgz", + "integrity": "sha512-Flok06AYNp7GV2oJPZZcP9vZdszev6vPBkHLwxwSpaIqx75wn6mUd3UFWsSsA0l8nXAKkyCmL/sR02m8RYGeHg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.23.3.tgz", + "integrity": "sha512-4t15ViVnaFdrPC74be1gXBSMzXk3B4Us9lP7uLRQHTFpV5Dvt33pn+2MyyNxmN3VTTm3oTrZVMUmuw3oBnQ2oQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.23.3.tgz", + "integrity": "sha512-OMCUx/bU6ChE3r4+ZdylEqAjaQgHAgipgW8nsCfu5pGqDcFytVd91AwRvUJSBZDz0exPGgnjoqhgRYLRjFZc9Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-property-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.23.3.tgz", + "integrity": "sha512-KcLIm+pDZkWZQAFJ9pdfmh89EwVfmNovFBcXko8szpBeF8z68kWIPeKlmSOkT9BXJxs2C0uk+5LxoxIv62MROA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.23.3.tgz", + "integrity": "sha512-wMHpNA4x2cIA32b/ci3AfwNgheiva2W0WUKWTK7vBHBhDKfPsc5cFGNWm69WBqpwd86u1qwZ9PWevKqm1A3yAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-sets-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.23.3.tgz", + "integrity": "sha512-W7lliA/v9bNR83Qc3q1ip9CQMZ09CcHDbHfbLRDNuAhn1Mvkr1ZNF7hPmztMQvtTGVLJ9m8IZqWsTkXOml8dbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.23.5.tgz", + "integrity": "sha512-0d/uxVD6tFGWXGDSfyMD1p2otoaKmu6+GD+NfAx0tMaH+dxORnp7T9TaVQ6mKyya7iBtCIVxHjWT7MuzzM9z+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.23.5", + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-validator-option": "^7.23.5", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.23.3", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.23.3", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.23.3", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-import-assertions": "^7.23.3", + "@babel/plugin-syntax-import-attributes": "^7.23.3", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.23.3", + "@babel/plugin-transform-async-generator-functions": "^7.23.4", + "@babel/plugin-transform-async-to-generator": "^7.23.3", + "@babel/plugin-transform-block-scoped-functions": "^7.23.3", + "@babel/plugin-transform-block-scoping": "^7.23.4", + "@babel/plugin-transform-class-properties": "^7.23.3", + "@babel/plugin-transform-class-static-block": "^7.23.4", + "@babel/plugin-transform-classes": "^7.23.5", + "@babel/plugin-transform-computed-properties": "^7.23.3", + "@babel/plugin-transform-destructuring": "^7.23.3", + "@babel/plugin-transform-dotall-regex": "^7.23.3", + "@babel/plugin-transform-duplicate-keys": "^7.23.3", + "@babel/plugin-transform-dynamic-import": "^7.23.4", + "@babel/plugin-transform-exponentiation-operator": "^7.23.3", + "@babel/plugin-transform-export-namespace-from": "^7.23.4", + "@babel/plugin-transform-for-of": "^7.23.3", + "@babel/plugin-transform-function-name": "^7.23.3", + "@babel/plugin-transform-json-strings": "^7.23.4", + "@babel/plugin-transform-literals": "^7.23.3", + "@babel/plugin-transform-logical-assignment-operators": "^7.23.4", + "@babel/plugin-transform-member-expression-literals": "^7.23.3", + "@babel/plugin-transform-modules-amd": "^7.23.3", + "@babel/plugin-transform-modules-commonjs": "^7.23.3", + "@babel/plugin-transform-modules-systemjs": "^7.23.3", + "@babel/plugin-transform-modules-umd": "^7.23.3", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.22.5", + "@babel/plugin-transform-new-target": "^7.23.3", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.23.4", + "@babel/plugin-transform-numeric-separator": "^7.23.4", + "@babel/plugin-transform-object-rest-spread": "^7.23.4", + "@babel/plugin-transform-object-super": "^7.23.3", + "@babel/plugin-transform-optional-catch-binding": "^7.23.4", + "@babel/plugin-transform-optional-chaining": "^7.23.4", + "@babel/plugin-transform-parameters": "^7.23.3", + "@babel/plugin-transform-private-methods": "^7.23.3", + "@babel/plugin-transform-private-property-in-object": "^7.23.4", + "@babel/plugin-transform-property-literals": "^7.23.3", + "@babel/plugin-transform-regenerator": "^7.23.3", + "@babel/plugin-transform-reserved-words": "^7.23.3", + "@babel/plugin-transform-shorthand-properties": "^7.23.3", + "@babel/plugin-transform-spread": "^7.23.3", + "@babel/plugin-transform-sticky-regex": "^7.23.3", + "@babel/plugin-transform-template-literals": "^7.23.3", + "@babel/plugin-transform-typeof-symbol": "^7.23.3", + "@babel/plugin-transform-unicode-escapes": "^7.23.3", + "@babel/plugin-transform-unicode-property-regex": "^7.23.3", + "@babel/plugin-transform-unicode-regex": "^7.23.3", + "@babel/plugin-transform-unicode-sets-regex": "^7.23.3", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "babel-plugin-polyfill-corejs2": "^0.4.6", + "babel-plugin-polyfill-corejs3": "^0.8.5", + "babel-plugin-polyfill-regenerator": "^0.5.3", + "core-js-compat": "^3.31.0", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.6-no-external-plugins", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", + "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/preset-react": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.23.3.tgz", + "integrity": "sha512-tbkHOS9axH6Ysf2OUEqoSZ6T3Fa2SrNH6WTWSPBboxKzdxNc9qOICeLXkNG0ZEwbQ1HY8liwOce4aN/Ceyuq6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-validator-option": "^7.22.15", + "@babel/plugin-transform-react-display-name": "^7.23.3", + "@babel/plugin-transform-react-jsx": "^7.22.15", + "@babel/plugin-transform-react-jsx-development": "^7.22.5", + "@babel/plugin-transform-react-pure-annotations": "^7.23.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@babel/runtime": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.5.tgz", + "integrity": "sha512-NdUTHcPe4C99WxPub+K9l9tK5/lV4UXIoaHSYgzco9BCyjKAAwzdBI+wWtYqHt7LJdbo74ZjRPJgzVweq1sz0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.5.tgz", + "integrity": "sha512-czx7Xy5a6sapWWRx61m1Ke1Ra4vczu1mCTtJam5zRTBOonfdJ+S/B6HYmGYu3fJtr8GGET3si6IhgWVBhJ/m8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.23.5", + "@babel/generator": "^7.23.5", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.23.5", + "@babel/types": "^7.23.5", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.5.tgz", + "integrity": "sha512-ON5kSOJwVO6xXVRTvOI0eOnWe7VdUcIpsovGo9U/Br4Ie4UVFQTboO2cYnDhAGU6Fp+UxSiT+pMft0SMHfuq6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.23.4", + "@babel/helper-validator-identifier": "^7.22.20", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.20", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", + "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@nicolo-ribaudo/chokidar-2": { + "version": "2.1.8-no-fsevents.3", + "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/chokidar-2/-/chokidar-2-2.1.8-no-fsevents.3.tgz", + "integrity": "sha512-s88O1aVtXftvp5bCPB7WnmXc5IwOZZ7YPuwNPt+GtOOXpPvad1LfbmjYv+qII7zP6RU2QGnqve27dnLycEnyEQ==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "optional": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.6.tgz", + "integrity": "sha512-jhHiWVZIlnPbEUKSSNb9YoWcQGdlTLq7z1GHL4AjFxaoOUMuuEVJ+Y4pAaQUGOGk93YsVCKPbqbfw3m0SM6H8Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.22.6", + "@babel/helper-define-polyfill-provider": "^0.4.3", + "semver": "^6.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.8.6", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.8.6.tgz", + "integrity": "sha512-leDIc4l4tUgU7str5BWLS2h8q2N4Nf6lGZP6UrNDxdtfF2g69eJ5L0H7S8A5Ln/arfFAfHor5InAdZuIOwZdgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.4.3", + "core-js-compat": "^3.33.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.3.tgz", + "integrity": "sha512-8sHeDOmXC8csczMrYEOf0UTNa4yE2SxV5JGeT/LP1n0OYVDUUFPxG9vdk2AlDlIit4t+Kf0xCtpgXPBwnn/9pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.4.3" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "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/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.1.tgz", + "integrity": "sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "caniuse-lite": "^1.0.30001541", + "electron-to-chromium": "^1.4.535", + "node-releases": "^2.0.13", + "update-browserslist-db": "^1.0.13" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001565", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001565.tgz", + "integrity": "sha512-xrE//a3O7TP0vaJ8ikzkD2c2NgcVUvsEe2IvFTntV4Yd1Z9FVzh+gW+enX96L0psrbaFMcVcH2l90xNuGDWc8w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "license": "MIT", + "optional": true, + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true, + "license": "MIT" + }, + "node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/core-js-compat": { + "version": "3.33.3", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.33.3.tgz", + "integrity": "sha512-cNzGqFsh3Ot+529GIXacjTJ7kegdt5fPXxCBVS1G0iaZpuo/tBz399ymceLJveQhFFZ8qThHiP3fzuoQjKN2ow==", + "dev": true, + "license": "MIT", + "dependencies": { + "browserslist": "^4.22.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/electron-to-chromium": { + "version": "1.4.596", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.596.tgz", + "integrity": "sha512-zW3zbZ40Icb2BCWjm47nxwcFGYlIgdXkAx85XDO7cyky9J4QQfq8t0W19/TLZqq3JPQXtlv8BPIGmfa9Jb4scg==", + "dev": true, + "license": "ISC" + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fs-readdir-recursive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz", + "integrity": "sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA==", + "dev": true, + "license": "MIT" + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "optional": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/hasown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", + "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-core-module": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "dev": true, + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "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/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-releases": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", + "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "dev": true, + "license": "MIT" + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.1.tgz", + "integrity": "sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz", + "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==", + "dev": true, + "license": "MIT" + }, + "node_modules/regenerator-transform": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", + "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.8.4" + } + }, + "node_modules/regexpu-core": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", + "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/regjsgen": "^0.8.0", + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.1.0", + "regjsparser": "^0.9.1", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regjsparser": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", + "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "jsesc": "~0.5.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/regjsparser/node_modules/jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + } + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", + "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", + "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + } + } +} diff --git a/src-js/yarn.lock b/src-js/yarn.lock index 08c364b..3021d44 100644 --- a/src-js/yarn.lock +++ b/src-js/yarn.lock @@ -4,7 +4,7 @@ "@ampproject/remapping@^2.2.0": version "2.2.1" - resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.1.tgz#99e8e11851128b8702cd57c33684f1d0f260b630" + resolved "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz" integrity sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg== dependencies: "@jridgewell/gen-mapping" "^0.3.0" @@ -12,7 +12,7 @@ "@babel/cli@^7.23.4": version "7.23.4" - resolved "https://registry.yarnpkg.com/@babel/cli/-/cli-7.23.4.tgz#f5cc90487278065fa0c3b1267cf0c1d44ddf85a7" + resolved "https://registry.npmjs.org/@babel/cli/-/cli-7.23.4.tgz" integrity sha512-j3luA9xGKCXVyCa5R7lJvOMM+Kc2JEnAEIgz2ggtjQ/j5YUVgfsg/WsG95bbsgq7YLHuiCOzMnoSasuY16qiCw== dependencies: "@jridgewell/trace-mapping" "^0.3.17" @@ -28,7 +28,7 @@ "@babel/code-frame@^7.22.13", "@babel/code-frame@^7.23.5": version "7.23.5" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.23.5.tgz#9009b69a8c602293476ad598ff53e4562e15c244" + resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz" integrity sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA== dependencies: "@babel/highlight" "^7.23.4" @@ -36,12 +36,12 @@ "@babel/compat-data@^7.22.6", "@babel/compat-data@^7.22.9", "@babel/compat-data@^7.23.3", "@babel/compat-data@^7.23.5": version "7.23.5" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.23.5.tgz#ffb878728bb6bdcb6f4510aa51b1be9afb8cfd98" + resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.5.tgz" integrity sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw== -"@babel/core@^7.23.5": +"@babel/core@^7.0.0", "@babel/core@^7.0.0-0", "@babel/core@^7.0.0-0 || ^8.0.0-0 <8.0.0", "@babel/core@^7.12.0", "@babel/core@^7.13.0", "@babel/core@^7.23.5", "@babel/core@^7.4.0 || ^8.0.0-0 <8.0.0": version "7.23.5" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.23.5.tgz#6e23f2acbcb77ad283c5ed141f824fd9f70101c7" + resolved "https://registry.npmjs.org/@babel/core/-/core-7.23.5.tgz" integrity sha512-Cwc2XjUrG4ilcfOw4wBAK+enbdgwAcAJCfGUItPBKR7Mjw4aEfAFYrLxeRp4jWgtNIKn3n2AlBOfwwafl+42/g== dependencies: "@ampproject/remapping" "^2.2.0" @@ -62,7 +62,7 @@ "@babel/generator@^7.23.5": version "7.23.5" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.23.5.tgz#17d0a1ea6b62f351d281350a5f80b87a810c4755" + resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.23.5.tgz" integrity sha512-BPssCHrBD+0YrxviOa3QzpqwhNIXKEtOa2jQrm4FlmkC2apYgRnQcmPWiGZDlGxiNtltnUFolMe8497Esry+jA== dependencies: "@babel/types" "^7.23.5" @@ -72,21 +72,21 @@ "@babel/helper-annotate-as-pure@^7.22.5": version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz#e7f06737b197d580a01edf75d97e2c8be99d3882" + resolved "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz" integrity sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg== dependencies: "@babel/types" "^7.22.5" "@babel/helper-builder-binary-assignment-operator-visitor@^7.22.15": version "7.22.15" - resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.22.15.tgz#5426b109cf3ad47b91120f8328d8ab1be8b0b956" + resolved "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.22.15.tgz" integrity sha512-QkBXwGgaoC2GtGZRoma6kv7Szfv06khvhFav67ZExau2RaXzy8MpHSMO2PNoP2XtmQphJQRHFfg77Bq731Yizw== dependencies: "@babel/types" "^7.22.15" "@babel/helper-compilation-targets@^7.22.15", "@babel/helper-compilation-targets@^7.22.6": version "7.22.15" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz#0698fc44551a26cf29f18d4662d5bf545a6cfc52" + resolved "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz" integrity sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw== dependencies: "@babel/compat-data" "^7.22.9" @@ -97,7 +97,7 @@ "@babel/helper-create-class-features-plugin@^7.22.15": version "7.23.5" - resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.23.5.tgz#2a8792357008ae9ce8c0f2b78b9f646ac96b314b" + resolved "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.23.5.tgz" integrity sha512-QELlRWxSpgdwdJzSJn4WAhKC+hvw/AtHbbrIoncKHkhKKR/luAlKkgBDcri1EzWAo8f8VvYVryEHN4tax/V67A== dependencies: "@babel/helper-annotate-as-pure" "^7.22.5" @@ -112,7 +112,7 @@ "@babel/helper-create-regexp-features-plugin@^7.18.6", "@babel/helper-create-regexp-features-plugin@^7.22.15", "@babel/helper-create-regexp-features-plugin@^7.22.5": version "7.22.15" - resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.22.15.tgz#5ee90093914ea09639b01c711db0d6775e558be1" + resolved "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.22.15.tgz" integrity sha512-29FkPLFjn4TPEa3RE7GpW+qbE8tlsu3jntNYNfcGsc49LphF1PQIiD+vMZ1z1xVOKt+93khA9tc2JBs3kBjA7w== dependencies: "@babel/helper-annotate-as-pure" "^7.22.5" @@ -121,7 +121,7 @@ "@babel/helper-define-polyfill-provider@^0.4.3": version "0.4.3" - resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.4.3.tgz#a71c10f7146d809f4a256c373f462d9bba8cf6ba" + resolved "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.4.3.tgz" integrity sha512-WBrLmuPP47n7PNwsZ57pqam6G/RGo1vw/87b0Blc53tZNGZ4x7YvZ6HgQe2vo1W/FR20OgjeZuGXzudPiXHFug== dependencies: "@babel/helper-compilation-targets" "^7.22.6" @@ -132,12 +132,12 @@ "@babel/helper-environment-visitor@^7.22.20": version "7.22.20" - resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz#96159db61d34a29dba454c959f5ae4a649ba9167" + resolved "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz" integrity sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA== "@babel/helper-function-name@^7.22.5", "@babel/helper-function-name@^7.23.0": version "7.23.0" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz#1f9a3cdbd5b2698a670c30d2735f9af95ed52759" + resolved "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz" integrity sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw== dependencies: "@babel/template" "^7.22.15" @@ -145,28 +145,28 @@ "@babel/helper-hoist-variables@^7.22.5": version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz#c01a007dac05c085914e8fb652b339db50d823bb" + resolved "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz" integrity sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw== dependencies: "@babel/types" "^7.22.5" "@babel/helper-member-expression-to-functions@^7.22.15", "@babel/helper-member-expression-to-functions@^7.23.0": version "7.23.0" - resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.23.0.tgz#9263e88cc5e41d39ec18c9a3e0eced59a3e7d366" + resolved "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.23.0.tgz" integrity sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA== dependencies: "@babel/types" "^7.23.0" "@babel/helper-module-imports@^7.22.15": version "7.22.15" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz#16146307acdc40cc00c3b2c647713076464bdbf0" + resolved "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz" integrity sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w== dependencies: "@babel/types" "^7.22.15" "@babel/helper-module-transforms@^7.23.3": version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz#d7d12c3c5d30af5b3c0fcab2a6d5217773e2d0f1" + resolved "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz" integrity sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ== dependencies: "@babel/helper-environment-visitor" "^7.22.20" @@ -177,19 +177,19 @@ "@babel/helper-optimise-call-expression@^7.22.5": version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.22.5.tgz#f21531a9ccbff644fdd156b4077c16ff0c3f609e" + resolved "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.22.5.tgz" integrity sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw== dependencies: "@babel/types" "^7.22.5" "@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.22.5", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz#dd7ee3735e8a313b9f7b05a773d892e88e6d7295" + resolved "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz" integrity sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg== "@babel/helper-remap-async-to-generator@^7.22.20": version "7.22.20" - resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.22.20.tgz#7b68e1cb4fa964d2996fd063723fb48eca8498e0" + resolved "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.22.20.tgz" integrity sha512-pBGyV4uBqOns+0UvhsTO8qgl8hO89PmiDYv+/COyp1aeMcmfrfruz+/nCMFiYyFF/Knn0yfrC85ZzNFjembFTw== dependencies: "@babel/helper-annotate-as-pure" "^7.22.5" @@ -198,7 +198,7 @@ "@babel/helper-replace-supers@^7.22.20": version "7.22.20" - resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.22.20.tgz#e37d367123ca98fe455a9887734ed2e16eb7a793" + resolved "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.22.20.tgz" integrity sha512-qsW0In3dbwQUbK8kejJ4R7IHVGwHJlV6lpG6UA7a9hSa2YEiAib+N1T2kr6PEeUT+Fl7najmSOS6SmAwCHK6Tw== dependencies: "@babel/helper-environment-visitor" "^7.22.20" @@ -207,43 +207,43 @@ "@babel/helper-simple-access@^7.22.5": version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz#4938357dc7d782b80ed6dbb03a0fba3d22b1d5de" + resolved "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz" integrity sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w== dependencies: "@babel/types" "^7.22.5" "@babel/helper-skip-transparent-expression-wrappers@^7.22.5": version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.22.5.tgz#007f15240b5751c537c40e77abb4e89eeaaa8847" + resolved "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.22.5.tgz" integrity sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q== dependencies: "@babel/types" "^7.22.5" "@babel/helper-split-export-declaration@^7.22.6": version "7.22.6" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz#322c61b7310c0997fe4c323955667f18fcefb91c" + resolved "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz" integrity sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g== dependencies: "@babel/types" "^7.22.5" "@babel/helper-string-parser@^7.23.4": version "7.23.4" - resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz#9478c707febcbbe1ddb38a3d91a2e054ae622d83" + resolved "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz" integrity sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ== "@babel/helper-validator-identifier@^7.22.20": version "7.22.20" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz#c4ae002c61d2879e724581d96665583dbc1dc0e0" + resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz" integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A== "@babel/helper-validator-option@^7.22.15", "@babel/helper-validator-option@^7.23.5": version "7.23.5" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz#907a3fbd4523426285365d1206c423c4c5520307" + resolved "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz" integrity sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw== "@babel/helper-wrap-function@^7.22.20": version "7.22.20" - resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.22.20.tgz#15352b0b9bfb10fc9c76f79f6342c00e3411a569" + resolved "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.22.20.tgz" integrity sha512-pms/UwkOpnQe/PDAEdV/d7dVCoBbB+R4FvYoHGZz+4VPcg7RtYy2KP7S2lbuWM6FCSgob5wshfGESbC/hzNXZw== dependencies: "@babel/helper-function-name" "^7.22.5" @@ -252,7 +252,7 @@ "@babel/helpers@^7.23.5": version "7.23.5" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.23.5.tgz#52f522840df8f1a848d06ea6a79b79eefa72401e" + resolved "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.5.tgz" integrity sha512-oO7us8FzTEsG3U6ag9MfdF1iA/7Z6dz+MtFhifZk8C8o453rGJFFWUP1t+ULM9TUIAzC9uxXEiXjOiVMyd7QPg== dependencies: "@babel/template" "^7.22.15" @@ -261,7 +261,7 @@ "@babel/highlight@^7.23.4": version "7.23.4" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.23.4.tgz#edaadf4d8232e1a961432db785091207ead0621b" + resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz" integrity sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A== dependencies: "@babel/helper-validator-identifier" "^7.22.20" @@ -270,19 +270,19 @@ "@babel/parser@^7.22.15", "@babel/parser@^7.23.5": version "7.23.5" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.5.tgz#37dee97c4752af148e1d38c34b856b2507660563" + resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.23.5.tgz" integrity sha512-hOOqoiNXrmGdFbhgCzu6GiURxUgM27Xwd/aPuu8RfHEZPBzL1Z54okAHAQjXfcQNwvrlkAmAp4SlRTZ45vlthQ== "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.23.3": version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.23.3.tgz#5cd1c87ba9380d0afb78469292c954fee5d2411a" + resolved "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.23.3.tgz" integrity sha512-iRkKcCqb7iGnq9+3G6rZ+Ciz5VywC4XNRHe57lKM+jOeYAoR0lVqdeeDRfh0tQcTfw/+vBhHn926FmQhLtlFLQ== dependencies: "@babel/helper-plugin-utils" "^7.22.5" "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.23.3": version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.23.3.tgz#f6652bb16b94f8f9c20c50941e16e9756898dc5d" + resolved "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.23.3.tgz" integrity sha512-WwlxbfMNdVEpQjZmK5mhm7oSwD3dS6eU+Iwsi4Knl9wAletWem7kaRsGOG+8UEbRyqxY4SS5zvtfXwX+jMxUwQ== dependencies: "@babel/helper-plugin-utils" "^7.22.5" @@ -291,7 +291,7 @@ "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@^7.23.3": version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.23.3.tgz#20c60d4639d18f7da8602548512e9d3a4c8d7098" + resolved "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.23.3.tgz" integrity sha512-XaJak1qcityzrX0/IU5nKHb34VaibwP3saKqG6a/tppelgllOH13LUann4ZCIBcVOeE6H18K4Vx9QKkVww3z/w== dependencies: "@babel/helper-environment-visitor" "^7.22.20" @@ -299,138 +299,138 @@ "@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2": version "7.21.0-placeholder-for-preset-env.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz#7844f9289546efa9febac2de4cfe358a050bd703" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz" integrity sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w== "@babel/plugin-syntax-async-generators@^7.8.4": version "7.8.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz" integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== dependencies: "@babel/helper-plugin-utils" "^7.8.0" "@babel/plugin-syntax-class-properties@^7.12.13": version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz" integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== dependencies: "@babel/helper-plugin-utils" "^7.12.13" "@babel/plugin-syntax-class-static-block@^7.14.5": version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz#195df89b146b4b78b3bf897fd7a257c84659d406" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz" integrity sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw== dependencies: "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-syntax-dynamic-import@^7.8.3": version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz" integrity sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ== dependencies: "@babel/helper-plugin-utils" "^7.8.0" "@babel/plugin-syntax-export-namespace-from@^7.8.3": version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz#028964a9ba80dbc094c915c487ad7c4e7a66465a" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz" integrity sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q== dependencies: "@babel/helper-plugin-utils" "^7.8.3" "@babel/plugin-syntax-import-assertions@^7.23.3": version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.23.3.tgz#9c05a7f592982aff1a2768260ad84bcd3f0c77fc" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.23.3.tgz" integrity sha512-lPgDSU+SJLK3xmFDTV2ZRQAiM7UuUjGidwBywFavObCiZc1BeAAcMtHJKUya92hPHO+at63JJPLygilZard8jw== dependencies: "@babel/helper-plugin-utils" "^7.22.5" "@babel/plugin-syntax-import-attributes@^7.23.3": version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.23.3.tgz#992aee922cf04512461d7dae3ff6951b90a2dc06" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.23.3.tgz" integrity sha512-pawnE0P9g10xgoP7yKr6CK63K2FMsTE+FZidZO/1PwRdzmAPVs+HS1mAURUsgaoxammTJvULUdIkEK0gOcU2tA== dependencies: "@babel/helper-plugin-utils" "^7.22.5" "@babel/plugin-syntax-import-meta@^7.10.4": version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz" integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== dependencies: "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-json-strings@^7.8.3": version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz" integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== dependencies: "@babel/helper-plugin-utils" "^7.8.0" "@babel/plugin-syntax-jsx@^7.23.3": version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.23.3.tgz#8f2e4f8a9b5f9aa16067e142c1ac9cd9f810f473" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.23.3.tgz" integrity sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg== dependencies: "@babel/helper-plugin-utils" "^7.22.5" "@babel/plugin-syntax-logical-assignment-operators@^7.10.4": version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz" integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== dependencies: "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz" integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== dependencies: "@babel/helper-plugin-utils" "^7.8.0" "@babel/plugin-syntax-numeric-separator@^7.10.4": version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz" integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== dependencies: "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-object-rest-spread@^7.8.3": version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz" integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== dependencies: "@babel/helper-plugin-utils" "^7.8.0" "@babel/plugin-syntax-optional-catch-binding@^7.8.3": version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz" integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== dependencies: "@babel/helper-plugin-utils" "^7.8.0" "@babel/plugin-syntax-optional-chaining@^7.8.3": version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz" integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== dependencies: "@babel/helper-plugin-utils" "^7.8.0" "@babel/plugin-syntax-private-property-in-object@^7.14.5": version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz#0dc6671ec0ea22b6e94a1114f857970cd39de1ad" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz" integrity sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg== dependencies: "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-syntax-top-level-await@^7.14.5": version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz" integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== dependencies: "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-syntax-unicode-sets-regex@^7.18.6": version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz#d49a3b3e6b52e5be6740022317580234a6a47357" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz" integrity sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg== dependencies: "@babel/helper-create-regexp-features-plugin" "^7.18.6" @@ -438,14 +438,14 @@ "@babel/plugin-transform-arrow-functions@^7.23.3": version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.23.3.tgz#94c6dcfd731af90f27a79509f9ab7fb2120fc38b" + resolved "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.23.3.tgz" integrity sha512-NzQcQrzaQPkaEwoTm4Mhyl8jI1huEL/WWIEvudjTCMJ9aBZNpsJbMASx7EQECtQQPS/DcnFpo0FIh3LvEO9cxQ== dependencies: "@babel/helper-plugin-utils" "^7.22.5" "@babel/plugin-transform-async-generator-functions@^7.23.4": version "7.23.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.23.4.tgz#93ac8e3531f347fba519b4703f9ff2a75c6ae27a" + resolved "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.23.4.tgz" integrity sha512-efdkfPhHYTtn0G6n2ddrESE91fgXxjlqLsnUtPWnJs4a4mZIbUaK7ffqKIIUKXSHwcDvaCVX6GXkaJJFqtX7jw== dependencies: "@babel/helper-environment-visitor" "^7.22.20" @@ -455,7 +455,7 @@ "@babel/plugin-transform-async-to-generator@^7.23.3": version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.23.3.tgz#d1f513c7a8a506d43f47df2bf25f9254b0b051fa" + resolved "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.23.3.tgz" integrity sha512-A7LFsKi4U4fomjqXJlZg/u0ft/n8/7n7lpffUP/ZULx/DtV9SGlNKZolHH6PE8Xl1ngCc0M11OaeZptXVkfKSw== dependencies: "@babel/helper-module-imports" "^7.22.15" @@ -464,21 +464,21 @@ "@babel/plugin-transform-block-scoped-functions@^7.23.3": version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.23.3.tgz#fe1177d715fb569663095e04f3598525d98e8c77" + resolved "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.23.3.tgz" integrity sha512-vI+0sIaPIO6CNuM9Kk5VmXcMVRiOpDh7w2zZt9GXzmE/9KD70CUEVhvPR/etAeNK/FAEkhxQtXOzVF3EuRL41A== dependencies: "@babel/helper-plugin-utils" "^7.22.5" "@babel/plugin-transform-block-scoping@^7.23.4": version "7.23.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.23.4.tgz#b2d38589531c6c80fbe25e6b58e763622d2d3cf5" + resolved "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.23.4.tgz" integrity sha512-0QqbP6B6HOh7/8iNR4CQU2Th/bbRtBp4KS9vcaZd1fZ0wSh5Fyssg0UCIHwxh+ka+pNDREbVLQnHCMHKZfPwfw== dependencies: "@babel/helper-plugin-utils" "^7.22.5" "@babel/plugin-transform-class-properties@^7.23.3": version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.23.3.tgz#35c377db11ca92a785a718b6aa4e3ed1eb65dc48" + resolved "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.23.3.tgz" integrity sha512-uM+AN8yCIjDPccsKGlw271xjJtGii+xQIF/uMPS8H15L12jZTsLfF4o5vNO7d/oUguOyfdikHGc/yi9ge4SGIg== dependencies: "@babel/helper-create-class-features-plugin" "^7.22.15" @@ -486,7 +486,7 @@ "@babel/plugin-transform-class-static-block@^7.23.4": version "7.23.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.23.4.tgz#2a202c8787a8964dd11dfcedf994d36bfc844ab5" + resolved "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.23.4.tgz" integrity sha512-nsWu/1M+ggti1SOALj3hfx5FXzAY06fwPJsUZD4/A5e1bWi46VUIWtD+kOX6/IdhXGsXBWllLFDSnqSCdUNydQ== dependencies: "@babel/helper-create-class-features-plugin" "^7.22.15" @@ -495,7 +495,7 @@ "@babel/plugin-transform-classes@^7.23.5": version "7.23.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.23.5.tgz#e7a75f815e0c534cc4c9a39c56636c84fc0d64f2" + resolved "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.23.5.tgz" integrity sha512-jvOTR4nicqYC9yzOHIhXG5emiFEOpappSJAl73SDSEDcybD+Puuze8Tnpb9p9qEyYup24tq891gkaygIFvWDqg== dependencies: "@babel/helper-annotate-as-pure" "^7.22.5" @@ -510,7 +510,7 @@ "@babel/plugin-transform-computed-properties@^7.23.3": version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.23.3.tgz#652e69561fcc9d2b50ba4f7ac7f60dcf65e86474" + resolved "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.23.3.tgz" integrity sha512-dTj83UVTLw/+nbiHqQSFdwO9CbTtwq1DsDqm3CUEtDrZNET5rT5E6bIdTlOftDTDLMYxvxHNEYO4B9SLl8SLZw== dependencies: "@babel/helper-plugin-utils" "^7.22.5" @@ -518,14 +518,14 @@ "@babel/plugin-transform-destructuring@^7.23.3": version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.23.3.tgz#8c9ee68228b12ae3dff986e56ed1ba4f3c446311" + resolved "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.23.3.tgz" integrity sha512-n225npDqjDIr967cMScVKHXJs7rout1q+tt50inyBCPkyZ8KxeI6d+GIbSBTT/w/9WdlWDOej3V9HE5Lgk57gw== dependencies: "@babel/helper-plugin-utils" "^7.22.5" "@babel/plugin-transform-dotall-regex@^7.23.3": version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.23.3.tgz#3f7af6054882ede89c378d0cf889b854a993da50" + resolved "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.23.3.tgz" integrity sha512-vgnFYDHAKzFaTVp+mneDsIEbnJ2Np/9ng9iviHw3P/KVcgONxpNULEW/51Z/BaFojG2GI2GwwXck5uV1+1NOYQ== dependencies: "@babel/helper-create-regexp-features-plugin" "^7.22.15" @@ -533,14 +533,14 @@ "@babel/plugin-transform-duplicate-keys@^7.23.3": version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.23.3.tgz#664706ca0a5dfe8d066537f99032fc1dc8b720ce" + resolved "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.23.3.tgz" integrity sha512-RrqQ+BQmU3Oyav3J+7/myfvRCq7Tbz+kKLLshUmMwNlDHExbGL7ARhajvoBJEvc+fCguPPu887N+3RRXBVKZUA== dependencies: "@babel/helper-plugin-utils" "^7.22.5" "@babel/plugin-transform-dynamic-import@^7.23.4": version "7.23.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.23.4.tgz#c7629e7254011ac3630d47d7f34ddd40ca535143" + resolved "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.23.4.tgz" integrity sha512-V6jIbLhdJK86MaLh4Jpghi8ho5fGzt3imHOBu/x0jlBaPYqDoWz4RDXjmMOfnh+JWNaQleEAByZLV0QzBT4YQQ== dependencies: "@babel/helper-plugin-utils" "^7.22.5" @@ -548,7 +548,7 @@ "@babel/plugin-transform-exponentiation-operator@^7.23.3": version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.23.3.tgz#ea0d978f6b9232ba4722f3dbecdd18f450babd18" + resolved "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.23.3.tgz" integrity sha512-5fhCsl1odX96u7ILKHBj4/Y8vipoqwsJMh4csSA8qFfxrZDEA4Ssku2DyNvMJSmZNOEBT750LfFPbtrnTP90BQ== dependencies: "@babel/helper-builder-binary-assignment-operator-visitor" "^7.22.15" @@ -556,7 +556,7 @@ "@babel/plugin-transform-export-namespace-from@^7.23.4": version "7.23.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.23.4.tgz#084c7b25e9a5c8271e987a08cf85807b80283191" + resolved "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.23.4.tgz" integrity sha512-GzuSBcKkx62dGzZI1WVgTWvkkz84FZO5TC5T8dl/Tht/rAla6Dg/Mz9Yhypg+ezVACf/rgDuQt3kbWEv7LdUDQ== dependencies: "@babel/helper-plugin-utils" "^7.22.5" @@ -564,14 +564,14 @@ "@babel/plugin-transform-for-of@^7.23.3": version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.23.3.tgz#afe115ff0fbce735e02868d41489093c63e15559" + resolved "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.23.3.tgz" integrity sha512-X8jSm8X1CMwxmK878qsUGJRmbysKNbdpTv/O1/v0LuY/ZkZrng5WYiekYSdg9m09OTmDDUWeEDsTE+17WYbAZw== dependencies: "@babel/helper-plugin-utils" "^7.22.5" "@babel/plugin-transform-function-name@^7.23.3": version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.23.3.tgz#8f424fcd862bf84cb9a1a6b42bc2f47ed630f8dc" + resolved "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.23.3.tgz" integrity sha512-I1QXp1LxIvt8yLaib49dRW5Okt7Q4oaxao6tFVKS/anCdEOMtYwWVKoiOA1p34GOWIZjUK0E+zCp7+l1pfQyiw== dependencies: "@babel/helper-compilation-targets" "^7.22.15" @@ -580,7 +580,7 @@ "@babel/plugin-transform-json-strings@^7.23.4": version "7.23.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.23.4.tgz#a871d9b6bd171976efad2e43e694c961ffa3714d" + resolved "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.23.4.tgz" integrity sha512-81nTOqM1dMwZ/aRXQ59zVubN9wHGqk6UtqRK+/q+ciXmRy8fSolhGVvG09HHRGo4l6fr/c4ZhXUQH0uFW7PZbg== dependencies: "@babel/helper-plugin-utils" "^7.22.5" @@ -588,14 +588,14 @@ "@babel/plugin-transform-literals@^7.23.3": version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.23.3.tgz#8214665f00506ead73de157eba233e7381f3beb4" + resolved "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.23.3.tgz" integrity sha512-wZ0PIXRxnwZvl9AYpqNUxpZ5BiTGrYt7kueGQ+N5FiQ7RCOD4cm8iShd6S6ggfVIWaJf2EMk8eRzAh52RfP4rQ== dependencies: "@babel/helper-plugin-utils" "^7.22.5" "@babel/plugin-transform-logical-assignment-operators@^7.23.4": version "7.23.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.23.4.tgz#e599f82c51d55fac725f62ce55d3a0886279ecb5" + resolved "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.23.4.tgz" integrity sha512-Mc/ALf1rmZTP4JKKEhUwiORU+vcfarFVLfcFiolKUo6sewoxSEgl36ak5t+4WamRsNr6nzjZXQjM35WsU+9vbg== dependencies: "@babel/helper-plugin-utils" "^7.22.5" @@ -603,14 +603,14 @@ "@babel/plugin-transform-member-expression-literals@^7.23.3": version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.23.3.tgz#e37b3f0502289f477ac0e776b05a833d853cabcc" + resolved "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.23.3.tgz" integrity sha512-sC3LdDBDi5x96LA+Ytekz2ZPk8i/Ck+DEuDbRAll5rknJ5XRTSaPKEYwomLcs1AA8wg9b3KjIQRsnApj+q51Ag== dependencies: "@babel/helper-plugin-utils" "^7.22.5" "@babel/plugin-transform-modules-amd@^7.23.3": version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.23.3.tgz#e19b55436a1416829df0a1afc495deedfae17f7d" + resolved "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.23.3.tgz" integrity sha512-vJYQGxeKM4t8hYCKVBlZX/gtIY2I7mRGFNcm85sgXGMTBcoV3QdVtdpbcWEbzbfUIUZKwvgFT82mRvaQIebZzw== dependencies: "@babel/helper-module-transforms" "^7.23.3" @@ -618,7 +618,7 @@ "@babel/plugin-transform-modules-commonjs@^7.23.3": version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.23.3.tgz#661ae831b9577e52be57dd8356b734f9700b53b4" + resolved "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.23.3.tgz" integrity sha512-aVS0F65LKsdNOtcz6FRCpE4OgsP2OFnW46qNxNIX9h3wuzaNcSQsJysuMwqSibC98HPrf2vCgtxKNwS0DAlgcA== dependencies: "@babel/helper-module-transforms" "^7.23.3" @@ -627,7 +627,7 @@ "@babel/plugin-transform-modules-systemjs@^7.23.3": version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.23.3.tgz#fa7e62248931cb15b9404f8052581c302dd9de81" + resolved "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.23.3.tgz" integrity sha512-ZxyKGTkF9xT9YJuKQRo19ewf3pXpopuYQd8cDXqNzc3mUNbOME0RKMoZxviQk74hwzfQsEe66dE92MaZbdHKNQ== dependencies: "@babel/helper-hoist-variables" "^7.22.5" @@ -637,7 +637,7 @@ "@babel/plugin-transform-modules-umd@^7.23.3": version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.23.3.tgz#5d4395fccd071dfefe6585a4411aa7d6b7d769e9" + resolved "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.23.3.tgz" integrity sha512-zHsy9iXX2nIsCBFPud3jKn1IRPWg3Ing1qOZgeKV39m1ZgIdpJqvlWVeiHBZC6ITRG0MfskhYe9cLgntfSFPIg== dependencies: "@babel/helper-module-transforms" "^7.23.3" @@ -645,7 +645,7 @@ "@babel/plugin-transform-named-capturing-groups-regex@^7.22.5": version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.22.5.tgz#67fe18ee8ce02d57c855185e27e3dc959b2e991f" + resolved "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.22.5.tgz" integrity sha512-YgLLKmS3aUBhHaxp5hi1WJTgOUb/NCuDHzGT9z9WTt3YG+CPRhJs6nprbStx6DnWM4dh6gt7SU3sZodbZ08adQ== dependencies: "@babel/helper-create-regexp-features-plugin" "^7.22.5" @@ -653,14 +653,14 @@ "@babel/plugin-transform-new-target@^7.23.3": version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.23.3.tgz#5491bb78ed6ac87e990957cea367eab781c4d980" + resolved "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.23.3.tgz" integrity sha512-YJ3xKqtJMAT5/TIZnpAR3I+K+WaDowYbN3xyxI8zxx/Gsypwf9B9h0VB+1Nh6ACAAPRS5NSRje0uVv5i79HYGQ== dependencies: "@babel/helper-plugin-utils" "^7.22.5" "@babel/plugin-transform-nullish-coalescing-operator@^7.23.4": version "7.23.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.23.4.tgz#45556aad123fc6e52189ea749e33ce090637346e" + resolved "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.23.4.tgz" integrity sha512-jHE9EVVqHKAQx+VePv5LLGHjmHSJR76vawFPTdlxR/LVJPfOEGxREQwQfjuZEOPTwG92X3LINSh3M40Rv4zpVA== dependencies: "@babel/helper-plugin-utils" "^7.22.5" @@ -668,7 +668,7 @@ "@babel/plugin-transform-numeric-separator@^7.23.4": version "7.23.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.23.4.tgz#03d08e3691e405804ecdd19dd278a40cca531f29" + resolved "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.23.4.tgz" integrity sha512-mps6auzgwjRrwKEZA05cOwuDc9FAzoyFS4ZsG/8F43bTLf/TgkJg7QXOrPO1JO599iA3qgK9MXdMGOEC8O1h6Q== dependencies: "@babel/helper-plugin-utils" "^7.22.5" @@ -676,7 +676,7 @@ "@babel/plugin-transform-object-rest-spread@^7.23.4": version "7.23.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.23.4.tgz#2b9c2d26bf62710460bdc0d1730d4f1048361b83" + resolved "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.23.4.tgz" integrity sha512-9x9K1YyeQVw0iOXJlIzwm8ltobIIv7j2iLyP2jIhEbqPRQ7ScNgwQufU2I0Gq11VjyG4gI4yMXt2VFags+1N3g== dependencies: "@babel/compat-data" "^7.23.3" @@ -687,7 +687,7 @@ "@babel/plugin-transform-object-super@^7.23.3": version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.23.3.tgz#81fdb636dcb306dd2e4e8fd80db5b2362ed2ebcd" + resolved "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.23.3.tgz" integrity sha512-BwQ8q0x2JG+3lxCVFohg+KbQM7plfpBwThdW9A6TMtWwLsbDA01Ek2Zb/AgDN39BiZsExm4qrXxjk+P1/fzGrA== dependencies: "@babel/helper-plugin-utils" "^7.22.5" @@ -695,7 +695,7 @@ "@babel/plugin-transform-optional-catch-binding@^7.23.4": version "7.23.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.23.4.tgz#318066de6dacce7d92fa244ae475aa8d91778017" + resolved "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.23.4.tgz" integrity sha512-XIq8t0rJPHf6Wvmbn9nFxU6ao4c7WhghTR5WyV8SrJfUFzyxhCm4nhC+iAp3HFhbAKLfYpgzhJ6t4XCtVwqO5A== dependencies: "@babel/helper-plugin-utils" "^7.22.5" @@ -703,7 +703,7 @@ "@babel/plugin-transform-optional-chaining@^7.23.3", "@babel/plugin-transform-optional-chaining@^7.23.4": version "7.23.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.23.4.tgz#6acf61203bdfc4de9d4e52e64490aeb3e52bd017" + resolved "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.23.4.tgz" integrity sha512-ZU8y5zWOfjM5vZ+asjgAPwDaBjJzgufjES89Rs4Lpq63O300R/kOz30WCLo6BxxX6QVEilwSlpClnG5cZaikTA== dependencies: "@babel/helper-plugin-utils" "^7.22.5" @@ -712,14 +712,14 @@ "@babel/plugin-transform-parameters@^7.23.3": version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.23.3.tgz#83ef5d1baf4b1072fa6e54b2b0999a7b2527e2af" + resolved "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.23.3.tgz" integrity sha512-09lMt6UsUb3/34BbECKVbVwrT9bO6lILWln237z7sLaWnMsTi7Yc9fhX5DLpkJzAGfaReXI22wP41SZmnAA3Vw== dependencies: "@babel/helper-plugin-utils" "^7.22.5" "@babel/plugin-transform-private-methods@^7.23.3": version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.23.3.tgz#b2d7a3c97e278bfe59137a978d53b2c2e038c0e4" + resolved "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.23.3.tgz" integrity sha512-UzqRcRtWsDMTLrRWFvUBDwmw06tCQH9Rl1uAjfh6ijMSmGYQ+fpdB+cnqRC8EMh5tuuxSv0/TejGL+7vyj+50g== dependencies: "@babel/helper-create-class-features-plugin" "^7.22.15" @@ -727,7 +727,7 @@ "@babel/plugin-transform-private-property-in-object@^7.23.4": version "7.23.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.23.4.tgz#3ec711d05d6608fd173d9b8de39872d8dbf68bf5" + resolved "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.23.4.tgz" integrity sha512-9G3K1YqTq3F4Vt88Djx1UZ79PDyj+yKRnUy7cZGSMe+a7jkwD259uKKuUzQlPkGam7R+8RJwh5z4xO27fA1o2A== dependencies: "@babel/helper-annotate-as-pure" "^7.22.5" @@ -737,28 +737,28 @@ "@babel/plugin-transform-property-literals@^7.23.3": version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.23.3.tgz#54518f14ac4755d22b92162e4a852d308a560875" + resolved "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.23.3.tgz" integrity sha512-jR3Jn3y7cZp4oEWPFAlRsSWjxKe4PZILGBSd4nis1TsC5qeSpb+nrtihJuDhNI7QHiVbUaiXa0X2RZY3/TI6Nw== dependencies: "@babel/helper-plugin-utils" "^7.22.5" "@babel/plugin-transform-react-display-name@^7.23.3": version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.23.3.tgz#70529f034dd1e561045ad3c8152a267f0d7b6200" + resolved "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.23.3.tgz" integrity sha512-GnvhtVfA2OAtzdX58FJxU19rhoGeQzyVndw3GgtdECQvQFXPEZIOVULHVZGAYmOgmqjXpVpfocAbSjh99V/Fqw== dependencies: "@babel/helper-plugin-utils" "^7.22.5" "@babel/plugin-transform-react-jsx-development@^7.22.5": version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.22.5.tgz#e716b6edbef972a92165cd69d92f1255f7e73e87" + resolved "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.22.5.tgz" integrity sha512-bDhuzwWMuInwCYeDeMzyi7TaBgRQei6DqxhbyniL7/VG4RSS7HtSL2QbY4eESy1KJqlWt8g3xeEBGPuo+XqC8A== dependencies: "@babel/plugin-transform-react-jsx" "^7.22.5" "@babel/plugin-transform-react-jsx@^7.22.15", "@babel/plugin-transform-react-jsx@^7.22.5": version "7.23.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.23.4.tgz#393f99185110cea87184ea47bcb4a7b0c2e39312" + resolved "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.23.4.tgz" integrity sha512-5xOpoPguCZCRbo/JeHlloSkTA8Bld1J/E1/kLfD1nsuiW1m8tduTA1ERCgIZokDflX/IBzKcqR3l7VlRgiIfHA== dependencies: "@babel/helper-annotate-as-pure" "^7.22.5" @@ -769,7 +769,7 @@ "@babel/plugin-transform-react-pure-annotations@^7.23.3": version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.23.3.tgz#fabedbdb8ee40edf5da96f3ecfc6958e3783b93c" + resolved "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.23.3.tgz" integrity sha512-qMFdSS+TUhB7Q/3HVPnEdYJDQIk57jkntAwSuz9xfSE4n+3I+vHYCli3HoHawN1Z3RfCz/y1zXA/JXjG6cVImQ== dependencies: "@babel/helper-annotate-as-pure" "^7.22.5" @@ -777,7 +777,7 @@ "@babel/plugin-transform-regenerator@^7.23.3": version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.23.3.tgz#141afd4a2057298602069fce7f2dc5173e6c561c" + resolved "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.23.3.tgz" integrity sha512-KP+75h0KghBMcVpuKisx3XTu9Ncut8Q8TuvGO4IhY+9D5DFEckQefOuIsB/gQ2tG71lCke4NMrtIPS8pOj18BQ== dependencies: "@babel/helper-plugin-utils" "^7.22.5" @@ -785,21 +785,21 @@ "@babel/plugin-transform-reserved-words@^7.23.3": version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.23.3.tgz#4130dcee12bd3dd5705c587947eb715da12efac8" + resolved "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.23.3.tgz" integrity sha512-QnNTazY54YqgGxwIexMZva9gqbPa15t/x9VS+0fsEFWplwVpXYZivtgl43Z1vMpc1bdPP2PP8siFeVcnFvA3Cg== dependencies: "@babel/helper-plugin-utils" "^7.22.5" "@babel/plugin-transform-shorthand-properties@^7.23.3": version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.23.3.tgz#97d82a39b0e0c24f8a981568a8ed851745f59210" + resolved "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.23.3.tgz" integrity sha512-ED2fgqZLmexWiN+YNFX26fx4gh5qHDhn1O2gvEhreLW2iI63Sqm4llRLCXALKrCnbN4Jy0VcMQZl/SAzqug/jg== dependencies: "@babel/helper-plugin-utils" "^7.22.5" "@babel/plugin-transform-spread@^7.23.3": version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.23.3.tgz#41d17aacb12bde55168403c6f2d6bdca563d362c" + resolved "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.23.3.tgz" integrity sha512-VvfVYlrlBVu+77xVTOAoxQ6mZbnIq5FM0aGBSFEcIh03qHf+zNqA4DC/3XMUozTg7bZV3e3mZQ0i13VB6v5yUg== dependencies: "@babel/helper-plugin-utils" "^7.22.5" @@ -807,35 +807,35 @@ "@babel/plugin-transform-sticky-regex@^7.23.3": version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.23.3.tgz#dec45588ab4a723cb579c609b294a3d1bd22ff04" + resolved "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.23.3.tgz" integrity sha512-HZOyN9g+rtvnOU3Yh7kSxXrKbzgrm5X4GncPY1QOquu7epga5MxKHVpYu2hvQnry/H+JjckSYRb93iNfsioAGg== dependencies: "@babel/helper-plugin-utils" "^7.22.5" "@babel/plugin-transform-template-literals@^7.23.3": version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.23.3.tgz#5f0f028eb14e50b5d0f76be57f90045757539d07" + resolved "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.23.3.tgz" integrity sha512-Flok06AYNp7GV2oJPZZcP9vZdszev6vPBkHLwxwSpaIqx75wn6mUd3UFWsSsA0l8nXAKkyCmL/sR02m8RYGeHg== dependencies: "@babel/helper-plugin-utils" "^7.22.5" "@babel/plugin-transform-typeof-symbol@^7.23.3": version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.23.3.tgz#9dfab97acc87495c0c449014eb9c547d8966bca4" + resolved "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.23.3.tgz" integrity sha512-4t15ViVnaFdrPC74be1gXBSMzXk3B4Us9lP7uLRQHTFpV5Dvt33pn+2MyyNxmN3VTTm3oTrZVMUmuw3oBnQ2oQ== dependencies: "@babel/helper-plugin-utils" "^7.22.5" "@babel/plugin-transform-unicode-escapes@^7.23.3": version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.23.3.tgz#1f66d16cab01fab98d784867d24f70c1ca65b925" + resolved "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.23.3.tgz" integrity sha512-OMCUx/bU6ChE3r4+ZdylEqAjaQgHAgipgW8nsCfu5pGqDcFytVd91AwRvUJSBZDz0exPGgnjoqhgRYLRjFZc9Q== dependencies: "@babel/helper-plugin-utils" "^7.22.5" "@babel/plugin-transform-unicode-property-regex@^7.23.3": version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.23.3.tgz#19e234129e5ffa7205010feec0d94c251083d7ad" + resolved "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.23.3.tgz" integrity sha512-KcLIm+pDZkWZQAFJ9pdfmh89EwVfmNovFBcXko8szpBeF8z68kWIPeKlmSOkT9BXJxs2C0uk+5LxoxIv62MROA== dependencies: "@babel/helper-create-regexp-features-plugin" "^7.22.15" @@ -843,7 +843,7 @@ "@babel/plugin-transform-unicode-regex@^7.23.3": version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.23.3.tgz#26897708d8f42654ca4ce1b73e96140fbad879dc" + resolved "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.23.3.tgz" integrity sha512-wMHpNA4x2cIA32b/ci3AfwNgheiva2W0WUKWTK7vBHBhDKfPsc5cFGNWm69WBqpwd86u1qwZ9PWevKqm1A3yAw== dependencies: "@babel/helper-create-regexp-features-plugin" "^7.22.15" @@ -851,7 +851,7 @@ "@babel/plugin-transform-unicode-sets-regex@^7.23.3": version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.23.3.tgz#4fb6f0a719c2c5859d11f6b55a050cc987f3799e" + resolved "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.23.3.tgz" integrity sha512-W7lliA/v9bNR83Qc3q1ip9CQMZ09CcHDbHfbLRDNuAhn1Mvkr1ZNF7hPmztMQvtTGVLJ9m8IZqWsTkXOml8dbw== dependencies: "@babel/helper-create-regexp-features-plugin" "^7.22.15" @@ -859,7 +859,7 @@ "@babel/preset-env@^7.23.5": version "7.23.5" - resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.23.5.tgz#350a3aedfa9f119ad045b068886457e895ba0ca1" + resolved "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.23.5.tgz" integrity sha512-0d/uxVD6tFGWXGDSfyMD1p2otoaKmu6+GD+NfAx0tMaH+dxORnp7T9TaVQ6mKyya7iBtCIVxHjWT7MuzzM9z+A== dependencies: "@babel/compat-data" "^7.23.5" @@ -945,7 +945,7 @@ "@babel/preset-modules@0.1.6-no-external-plugins": version "0.1.6-no-external-plugins" - resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz#ccb88a2c49c817236861fee7826080573b8a923a" + resolved "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz" integrity sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA== dependencies: "@babel/helper-plugin-utils" "^7.0.0" @@ -954,7 +954,7 @@ "@babel/preset-react@^7.23.3": version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-7.23.3.tgz#f73ca07e7590f977db07eb54dbe46538cc015709" + resolved "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.23.3.tgz" integrity sha512-tbkHOS9axH6Ysf2OUEqoSZ6T3Fa2SrNH6WTWSPBboxKzdxNc9qOICeLXkNG0ZEwbQ1HY8liwOce4aN/Ceyuq6w== dependencies: "@babel/helper-plugin-utils" "^7.22.5" @@ -966,19 +966,19 @@ "@babel/regjsgen@^0.8.0": version "0.8.0" - resolved "https://registry.yarnpkg.com/@babel/regjsgen/-/regjsgen-0.8.0.tgz#f0ba69b075e1f05fb2825b7fad991e7adbb18310" + resolved "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz" integrity sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA== "@babel/runtime@^7.8.4": version "7.23.5" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.23.5.tgz#11edb98f8aeec529b82b211028177679144242db" + resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.5.tgz" integrity sha512-NdUTHcPe4C99WxPub+K9l9tK5/lV4UXIoaHSYgzco9BCyjKAAwzdBI+wWtYqHt7LJdbo74ZjRPJgzVweq1sz0w== dependencies: regenerator-runtime "^0.14.0" "@babel/template@^7.22.15": version "7.22.15" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.22.15.tgz#09576efc3830f0430f4548ef971dde1350ef2f38" + resolved "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz" integrity sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w== dependencies: "@babel/code-frame" "^7.22.13" @@ -987,7 +987,7 @@ "@babel/traverse@^7.23.5": version "7.23.5" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.23.5.tgz#f546bf9aba9ef2b042c0e00d245990c15508e7ec" + resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.5.tgz" integrity sha512-czx7Xy5a6sapWWRx61m1Ke1Ra4vczu1mCTtJam5zRTBOonfdJ+S/B6HYmGYu3fJtr8GGET3si6IhgWVBhJ/m8w== dependencies: "@babel/code-frame" "^7.23.5" @@ -1003,7 +1003,7 @@ "@babel/types@^7.22.15", "@babel/types@^7.22.19", "@babel/types@^7.22.5", "@babel/types@^7.23.0", "@babel/types@^7.23.4", "@babel/types@^7.23.5", "@babel/types@^7.4.4": version "7.23.5" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.23.5.tgz#48d730a00c95109fa4393352705954d74fb5b602" + resolved "https://registry.npmjs.org/@babel/types/-/types-7.23.5.tgz" integrity sha512-ON5kSOJwVO6xXVRTvOI0eOnWe7VdUcIpsovGo9U/Br4Ie4UVFQTboO2cYnDhAGU6Fp+UxSiT+pMft0SMHfuq6w== dependencies: "@babel/helper-string-parser" "^7.23.4" @@ -1012,7 +1012,7 @@ "@jridgewell/gen-mapping@^0.3.0", "@jridgewell/gen-mapping@^0.3.2": version "0.3.3" - resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz#7e02e6eb5df901aaedb08514203b096614024098" + resolved "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz" integrity sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ== dependencies: "@jridgewell/set-array" "^1.0.1" @@ -1021,22 +1021,22 @@ "@jridgewell/resolve-uri@^3.1.0": version "3.1.1" - resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz#c08679063f279615a3326583ba3a90d1d82cc721" + resolved "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz" integrity sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA== "@jridgewell/set-array@^1.0.1": version "1.1.2" - resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" + resolved "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz" integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== "@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14": version "1.4.15" - resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" + resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz" integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== "@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.9": version "0.3.20" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz#72e45707cf240fa6b081d0366f8265b0cd10197f" + resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz" integrity sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q== dependencies: "@jridgewell/resolve-uri" "^3.1.0" @@ -1044,19 +1044,19 @@ "@nicolo-ribaudo/chokidar-2@2.1.8-no-fsevents.3": version "2.1.8-no-fsevents.3" - resolved "https://registry.yarnpkg.com/@nicolo-ribaudo/chokidar-2/-/chokidar-2-2.1.8-no-fsevents.3.tgz#323d72dd25103d0c4fbdce89dadf574a787b1f9b" + resolved "https://registry.npmjs.org/@nicolo-ribaudo/chokidar-2/-/chokidar-2-2.1.8-no-fsevents.3.tgz" integrity sha512-s88O1aVtXftvp5bCPB7WnmXc5IwOZZ7YPuwNPt+GtOOXpPvad1LfbmjYv+qII7zP6RU2QGnqve27dnLycEnyEQ== ansi-styles@^3.2.1: version "3.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz" integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== dependencies: color-convert "^1.9.0" anymatch@~3.1.2: version "3.1.3" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" + resolved "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz" integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== dependencies: normalize-path "^3.0.0" @@ -1064,7 +1064,7 @@ anymatch@~3.1.2: babel-plugin-polyfill-corejs2@^0.4.6: version "0.4.6" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.6.tgz#b2df0251d8e99f229a8e60fc4efa9a68b41c8313" + resolved "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.6.tgz" integrity sha512-jhHiWVZIlnPbEUKSSNb9YoWcQGdlTLq7z1GHL4AjFxaoOUMuuEVJ+Y4pAaQUGOGk93YsVCKPbqbfw3m0SM6H8Q== dependencies: "@babel/compat-data" "^7.22.6" @@ -1073,7 +1073,7 @@ babel-plugin-polyfill-corejs2@^0.4.6: babel-plugin-polyfill-corejs3@^0.8.5: version "0.8.6" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.8.6.tgz#25c2d20002da91fe328ff89095c85a391d6856cf" + resolved "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.8.6.tgz" integrity sha512-leDIc4l4tUgU7str5BWLS2h8q2N4Nf6lGZP6UrNDxdtfF2g69eJ5L0H7S8A5Ln/arfFAfHor5InAdZuIOwZdgQ== dependencies: "@babel/helper-define-polyfill-provider" "^0.4.3" @@ -1081,24 +1081,24 @@ babel-plugin-polyfill-corejs3@^0.8.5: babel-plugin-polyfill-regenerator@^0.5.3: version "0.5.3" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.3.tgz#d4c49e4b44614607c13fb769bcd85c72bb26a4a5" + resolved "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.3.tgz" integrity sha512-8sHeDOmXC8csczMrYEOf0UTNa4yE2SxV5JGeT/LP1n0OYVDUUFPxG9vdk2AlDlIit4t+Kf0xCtpgXPBwnn/9pw== dependencies: "@babel/helper-define-polyfill-provider" "^0.4.3" balanced-match@^1.0.0: version "1.0.2" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== binary-extensions@^2.0.0: version "2.2.0" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" + resolved "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz" integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== brace-expansion@^1.1.7: version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz" integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== dependencies: balanced-match "^1.0.0" @@ -1106,14 +1106,14 @@ brace-expansion@^1.1.7: braces@~3.0.2: version "3.0.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + resolved "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz" integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== dependencies: fill-range "^7.0.1" -browserslist@^4.21.9, browserslist@^4.22.1: +browserslist@^4.21.9, browserslist@^4.22.1, "browserslist@>= 4.21.0": version "4.22.1" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.22.1.tgz#ba91958d1a59b87dab6fed8dfbcb3da5e2e9c619" + resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.22.1.tgz" integrity sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ== dependencies: caniuse-lite "^1.0.30001541" @@ -1123,12 +1123,12 @@ browserslist@^4.21.9, browserslist@^4.22.1: caniuse-lite@^1.0.30001541: version "1.0.30001565" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001565.tgz#a528b253c8a2d95d2b415e11d8b9942acc100c4f" + resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001565.tgz" integrity sha512-xrE//a3O7TP0vaJ8ikzkD2c2NgcVUvsEe2IvFTntV4Yd1Z9FVzh+gW+enX96L0psrbaFMcVcH2l90xNuGDWc8w== chalk@^2.4.2: version "2.4.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== dependencies: ansi-styles "^3.2.1" @@ -1137,7 +1137,7 @@ chalk@^2.4.2: chokidar@^3.4.0: version "3.5.3" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" + resolved "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz" integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== dependencies: anymatch "~3.1.2" @@ -1152,107 +1152,107 @@ chokidar@^3.4.0: color-convert@^1.9.0: version "1.9.3" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + resolved "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz" integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== dependencies: color-name "1.1.3" color-name@1.1.3: version "1.1.3" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== commander@^4.0.1: version "4.1.1" - resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068" + resolved "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz" integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA== concat-map@0.0.1: version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== convert-source-map@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" + resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz" integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== core-js-compat@^3.31.0, core-js-compat@^3.33.1: version "3.33.3" - resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.33.3.tgz#ec678b772c5a2d8a7c60a91c3a81869aa704ae01" + resolved "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.33.3.tgz" integrity sha512-cNzGqFsh3Ot+529GIXacjTJ7kegdt5fPXxCBVS1G0iaZpuo/tBz399ymceLJveQhFFZ8qThHiP3fzuoQjKN2ow== dependencies: browserslist "^4.22.1" debug@^4.1.0, debug@^4.1.1: version "4.3.4" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz" integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== dependencies: ms "2.1.2" electron-to-chromium@^1.4.535: version "1.4.596" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.596.tgz#6752d1aa795d942d49dfc5d3764d6ea283fab1d7" + resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.596.tgz" integrity sha512-zW3zbZ40Icb2BCWjm47nxwcFGYlIgdXkAx85XDO7cyky9J4QQfq8t0W19/TLZqq3JPQXtlv8BPIGmfa9Jb4scg== escalade@^3.1.1: version "3.1.1" - resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" + resolved "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz" integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== escape-string-regexp@^1.0.5: version "1.0.5" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz" integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== esutils@^2.0.2: version "2.0.3" - resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + resolved "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== fill-range@^7.0.1: version "7.0.1" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + resolved "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz" integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== dependencies: to-regex-range "^5.0.1" fs-readdir-recursive@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz#e32fc030a2ccee44a6b5371308da54be0b397d27" + resolved "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz" integrity sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA== fs.realpath@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== fsevents@~2.3.2: version "2.3.3" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz" integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== function-bind@^1.1.2: version "1.1.2" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz" integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== gensync@^1.0.0-beta.2: version "1.0.0-beta.2" - resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" + resolved "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz" integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== glob-parent@~5.1.2: version "5.1.2" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz" integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== dependencies: is-glob "^4.0.1" glob@^7.2.0: version "7.2.3" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" + resolved "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz" integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== dependencies: fs.realpath "^1.0.0" @@ -1264,24 +1264,24 @@ glob@^7.2.0: globals@^11.1.0: version "11.12.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + resolved "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz" integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== has-flag@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + resolved "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz" integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== hasown@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.0.tgz#f4c513d454a57b7c7e1650778de226b11700546c" + resolved "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz" integrity sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA== dependencies: function-bind "^1.1.2" inflight@^1.0.4: version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz" integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== dependencies: once "^1.3.0" @@ -1289,75 +1289,75 @@ inflight@^1.0.4: inherits@2: version "2.0.4" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== is-binary-path@~2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + resolved "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz" integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== dependencies: binary-extensions "^2.0.0" is-core-module@^2.13.0: version "2.13.1" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.1.tgz#ad0d7532c6fea9da1ebdc82742d74525c6273384" + resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz" integrity sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw== dependencies: hasown "^2.0.0" is-extglob@^2.1.1: version "2.1.1" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz" integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== is-glob@^4.0.1, is-glob@~4.0.1: version "4.0.3" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz" integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== dependencies: is-extglob "^2.1.1" is-number@^7.0.0: version "7.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + resolved "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz" integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== js-tokens@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== jsesc@^2.5.1: version "2.5.2" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + resolved "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz" integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== jsesc@~0.5.0: version "0.5.0" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" + resolved "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz" integrity sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA== json5@^2.2.3: version "2.2.3" - resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" + resolved "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz" integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== lodash.debounce@^4.0.8: version "4.0.8" - resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" + resolved "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz" integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow== lru-cache@^5.1.1: version "5.1.1" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" + resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz" integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== dependencies: yallist "^3.0.2" make-dir@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" + resolved "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz" integrity sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA== dependencies: pify "^4.0.1" @@ -1365,92 +1365,92 @@ make-dir@^2.1.0: minimatch@^3.1.1: version "3.1.2" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz" integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== dependencies: brace-expansion "^1.1.7" ms@2.1.2: version "2.1.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== node-releases@^2.0.13: version "2.0.13" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.13.tgz#d5ed1627c23e3461e819b02e57b75e4899b1c81d" + resolved "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz" integrity sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ== normalize-path@^3.0.0, normalize-path@~3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz" integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== once@^1.3.0: version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz" integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== dependencies: wrappy "1" path-is-absolute@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz" integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== path-parse@^1.0.7: version "1.0.7" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== picocolors@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" + resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz" integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== picomatch@^2.0.4, picomatch@^2.2.1: version "2.3.1" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== pify@^4.0.1: version "4.0.1" - resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" + resolved "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz" integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== readdirp@~3.6.0: version "3.6.0" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + resolved "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz" integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== dependencies: picomatch "^2.2.1" regenerate-unicode-properties@^10.1.0: version "10.1.1" - resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.1.tgz#6b0e05489d9076b04c436f318d9b067bba459480" + resolved "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.1.tgz" integrity sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q== dependencies: regenerate "^1.4.2" regenerate@^1.4.2: version "1.4.2" - resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a" + resolved "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz" integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A== regenerator-runtime@^0.14.0: version "0.14.0" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz#5e19d68eb12d486f797e15a3c6a918f7cec5eb45" + resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz" integrity sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA== regenerator-transform@^0.15.2: version "0.15.2" - resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.15.2.tgz#5bbae58b522098ebdf09bca2f83838929001c7a4" + resolved "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz" integrity sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg== dependencies: "@babel/runtime" "^7.8.4" regexpu-core@^5.3.1: version "5.3.2" - resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-5.3.2.tgz#11a2b06884f3527aec3e93dbbf4a3b958a95546b" + resolved "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz" integrity sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ== dependencies: "@babel/regjsgen" "^0.8.0" @@ -1462,14 +1462,14 @@ regexpu-core@^5.3.1: regjsparser@^0.9.1: version "0.9.1" - resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.9.1.tgz#272d05aa10c7c1f67095b1ff0addae8442fc5709" + resolved "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz" integrity sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ== dependencies: jsesc "~0.5.0" resolve@^1.14.2: version "1.22.8" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" + resolved "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz" integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== dependencies: is-core-module "^2.13.0" @@ -1478,51 +1478,51 @@ resolve@^1.14.2: semver@^5.6.0: version "5.7.2" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" + resolved "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz" integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== semver@^6.3.1: version "6.3.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" + resolved "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== slash@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44" + resolved "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz" integrity sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A== supports-color@^5.3.0: version "5.5.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz" integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== dependencies: has-flag "^3.0.0" supports-preserve-symlinks-flag@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" + resolved "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz" integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== to-fast-properties@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + resolved "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz" integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== to-regex-range@^5.0.1: version "5.0.1" - resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + resolved "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz" integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== dependencies: is-number "^7.0.0" unicode-canonical-property-names-ecmascript@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz#301acdc525631670d39f6146e0e77ff6bbdebddc" + resolved "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz" integrity sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ== unicode-match-property-ecmascript@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz#54fd16e0ecb167cf04cf1f756bdcc92eba7976c3" + resolved "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz" integrity sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q== dependencies: unicode-canonical-property-names-ecmascript "^2.0.0" @@ -1530,17 +1530,17 @@ unicode-match-property-ecmascript@^2.0.0: unicode-match-property-value-ecmascript@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz#cb5fffdcd16a05124f5a4b0bf7c3770208acbbe0" + resolved "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz" integrity sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA== unicode-property-aliases-ecmascript@^2.0.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz#43d41e3be698bd493ef911077c9b131f827e8ccd" + resolved "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz" integrity sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w== update-browserslist-db@^1.0.13: version "1.0.13" - resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz#3c5e4f5c083661bd38ef64b6328c26ed6c8248c4" + resolved "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz" integrity sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg== dependencies: escalade "^3.1.1" @@ -1548,10 +1548,10 @@ update-browserslist-db@^1.0.13: wrappy@1: version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== yallist@^3.0.2: version "3.1.1" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" + resolved "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz" integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index b9c8c05..198dab0 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -4,18 +4,18 @@ version = 3 [[package]] name = "addr2line" -version = "0.22.0" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" dependencies = [ "gimli", ] [[package]] -name = "adler" -version = "1.0.2" +name = "adler2" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" [[package]] name = "aead" @@ -64,6 +64,19 @@ dependencies = [ "subtle", ] +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "const-random", + "once_cell", + "version_check", + "zerocopy", +] + [[package]] name = "aho-corasick" version = "1.1.3" @@ -105,19 +118,19 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.86" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" +checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04" [[package]] name = "arboard" -version = "3.4.0" +version = "3.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb4009533e8ff8f1450a5bcbc30f4242a1d34442221f72314bea1f5dc9c7f89" +checksum = "df099ccb16cd014ff054ac1bf392c67feeef57164b05c42f037cd40f5d4357f4" dependencies = [ "clipboard-win", "core-graphics 0.23.2", - "image 0.25.2", + "image 0.25.5", "log", "objc2", "objc2-app-kit", @@ -144,6 +157,17 @@ dependencies = [ "libc", ] +[[package]] +name = "async-trait" +version = "0.1.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b1244b10dcd56c92219da4e14caa97e312079e185f04ba3eea25061561dc0a0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.94", +] + [[package]] name = "atk" version = "0.15.1" @@ -170,25 +194,31 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "backtrace" -version = "0.3.73" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" dependencies = [ "addr2line", - "cc", "cfg-if", "libc", "miniz_oxide", "object", "rustc-demangle", + "windows-targets 0.52.6", ] +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + [[package]] name = "base64" version = "0.13.1" @@ -207,6 +237,23 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + +[[package]] +name = "bcrypt-pbkdf" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6aeac2e1fe888769f34f05ac343bbef98b14d1ffb292ab69d4608b3abc86f2a2" +dependencies = [ + "blowfish", + "pbkdf2 0.12.2", + "sha2", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -218,6 +265,9 @@ name = "bitflags" version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +dependencies = [ + "serde", +] [[package]] name = "block" @@ -240,7 +290,7 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2cb03d1bed155d89dce0f845b7899b18a9a163e148fd004e1c28421a783e2d8e" dependencies = [ - "block-padding", + "block-padding 0.2.1", "cipher 0.3.0", ] @@ -250,6 +300,15 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" +[[package]] +name = "block-padding" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93" +dependencies = [ + "generic-array", +] + [[package]] name = "block2" version = "0.5.1" @@ -259,6 +318,16 @@ dependencies = [ "objc2", ] +[[package]] +name = "blowfish" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e412e2cd0f2b2d93e02543ceae7917b3c70331573df19ee046bcbc35e45e87d7" +dependencies = [ + "byteorder", + "cipher 0.4.4", +] + [[package]] name = "botan" version = "0.10.7" @@ -285,9 +354,9 @@ dependencies = [ [[package]] name = "brotli" -version = "3.5.0" +version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d640d25bc63c50fb1f0b545ffd80207d2e10a4c965530809b40ba3386825c391" +checksum = "74f7971dbd9326d58187408ab83117d8ac1bb9c17b085fdacd1cf2f598719b6b" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -296,9 +365,9 @@ dependencies = [ [[package]] name = "brotli-decompressor" -version = "2.5.1" +version = "4.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e2e4afe60d7dd600fdd3de8d0f08c2b7ec039712e3b6137ff98b7004e82de4f" +checksum = "9a45bd2e4095a8b518033b128020dd4a55aab1c0a381ba4404a472630f4bc362" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -306,9 +375,9 @@ dependencies = [ [[package]] name = "bstr" -version = "1.10.0" +version = "1.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40723b8fb387abc38f4f4a37c09073622e41dd12327033091ef8950659e6dc0c" +checksum = "531a9155a481e2ee699d4f98f43c0ca4ff8ee1bfd55c31e9e98fb29d2b176fe0" dependencies = [ "memchr", "serde", @@ -322,9 +391,9 @@ checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "bytemuck" -version = "1.16.3" +version = "1.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "102087e286b4677862ea56cf8fc58bb2cdfa8725c40ffb80fe3a008eb7f2fc83" +checksum = "ef657dfab802224e671f5818e9a4935f9b1957ed18e58292690cc39e7a4092a3" [[package]] name = "byteorder" @@ -340,9 +409,9 @@ checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" [[package]] name = "bytes" -version = "1.7.1" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" +checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" [[package]] name = "cairo-rs" @@ -354,7 +423,7 @@ dependencies = [ "cairo-sys-rs", "glib", "libc", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -378,14 +447,24 @@ dependencies = [ "toml 0.7.8", ] +[[package]] +name = "cbc" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b52a9543ae338f279b96b0b9fed9c8093744685043739079ce85cd58f289a6" +dependencies = [ + "cipher 0.4.4", +] + [[package]] name = "cc" -version = "1.1.7" +version = "1.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26a5c3fd7bfa1ce3897a3a3501d362b2d87b7f2583ebcb4a949ec25911025cbc" +checksum = "a012a0df96dd6d06ba9a1b29d6402d1a5d77c6befd2566afdc26e10603dc93d7" dependencies = [ "jobserver", "libc", + "shlex", ] [[package]] @@ -436,6 +515,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + [[package]] name = "chacha20" version = "0.7.3" @@ -447,11 +532,22 @@ dependencies = [ "cpufeatures", ] +[[package]] +name = "chacha20" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818" +dependencies = [ + "cfg-if", + "cipher 0.4.4", + "cpufeatures", +] + [[package]] name = "chrono" -version = "0.4.38" +version = "0.4.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825" dependencies = [ "android-tzdata", "iana-time-zone", @@ -558,6 +654,32 @@ dependencies = [ "memchr", ] +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "const-random" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359" +dependencies = [ + "const-random-macro", +] + +[[package]] +name = "const-random-macro" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" +dependencies = [ + "getrandom 0.2.15", + "once_cell", + "tiny-keccak", +] + [[package]] name = "convert_case" version = "0.4.0" @@ -576,9 +698,9 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "core-graphics" @@ -619,9 +741,9 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.12" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3" dependencies = [ "libc", ] @@ -637,18 +759,18 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.13" +version = "0.5.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" +checksum = "06ba6d68e24814cb8de6bb986db8222d3a027d15872cabc0d18817bc3c0e4471" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-deque" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" dependencies = [ "crossbeam-epoch", "crossbeam-utils", @@ -665,9 +787,27 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.20" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "crypto-bigint" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "subtle", + "zeroize", +] [[package]] name = "crypto-common" @@ -704,17 +844,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" dependencies = [ "quote", - "syn 2.0.72", + "syn 2.0.94", ] [[package]] name = "ctor" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edb49164822f3ee45b17acd4a208cfc1251410cf0cad9a833234c9890774dd9f" +checksum = "32a2785755761f3ddc1492979ce1e48d2c00d09311c39e4466429188f3dd6501" dependencies = [ "quote", - "syn 2.0.72", + "syn 2.0.94", ] [[package]] @@ -726,6 +866,33 @@ dependencies = [ "cipher 0.4.4", ] +[[package]] +name = "curve25519-dalek" +version = "4.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" +dependencies = [ + "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", + "digest", + "fiat-crypto", + "rustc_version", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.94", +] + [[package]] name = "darling" version = "0.20.10" @@ -747,7 +914,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.72", + "syn 2.0.94", ] [[package]] @@ -758,7 +925,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn 2.0.72", + "syn 2.0.94", ] [[package]] @@ -767,6 +934,17 @@ version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" +[[package]] +name = "der" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" +dependencies = [ + "const-oid", + "pem-rfc7468", + "zeroize", +] + [[package]] name = "deranged" version = "0.3.11" @@ -796,7 +974,7 @@ checksum = "d150dea618e920167e5973d70ae6ece4385b7164e0d799fe7c122dd0a5d912ad" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.94", ] [[package]] @@ -809,7 +987,16 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn 2.0.72", + "syn 2.0.94", +] + +[[package]] +name = "des" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffdd80ce8ce993de27e9f063a444a4d53ce8e8db4c1f00cc03af5ad5a9867a1e" +dependencies = [ + "cipher 0.4.4", ] [[package]] @@ -825,10 +1012,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", + "const-oid", "crypto-common", "subtle", ] +[[package]] +name = "digest_auth" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3054f4e81d395e50822796c5e99ca522e6ba7be98947d6d4b0e5e61640bdb894" +dependencies = [ + "digest", + "hex", + "md-5", + "rand 0.8.5", + "sha2", +] + [[package]] name = "dirs-next" version = "2.0.0" @@ -856,6 +1057,17 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.94", +] + [[package]] name = "dlib" version = "0.5.2" @@ -888,15 +1100,75 @@ dependencies = [ [[package]] name = "dunce" -version = "1.0.4" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der", + "digest", + "elliptic-curve", + "rfc6979", + "signature", + "spki", +] + +[[package]] +name = "ed25519" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" +dependencies = [ + "pkcs8", + "signature", +] + +[[package]] +name = "ed25519-dalek" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" +dependencies = [ + "curve25519-dalek", + "ed25519", + "rand_core 0.6.4", + "serde", + "sha2", + "subtle", + "zeroize", +] + +[[package]] +name = "elliptic-curve" +version = "0.13.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest", + "ff", + "generic-array", + "group", + "hkdf", + "pem-rfc7468", + "pkcs8", + "rand_core 0.6.4", + "sec1", + "subtle", + "zeroize", +] [[package]] name = "embed-resource" -version = "2.4.3" +version = "2.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4edcacde9351c33139a41e3c97eb2334351a81a2791bebb0b243df837128f602" +checksum = "b68b6f9f63a0b6a38bc447d4ce84e2b388f3ec95c99c641c8ff0dd3ef89a6379" dependencies = [ "cc", "memchr", @@ -914,13 +1186,25 @@ checksum = "4ef6b89e5b37196644d8796de5268852ff179b44e96276cf4290264843743bb7" [[package]] name = "encoding_rs" -version = "0.8.34" +version = "0.8.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" dependencies = [ "cfg-if", ] +[[package]] +name = "enum_dispatch" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa18ce2bc66555b3218614519ac839ddb759a7d6720732f979ef8d13be147ecd" +dependencies = [ + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.94", +] + [[package]] name = "equivalent" version = "1.0.1" @@ -929,35 +1213,51 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.9" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "error-code" -version = "3.2.0" +version = "3.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0474425d51df81997e2f90a21591180b38eccf27292d755f3e30750225c175b" +checksum = "a5d9305ccc6942a704f4335694ecd3de2ea531b114ac2d51f5f843750787a92f" [[package]] name = "fastrand" -version = "2.1.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "fdeflate" -version = "0.3.4" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f9bfee30e4dedf0ab8b422f03af778d9612b63f502710fc500a334ebe2de645" +checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c" dependencies = [ "simd-adler32", ] +[[package]] +name = "ff" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +dependencies = [ + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "fiat-crypto" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" + [[package]] name = "field-offset" version = "0.3.6" @@ -970,14 +1270,14 @@ dependencies = [ [[package]] name = "filetime" -version = "0.2.23" +version = "0.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" +checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.4.1", - "windows-sys 0.52.0", + "libredox", + "windows-sys 0.59.0", ] [[package]] @@ -988,15 +1288,36 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" [[package]] name = "flate2" -version = "1.0.30" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" +checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" dependencies = [ "crc32fast", "libz-sys", "miniz_oxide", ] +[[package]] +name = "fluent-uri" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17c704e9dbe1ddd863da1e6ff3567795087b1eb201ce80d8fa81162e1516500d" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "flurry" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf5efcf77a4da27927d3ab0509dec5b0954bb3bc59da5a1de9e52642ebd4cdf9" +dependencies = [ + "ahash", + "num_cpus", + "parking_lot", + "seize", +] + [[package]] name = "fnv" version = "1.0.7" @@ -1030,7 +1351,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.94", ] [[package]] @@ -1064,26 +1385,42 @@ dependencies = [ "new_debug_unreachable", ] +[[package]] +name = "futures" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + [[package]] name = "futures-channel" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", + "futures-sink", ] [[package]] name = "futures-core" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-executor" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" dependencies = [ "futures-core", "futures-task", @@ -1092,36 +1429,46 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-macro" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.94", ] +[[package]] +name = "futures-sink" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" + [[package]] name = "futures-task" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] name = "futures-util" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ + "futures-channel", "futures-core", + "futures-io", "futures-macro", + "futures-sink", "futures-task", + "memchr", "pin-project-lite", "pin-utils", "slab", @@ -1243,6 +1590,7 @@ checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", + "zeroize", ] [[package]] @@ -1273,8 +1621,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", + "js-sys", "libc", "wasi 0.11.0+wasi-snapshot-preview1", + "wasm-bindgen", ] [[package]] @@ -1289,9 +1639,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.29.0" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" [[package]] name = "gio" @@ -1307,7 +1657,7 @@ dependencies = [ "glib", "libc", "once_cell", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -1340,7 +1690,7 @@ dependencies = [ "libc", "once_cell", "smallvec", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -1370,21 +1720,21 @@ dependencies = [ [[package]] name = "glob" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" +checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" [[package]] name = "globset" -version = "0.4.14" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57da3b9b5b85bd66f31093f8c408b90a74431672542466497dcbdfdc02034be1" +checksum = "15f1ce686646e7f1e19bf7d5533fe443a45dbfb990e00629110797578b42fb19" dependencies = [ "aho-corasick", "bstr", "log", - "regex-automata 0.4.7", - "regex-syntax 0.8.4", + "regex-automata 0.4.9", + "regex-syntax 0.8.5", ] [[package]] @@ -1398,6 +1748,17 @@ dependencies = [ "system-deps 6.2.2", ] +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core 0.6.4", + "subtle", +] + [[package]] name = "gtk" version = "0.15.5" @@ -1461,9 +1822,9 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "hashbrown" -version = "0.14.5" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" [[package]] name = "heck" @@ -1486,6 +1847,12 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + [[package]] name = "hex" version = "0.4.3" @@ -1498,6 +1865,21 @@ version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ebdb29d2ea9ed0083cd8cece49bbd968021bd99b0849edb4a9a7ee0fdf6a4e0" +[[package]] +name = "hex-literal" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" + +[[package]] +name = "hkdf" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" +dependencies = [ + "hmac", +] + [[package]] name = "hmac" version = "0.12.1" @@ -1509,11 +1891,11 @@ dependencies = [ [[package]] name = "home" -version = "0.5.9" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -1538,7 +1920,41 @@ checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" dependencies = [ "bytes", "fnv", - "itoa 1.0.11", + "itoa 1.0.14", +] + +[[package]] +name = "http" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea" +dependencies = [ + "bytes", + "fnv", + "itoa 1.0.14", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http 1.2.0", +] + +[[package]] +name = "http-body-util" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" +dependencies = [ + "bytes", + "futures-util", + "http 1.2.0", + "http-body", + "pin-project-lite", ] [[package]] @@ -1547,17 +1963,85 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "21dec9db110f5f872ed9699c3ecf50cf16f423502706ba5c72462e28d3157573" +[[package]] +name = "httparse" +version = "1.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + [[package]] name = "humantime" version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" +[[package]] +name = "hyper" +version = "1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "256fb8d4bd6413123cc9d91832d78325c48ff41677595be797d90f42969beae0" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http 1.2.0", + "http-body", + "httparse", + "itoa 1.0.14", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2" +dependencies = [ + "futures-util", + "http 1.2.0", + "hyper", + "hyper-util", + "rustls", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tower-service", + "webpki-roots", +] + +[[package]] +name = "hyper-util" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http 1.2.0", + "http-body", + "hyper", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", +] + [[package]] name = "iana-time-zone" -version = "0.1.60" +version = "0.1.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -1586,6 +2070,124 @@ dependencies = [ "png", ] +[[package]] +name = "icu_collections" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locid" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_locid_transform" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_locid_transform_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locid_transform_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" + +[[package]] +name = "icu_normalizer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" + +[[package]] +name = "icu_properties" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" + +[[package]] +name = "icu_provider" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_provider_macros", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_provider_macros" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.94", +] + [[package]] name = "ident_case" version = "1.0.1" @@ -1594,25 +2196,36 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "idna" -version = "0.5.0" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" dependencies = [ - "unicode-bidi", - "unicode-normalization", + "icu_normalizer", + "icu_properties", ] [[package]] name = "ignore" -version = "0.4.22" +version = "0.4.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b46810df39e66e925525d6e38ce1e7f6e1d208f72dc39757880fcb66e2c58af1" +checksum = "6d89fd380afde86567dfba715db065673989d6253f42b88179abd3eae47bda4b" dependencies = [ "crossbeam-deque", "globset", "log", "memchr", - "regex-automata 0.4.7", + "regex-automata 0.4.9", "same-file", "walkdir", "winapi-util", @@ -1632,9 +2245,9 @@ dependencies = [ [[package]] name = "image" -version = "0.25.2" +version = "0.25.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99314c8a2152b8ddb211f924cdae532d8c5e4c8bb54728e12fff1b0cd5963a10" +checksum = "cd6f44aed642f18953a158afeb30206f4d50da59fbc66ecb53c66488de73563b" dependencies = [ "bytemuck", "byteorder-lite", @@ -1656,12 +2269,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.3.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3fc2e30ba82dd1b3911c8de1ffc143c74a914a14e99514d7637e3099df5ea0" +checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" dependencies = [ "equivalent", - "hashbrown 0.14.5", + "hashbrown 0.15.2", "serde", ] @@ -1680,6 +2293,7 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" dependencies = [ + "block-padding 0.3.3", "generic-array", ] @@ -1692,6 +2306,12 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "ipnet" +version = "2.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" + [[package]] name = "itoa" version = "0.4.8" @@ -1700,9 +2320,9 @@ checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" [[package]] name = "itoa" -version = "1.0.11" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" [[package]] name = "javascriptcore-rs" @@ -1737,7 +2357,7 @@ dependencies = [ "combine", "jni-sys", "log", - "thiserror", + "thiserror 1.0.69", "walkdir", ] @@ -1764,22 +2384,35 @@ checksum = "f5d4a7da358eff58addd2877a45865158f0d78c911d43a5784ceb7bbf52833b0" [[package]] name = "js-sys" -version = "0.3.69" +version = "0.3.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +checksum = "6717b6b5b077764fb5966237269cb3c64edddde4b14ce42647430a78ced9e7b7" dependencies = [ + "once_cell", "wasm-bindgen", ] [[package]] name = "json-patch" -version = "1.4.0" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b1fb8864823fad91877e6caea0baca82e49e8db50f8e5c9f9a453e27d3330fc" +dependencies = [ + "jsonptr", + "serde", + "serde_json", + "thiserror 1.0.69", +] + +[[package]] +name = "jsonptr" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec9ad60d674508f3ca8f380a928cfe7b096bc729c4e2dbfe3852bc45da3ab30b" +checksum = "1c6e529149475ca0b2820835d3dce8fcc41c6b943ca608d32f35b449255e4627" dependencies = [ + "fluent-uri", "serde", "serde_json", - "thiserror", ] [[package]] @@ -1800,23 +2433,32 @@ name = "lazy_static" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +dependencies = [ + "spin", +] [[package]] name = "libc" -version = "0.2.155" +version = "0.2.169" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" [[package]] name = "libloading" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" +checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" dependencies = [ "cfg-if", "windows-targets 0.52.6", ] +[[package]] +name = "libm" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" + [[package]] name = "libredox" version = "0.1.3" @@ -1825,13 +2467,14 @@ checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ "bitflags 2.6.0", "libc", + "redox_syscall", ] [[package]] name = "libz-sys" -version = "1.1.18" +version = "1.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c15da26e5af7e25c90b37a2d75cdbf940cf4a55316de9d84c679c9b8bfabf82e" +checksum = "d2d16453e800a8cf6dd2fc3eb4bc99b786a9b90c663b8559a5b1a041bf89e472" dependencies = [ "cc", "pkg-config", @@ -1844,6 +2487,12 @@ version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +[[package]] +name = "litemap" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" + [[package]] name = "lock_api" version = "0.4.12" @@ -1891,7 +2540,7 @@ dependencies = [ "serde-value", "serde_json", "serde_yaml", - "thiserror", + "thiserror 1.0.69", "thread-id", "typemap-ors", "winapi", @@ -1956,6 +2605,22 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" +[[package]] +name = "md-5" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" +dependencies = [ + "cfg-if", + "digest", +] + +[[package]] +name = "md5" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771" + [[package]] name = "memchr" version = "2.7.4" @@ -1971,6 +2636,12 @@ dependencies = [ "autocfg", ] +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + [[package]] name = "minimal-lexical" version = "0.2.1" @@ -1979,14 +2650,25 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.7.4" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" +checksum = "4ffbe83022cedc1d264172192511ae958937694cd57ce297164951b8b3568394" dependencies = [ - "adler", + "adler2", "simd-adler32", ] +[[package]] +name = "mio" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" +dependencies = [ + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys 0.52.0", +] + [[package]] name = "ndk" version = "0.6.0" @@ -1997,7 +2679,7 @@ dependencies = [ "jni-sys", "ndk-sys", "num_enum", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -2029,7 +2711,7 @@ checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4" dependencies = [ "bitflags 2.6.0", "cfg-if", - "cfg_aliases", + "cfg_aliases 0.1.1", "libc", ] @@ -2059,12 +2741,60 @@ dependencies = [ "winapi", ] +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", + "rand 0.8.5", +] + +[[package]] +name = "num-bigint-dig" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" +dependencies = [ + "byteorder", + "lazy_static", + "libm", + "num-integer", + "num-iter", + "num-traits", + "rand 0.8.5", + "smallvec", + "zeroize", +] + [[package]] name = "num-conv" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.19" @@ -2072,6 +2802,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", + "libm", +] + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi", + "libc", ] [[package]] @@ -2235,39 +2976,41 @@ dependencies = [ [[package]] name = "object" -version = "0.36.2" +version = "0.36.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f203fa8daa7bb185f760ae12bd8e097f63d17041dcdcaf675ac54cdf863170e" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.19.0" +version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "onekeepass-core" -version = "0.15.0" -source = "git+https://github.com/OneKeePass/onekeepass-core.git?tag=v0.15.0#e2563327c783d3ea66e4a6b5c5f26acfc249574f" +version = "0.16.0" +source = "git+https://github.com/OneKeePass/onekeepass-core.git?tag=v0.16.0#54298e1f21d41381037c9b62a4079c3f7be8b8e2" dependencies = [ "aes 0.7.5", "aes-gcm", "argon2-sys", + "async-trait", "base64 0.21.7", "block-modes", "botan", "cfg-if", - "chacha20", + "chacha20 0.7.3", "chrono", "chrono-tz", "cipher 0.3.0", "data-encoding", + "enum_dispatch", "flate2", "hex", - "hex-literal", + "hex-literal 0.3.4", "hmac", "lazy_static", "log", @@ -2277,14 +3020,18 @@ dependencies = [ "rand 0.8.5", "rand_chacha 0.3.1", "regex", + "reqwest_dav", "rmp-serde", + "russh", + "russh-keys", + "russh-sftp", "secstr", "serde", "serde_json", "sha1", "sha2", "slice_as_array", - "thiserror", + "thiserror 1.0.69", "tokio", "url", "urlencoding", @@ -2343,9 +3090,9 @@ dependencies = [ [[package]] name = "os_info" -version = "3.8.2" +version = "3.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae99c7fa6dd38c7cafe1ec085e804f8f555a2f8659b0dbe03f1f9963a9b51092" +checksum = "eb6651f4be5e39563c4fe5cc8326349eb99a25d805a3493f791d5bfd0269e430" dependencies = [ "log", "serde", @@ -2369,14 +3116,52 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" [[package]] -name = "pango" -version = "0.15.10" +name = "p256" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22e4045548659aee5313bde6c582b0d83a627b7904dd20dc2d9ef0895d414e4f" +checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" dependencies = [ - "bitflags 1.3.2", - "glib", - "libc", + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2", +] + +[[package]] +name = "p384" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70786f51bcc69f6a4c0360e063a4cac5419ef7c5cd5b3c99ad70f3be5ba79209" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2", +] + +[[package]] +name = "p521" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fc9e2161f1f215afdfce23677034ae137bbd45016a880c2eb3ba8eb95f085b2" +dependencies = [ + "base16ct", + "ecdsa", + "elliptic-curve", + "primeorder", + "rand_core 0.6.4", + "sha2", +] + +[[package]] +name = "pango" +version = "0.15.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e4045548659aee5313bde6c582b0d83a627b7904dd20dc2d9ef0895d414e4f" +dependencies = [ + "bitflags 1.3.2", + "glib", + "libc", "once_cell", "pango-sys", ] @@ -2411,7 +3196,7 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.5.3", + "redox_syscall", "smallvec", "windows-targets 0.52.6", ] @@ -2425,6 +3210,17 @@ dependencies = [ "regex", ] +[[package]] +name = "password-hash" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700" +dependencies = [ + "base64ct", + "rand_core 0.6.4", + "subtle", +] + [[package]] name = "passwords" version = "3.1.16" @@ -2442,9 +3238,40 @@ checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] name = "pathdiff" -version = "0.2.1" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" + +[[package]] +name = "pbkdf2" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" +checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +dependencies = [ + "digest", + "hmac", + "password-hash", + "sha2", +] + +[[package]] +name = "pbkdf2" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" +dependencies = [ + "digest", + "hmac", +] + +[[package]] +name = "pem-rfc7468" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] [[package]] name = "percent-encoding" @@ -2459,7 +3286,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" dependencies = [ "fixedbitset", - "indexmap 2.3.0", + "indexmap 2.7.0", ] [[package]] @@ -2576,7 +3403,7 @@ dependencies = [ "phf_shared 0.11.2", "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.94", ] [[package]] @@ -2608,9 +3435,9 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" +checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" [[package]] name = "pin-utils" @@ -2618,11 +3445,49 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "pkcs1" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" +dependencies = [ + "der", + "pkcs8", + "spki", +] + +[[package]] +name = "pkcs5" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e847e2c91a18bfa887dd028ec33f2fe6f25db77db3619024764914affe8b69a6" +dependencies = [ + "aes 0.8.4", + "cbc", + "der", + "pbkdf2 0.12.2", + "scrypt", + "sha2", + "spki", +] + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "pkcs5", + "rand_core 0.6.4", + "spki", +] + [[package]] name = "pkg-config" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" [[package]] name = "plist" @@ -2631,7 +3496,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42cf17e9a1800f5f396bc67d193dc9411b59012a5876445ef450d449881e1016" dependencies = [ "base64 0.22.1", - "indexmap 2.3.0", + "indexmap 2.7.0", "quick-xml 0.32.0", "serde", "time", @@ -2639,9 +3504,9 @@ dependencies = [ [[package]] name = "png" -version = "0.17.13" +version = "0.17.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06e4b0d3d1312775e782c86c91a111aa1f910cbb65e1337f9975b5f9a554b5e1" +checksum = "82151a2fc869e011c153adc57cf2789ccb8d9906ce52c0b39a6b5697749d7526" dependencies = [ "bitflags 1.3.2", "crc32fast", @@ -2650,6 +3515,17 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "poly1305" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" +dependencies = [ + "cpufeatures", + "opaque-debug", + "universal-hash", +] + [[package]] name = "polyval" version = "0.6.2" @@ -2670,9 +3546,9 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" -version = "0.2.18" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dee4364d9f3b902ef14fab8a1ddffb783a1cb6b4bba3bfc1fa3922732c7de97f" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" dependencies = [ "zerocopy", ] @@ -2683,6 +3559,15 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" +[[package]] +name = "primeorder" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" +dependencies = [ + "elliptic-curve", +] + [[package]] name = "proc-macro-crate" version = "1.3.1" @@ -2725,9 +3610,9 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" [[package]] name = "proc-macro2" -version = "1.0.86" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" dependencies = [ "unicode-ident", ] @@ -2752,18 +3637,70 @@ dependencies = [ [[package]] name = "quick-xml" -version = "0.34.0" +version = "0.36.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f24d770aeca0eacb81ac29dfbc55ebcc09312fdd1f8bbecdc7e4a84e000e3b4" +checksum = "f7649a7b4df05aed9ea7ec6f628c67c9953a43869b8bc50929569b2999d443fe" dependencies = [ "memchr", ] +[[package]] +name = "quinn" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62e96808277ec6f97351a2380e6c25114bc9e67037775464979f3037c92d05ef" +dependencies = [ + "bytes", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash", + "rustls", + "socket2", + "thiserror 2.0.9", + "tokio", + "tracing", +] + +[[package]] +name = "quinn-proto" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2fe5ef3495d7d2e377ff17b1a8ce2ee2ec2a18cde8b6ad6619d65d0701c135d" +dependencies = [ + "bytes", + "getrandom 0.2.15", + "rand 0.8.5", + "ring", + "rustc-hash", + "rustls", + "rustls-pki-types", + "slab", + "thiserror 2.0.9", + "tinyvec", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-udp" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c40286217b4ba3a71d644d752e6a0b71f13f1b6a2c5311acfcbe0c2418ed904" +dependencies = [ + "cfg_aliases 0.2.1", + "libc", + "once_cell", + "socket2", + "tracing", + "windows-sys 0.59.0", +] + [[package]] name = "quote" -version = "1.0.36" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" dependencies = [ "proc-macro2", ] @@ -2851,9 +3788,9 @@ dependencies = [ [[package]] name = "random-number" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a3da5cbb4c27c5150c03a54a7e4745437cd90f9e329ae657c0b889a144bb7be" +checksum = "7fc8cdd49be664772ffc3dbfa743bb8c34b78f9cc6a9f50e56ae878546796067" dependencies = [ "proc-macro-hack", "rand 0.8.5", @@ -2862,13 +3799,13 @@ dependencies = [ [[package]] name = "random-number-macro-impl" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b86292cf41ccfc96c5de7165c1c53d5b4ac540c5bab9d1857acbe9eba5f1a0b" +checksum = "f5135143cb48d14289139e4615bffec0d59b4cbfd4ea2398a3770bd2abfc4aa2" dependencies = [ "proc-macro-hack", "quote", - "syn 2.0.72", + "syn 2.0.94", ] [[package]] @@ -2888,43 +3825,34 @@ checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9" [[package]] name = "redox_syscall" -version = "0.4.1" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" -dependencies = [ - "bitflags 1.3.2", -] - -[[package]] -name = "redox_syscall" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" +checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" dependencies = [ "bitflags 2.6.0", ] [[package]] name = "redox_users" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ "getrandom 0.2.15", "libredox", - "thiserror", + "thiserror 1.0.69", ] [[package]] name = "regex" -version = "1.10.6" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.7", - "regex-syntax 0.8.4", + "regex-automata 0.4.9", + "regex-syntax 0.8.5", ] [[package]] @@ -2938,13 +3866,13 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.7" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.4", + "regex-syntax 0.8.5", ] [[package]] @@ -2955,9 +3883,82 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.8.4" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "reqwest" +version = "0.12.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43e734407157c3c2034e0258f5e4473ddb361b1e85f95a66690d67264d7cd1da" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures-core", + "futures-util", + "http 1.2.0", + "http-body", + "http-body-util", + "hyper", + "hyper-rustls", + "hyper-util", + "ipnet", + "js-sys", + "log", + "mime", + "once_cell", + "percent-encoding", + "pin-project-lite", + "quinn", + "rustls", + "rustls-pemfile", + "rustls-pki-types", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tokio-rustls", + "tower", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "webpki-roots", + "windows-registry", +] + +[[package]] +name = "reqwest_dav" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" +checksum = "ea79cbb695b7cc877ae9c0f0eeb8468e36cd03dc9c41a93bcf237396357c7b42" +dependencies = [ + "async-trait", + "chrono", + "digest_auth", + "http 1.2.0", + "httpdate", + "reqwest", + "serde", + "serde-xml-rs", + "serde_derive", + "serde_json", + "tokio", + "url", +] + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] [[package]] name = "rfd" @@ -2983,6 +3984,21 @@ dependencies = [ "windows 0.37.0", ] +[[package]] +name = "ring" +version = "0.17.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.15", + "libc", + "spin", + "untrusted", + "windows-sys 0.52.0", +] + [[package]] name = "rmp" version = "0.8.14" @@ -3005,39 +4021,231 @@ dependencies = [ "serde", ] +[[package]] +name = "rsa" +version = "0.9.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47c75d7c5c6b673e58bf54d8544a9f432e3a925b0e80f7cd3602ab5c50c55519" +dependencies = [ + "const-oid", + "digest", + "num-bigint-dig", + "num-integer", + "num-traits", + "pkcs1", + "pkcs8", + "rand_core 0.6.4", + "sha2", + "signature", + "spki", + "subtle", + "zeroize", +] + +[[package]] +name = "russh" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a229f2a03daea3f62cee897b40329ce548600cca615906d98d58b8db3029b19" +dependencies = [ + "aes 0.8.4", + "aes-gcm", + "async-trait", + "bitflags 2.6.0", + "byteorder", + "cbc", + "chacha20 0.9.1", + "ctr", + "curve25519-dalek", + "des", + "digest", + "elliptic-curve", + "flate2", + "futures", + "generic-array", + "hex-literal 0.4.1", + "hmac", + "log", + "num-bigint", + "once_cell", + "p256", + "p384", + "p521", + "poly1305", + "rand 0.8.5", + "rand_core 0.6.4", + "russh-cryptovec", + "russh-keys", + "sha1", + "sha2", + "ssh-encoding", + "ssh-key", + "subtle", + "thiserror 1.0.69", + "tokio", +] + +[[package]] +name = "russh-cryptovec" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fadd2c0ab350e21c66556f94ee06f766d8bdae3213857ba7610bfd8e10e51880" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "russh-keys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89757474f7c9ee30121d8cc7fe293a954ba10b204a82ccf5850a5352a532ebc7" +dependencies = [ + "aes 0.8.4", + "async-trait", + "bcrypt-pbkdf", + "block-padding 0.3.3", + "byteorder", + "cbc", + "ctr", + "data-encoding", + "der", + "digest", + "ecdsa", + "ed25519-dalek", + "elliptic-curve", + "futures", + "hmac", + "home", + "inout", + "log", + "md5", + "num-integer", + "p256", + "p384", + "p521", + "pbkdf2 0.11.0", + "pkcs1", + "pkcs5", + "pkcs8", + "rand 0.8.5", + "rand_core 0.6.4", + "rsa", + "russh-cryptovec", + "sec1", + "serde", + "sha1", + "sha2", + "spki", + "ssh-encoding", + "ssh-key", + "thiserror 1.0.69", + "tokio", + "tokio-stream", + "typenum", + "zeroize", +] + +[[package]] +name = "russh-sftp" +version = "2.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a72c8afe2041c17435eecd85d0b7291841486fd3d1c4082e0b212e5437ca42" +dependencies = [ + "async-trait", + "bitflags 2.6.0", + "bytes", + "chrono", + "flurry", + "log", + "serde", + "thiserror 1.0.69", + "tokio", + "tokio-util", +] + [[package]] name = "rustc-demangle" version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +[[package]] +name = "rustc-hash" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497" + [[package]] name = "rustc_version" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ "semver", ] [[package]] name = "rustix" -version = "0.38.34" +version = "0.38.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85" dependencies = [ "bitflags 2.6.0", "errno", "libc", "linux-raw-sys", - "windows-sys 0.52.0", + "windows-sys 0.59.0", +] + +[[package]] +name = "rustls" +version = "0.23.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5065c3f250cbd332cd894be57c40fa52387247659b14a2d6041d121547903b1b" +dependencies = [ + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-pemfile" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "rustls-pki-types" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2bf47e6ff922db3825eb750c4e2ff784c6ff8fb9e13046ef6a1d1c5401b0b37" +dependencies = [ + "web-time", +] + +[[package]] +name = "rustls-webpki" +version = "0.102.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", ] [[package]] name = "rustversion" -version = "1.0.17" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" +checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" [[package]] name = "ryu" @@ -3045,6 +4253,15 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +[[package]] +name = "salsa20" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213" +dependencies = [ + "cipher 0.4.4", +] + [[package]] name = "same-file" version = "1.0.6" @@ -3066,6 +4283,31 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "scrypt" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0516a385866c09368f0b5bcd1caff3366aace790fcd46e2bb032697bb172fd1f" +dependencies = [ + "pbkdf2 0.12.2", + "salsa20", + "sha2", +] + +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", +] + [[package]] name = "secstr" version = "0.5.1" @@ -3075,6 +4317,12 @@ dependencies = [ "libc", ] +[[package]] +name = "seize" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "689224d06523904ebcc9b482c6a3f4f7fb396096645c4cd10c0d2ff7371a34d3" + [[package]] name = "selectors" version = "0.22.0" @@ -3097,18 +4345,18 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.23" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" +checksum = "3cb6eb87a131f756572d7fb904f6e7b68633f09cca868c5df1c4b8d1a694bbba" dependencies = [ "serde", ] [[package]] name = "serde" -version = "1.0.204" +version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" +checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" dependencies = [ "serde_derive", ] @@ -3123,25 +4371,37 @@ dependencies = [ "serde", ] +[[package]] +name = "serde-xml-rs" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb3aa78ecda1ebc9ec9847d5d3aba7d618823446a049ba2491940506da6e2782" +dependencies = [ + "log", + "serde", + "thiserror 1.0.69", + "xml-rs", +] + [[package]] name = "serde_derive" -version = "1.0.204" +version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" +checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.94", ] [[package]] name = "serde_json" -version = "1.0.122" +version = "1.0.134" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784b6203951c57ff748476b126ccb5e8e2959a5c19e5c617ab1956be3dbc68da" +checksum = "d00f4175c42ee48b15416f6193a959ba3a0d67fc699a0db9ad12df9f83991c7d" dependencies = [ - "indexmap 2.3.0", - "itoa 1.0.11", + "indexmap 2.7.0", + "itoa 1.0.14", "memchr", "ryu", "serde", @@ -3155,29 +4415,41 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.94", ] [[package]] name = "serde_spanned" -version = "0.6.7" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d" +checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" dependencies = [ "serde", ] +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa 1.0.14", + "ryu", + "serde", +] + [[package]] name = "serde_with" -version = "3.9.0" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cecfa94848272156ea67b2b1a53f20fc7bc638c4a46d2f8abde08f05f4b857" +checksum = "d6b6f7f2fcb69f747921f79f3926bd1e203fce4fef62c268dd3abfb6d86029aa" dependencies = [ "base64 0.22.1", "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.3.0", + "indexmap 2.7.0", "serde", "serde_derive", "serde_json", @@ -3187,14 +4459,14 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.9.0" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8fee4991ef4f274617a51ad4af30519438dacb2f56ac773b08a1922ff743350" +checksum = "8d00caa5193a3c8362ac2b73be6b9e768aa5a4b2f721d8f4b339600c3cb51f8e" dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.94", ] [[package]] @@ -3203,8 +4475,8 @@ version = "0.9.34+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" dependencies = [ - "indexmap 2.3.0", - "itoa 1.0.11", + "indexmap 2.7.0", + "itoa 1.0.14", "ryu", "serde", "unsafe-libyaml", @@ -3212,9 +4484,9 @@ dependencies = [ [[package]] name = "serialize-to-javascript" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9823f2d3b6a81d98228151fdeaf848206a7855a7a042bbf9bf870449a66cafb" +checksum = "04f3666a07a197cdb77cdf306c32be9b7f598d7060d50cfd4d5aa04bfd92f6c5" dependencies = [ "serde", "serde_json", @@ -3223,13 +4495,13 @@ dependencies = [ [[package]] name = "serialize-to-javascript-impl" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74064874e9f6a15f04c1f3cb627902d0e6b410abbf36668afa873c61889f1763" +checksum = "772ee033c0916d670af7860b6e1ef7d658a4629a6d0b4c8c3e67f09b3765b75d" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.94", ] [[package]] @@ -3283,6 +4555,31 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signal-hook-registry" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +dependencies = [ + "libc", +] + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest", + "rand_core 0.6.4", +] + [[package]] name = "simd-adler32" version = "0.3.7" @@ -3316,6 +4613,16 @@ version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +[[package]] +name = "socket2" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + [[package]] name = "soup2" version = "0.2.1" @@ -3331,17 +4638,84 @@ dependencies = [ ] [[package]] -name = "soup2-sys" -version = "0.2.0" +name = "soup2-sys" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "009ef427103fcb17f802871647a7fa6c60cbb654b4c4e4c0ac60a31c5f6dc9cf" +dependencies = [ + "bitflags 1.3.2", + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "system-deps 5.0.0", +] + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "ssh-cipher" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caac132742f0d33c3af65bfcde7f6aa8f62f0e991d80db99149eb9d44708784f" +dependencies = [ + "aes 0.8.4", + "aes-gcm", + "cbc", + "chacha20 0.9.1", + "cipher 0.4.4", + "ctr", + "poly1305", + "ssh-encoding", + "subtle", +] + +[[package]] +name = "ssh-encoding" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb9242b9ef4108a78e8cd1a2c98e193ef372437f8c22be363075233321dd4a15" +dependencies = [ + "base64ct", + "pem-rfc7468", + "sha2", +] + +[[package]] +name = "ssh-key" +version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "009ef427103fcb17f802871647a7fa6c60cbb654b4c4e4c0ac60a31c5f6dc9cf" +checksum = "3b86f5297f0f04d08cabaa0f6bff7cb6aec4d9c3b49d87990d63da9d9156a8c3" dependencies = [ - "bitflags 1.3.2", - "gio-sys", - "glib-sys", - "gobject-sys", - "libc", - "system-deps 5.0.0", + "bcrypt-pbkdf", + "ed25519-dalek", + "num-bigint-dig", + "p256", + "p384", + "p521", + "rand_core 0.6.4", + "rsa", + "sec1", + "sha2", + "signature", + "ssh-cipher", + "ssh-encoding", + "subtle", + "zeroize", ] [[package]] @@ -3399,8 +4773,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "swift-rs" -version = "1.0.5" -source = "git+https://github.com/Brendonovich/swift-rs.git?rev=973c22215734d1d5b97c496601d658371e537ece#973c22215734d1d5b97c496601d658371e537ece" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4057c98e2e852d51fdcfca832aac7b571f6b351ad159f9eda5db1655f8d0c4d7" dependencies = [ "base64 0.21.7", "serde", @@ -3420,20 +4795,40 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.72" +version = "2.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af" +checksum = "987bc0be1cdea8b10216bd06e2ca407d40b9543468fafd3ddfb02f36e77f71f3" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] + +[[package]] +name = "synstructure" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.94", +] + [[package]] name = "sys-locale" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e801cf239ecd6ccd71f03d270d67dd53d13e90aab208bf4b8fe4ad957ea949b0" +checksum = "8eab9a99a024a169fe8a903cf9d4a3b3601109bcc13bd9e3c6fff259138626c4" dependencies = [ "libc", ] @@ -3466,9 +4861,9 @@ dependencies = [ [[package]] name = "tao" -version = "0.16.9" +version = "0.16.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "575c856fc21e551074869dcfaad8f706412bd5b803dfa0fbf6881c4ff4bfafab" +checksum = "48d298c441a1da46e28e8ad8ec205aab7fd8cd71b9d10e05454224eef422e1ae" dependencies = [ "bitflags 1.3.2", "cairo-rs", @@ -3513,20 +4908,20 @@ dependencies = [ [[package]] name = "tao-macros" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec114582505d158b669b136e6851f85840c109819d77c42bb7c0709f727d18c2" +checksum = "f4e16beb8b2ac17db28eab8bca40e62dbfbb34c0fcdc6d9826b11b7b5d047dfd" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.94", ] [[package]] name = "tar" -version = "0.4.41" +version = "0.4.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb797dad5fb5b76fcf519e702f4a589483b5ef06567f160c392832c1f5e44909" +checksum = "c65998313f8e17d0d553d28f91a0df93e4dbbbf770279c7bc21ca0f09ea1a1f6" dependencies = [ "filetime", "libc", @@ -3541,9 +4936,9 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" [[package]] name = "tauri" -version = "1.7.1" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "336bc661a3f3250853fa83c6e5245449ed1c26dce5dcb28bdee7efedf6278806" +checksum = "1bf327e247698d3f39af8aa99401c9708384290d1f5c544bf5d251d44c2fea22" dependencies = [ "anyhow", "cocoa", @@ -3558,13 +4953,15 @@ dependencies = [ "glob", "gtk", "heck 0.5.0", - "http", + "http 0.2.12", "ignore", + "log", "objc", "once_cell", "open", "os_pipe", "percent-encoding", + "plist", "rand 0.8.5", "raw-window-handle", "regex", @@ -3582,7 +4979,7 @@ dependencies = [ "tauri-runtime-wry", "tauri-utils", "tempfile", - "thiserror", + "thiserror 1.0.69", "tokio", "url", "uuid", @@ -3593,9 +4990,9 @@ dependencies = [ [[package]] name = "tauri-build" -version = "1.5.3" +version = "1.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c6ec7a5c3296330c7818478948b422967ce4649094696c985f61d50076d29c" +checksum = "586f3e677f940c8bb4f70c52eda05dc59b79e61543f1182de83516810bb8e35d" dependencies = [ "anyhow", "cargo_toml", @@ -3612,9 +5009,9 @@ dependencies = [ [[package]] name = "tauri-codegen" -version = "1.4.4" +version = "1.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1aed706708ff1200ec12de9cfbf2582b5d8ec05f6a7293911091effbd22036b" +checksum = "93a9e3f5cebf779a63bf24903e714ec91196c307d8249a0008b882424328bcda" dependencies = [ "base64 0.21.7", "brotli", @@ -3630,7 +5027,7 @@ dependencies = [ "serde_json", "sha2", "tauri-utils", - "thiserror", + "thiserror 1.0.69", "time", "uuid", "walkdir", @@ -3638,9 +5035,9 @@ dependencies = [ [[package]] name = "tauri-macros" -version = "1.4.5" +version = "1.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b88f831d2973ae4f81a706a0004e67dac87f2e4439973bbe98efbd73825d8ede" +checksum = "d1d0e989f54fe06c5ef0875c5e19cf96453d099a0a774d5192ab47e80471cdab" dependencies = [ "heck 0.5.0", "proc-macro2", @@ -3652,19 +5049,19 @@ dependencies = [ [[package]] name = "tauri-runtime" -version = "0.14.4" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3068ed62b63dedc705558f4248c7ecbd5561f0f8050949859ea0db2326f26012" +checksum = "f33fda7d213e239077fad52e96c6b734cecedb30c2382118b64f94cb5103ff3a" dependencies = [ "gtk", - "http", + "http 0.2.12", "http-range", "rand 0.8.5", "raw-window-handle", "serde", "serde_json", "tauri-utils", - "thiserror", + "thiserror 1.0.69", "url", "uuid", "webview2-com", @@ -3673,9 +5070,9 @@ dependencies = [ [[package]] name = "tauri-runtime-wry" -version = "0.14.9" +version = "0.14.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4c3db170233096aa30330feadcd895bf9317be97e624458560a20e814db7955" +checksum = "18c447dcd9b0f09c7dc4b752cc33e72788805bfd761fbda5692d30c48289efec" dependencies = [ "arboard", "cocoa", @@ -3694,9 +5091,9 @@ dependencies = [ [[package]] name = "tauri-utils" -version = "1.6.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2826db448309d382dac14d520f0c0a40839b87b57b977e59cf5f296b3ace6a93" +checksum = "83a0c939e88d82903a0a7dfb28388b12a3c03504d6bd6086550edaa3b6d8beaa" dependencies = [ "brotli", "ctor", @@ -3716,7 +5113,7 @@ dependencies = [ "serde", "serde_json", "serde_with", - "thiserror", + "thiserror 1.0.69", "url", "walkdir", "windows-version", @@ -3734,15 +5131,16 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.11.0" +version = "3.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8fcd239983515c23a32fb82099f97d0b11b8c72f654ed659363a95c3dad7a53" +checksum = "9a8a559c81686f576e8cd0290cd2a24a2a9ad80c98b3478856500fcbd7acd704" dependencies = [ "cfg-if", "fastrand", + "getrandom 0.2.15", "once_cell", "rustix", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -3764,22 +5162,42 @@ checksum = "8eaa81235c7058867fa8c0e7314f33dcce9c215f535d1913822a2b3f5e289f3c" [[package]] name = "thiserror" -version = "1.0.63" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f072643fd0190df67a8bab670c20ef5d8737177d6ac6b2e9a236cb096206b2cc" +dependencies = [ + "thiserror-impl 2.0.9", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ - "thiserror-impl", + "proc-macro2", + "quote", + "syn 2.0.94", ] [[package]] name = "thiserror-impl" -version = "1.0.63" +version = "2.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" +checksum = "7b50fa271071aae2e6ee85f842e2e28ba8cd2c5fb67f11fcb1fd70b276f9e7d4" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.94", ] [[package]] @@ -3815,12 +5233,12 @@ dependencies = [ [[package]] name = "time" -version = "0.3.36" +version = "0.3.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" +checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" dependencies = [ "deranged", - "itoa 1.0.11", + "itoa 1.0.14", "num-conv", "powerfmt", "serde", @@ -3836,19 +5254,38 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.18" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" +checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de" dependencies = [ "num-conv", "time-core", ] +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + +[[package]] +name = "tinystr" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +dependencies = [ + "displaydoc", + "zerovec", +] + [[package]] name = "tinyvec" -version = "1.8.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" +checksum = "022db8904dfa342efe721985167e9fcd16c29b226db4397ed752a761cfce81e8" dependencies = [ "tinyvec_macros", ] @@ -3861,13 +5298,64 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.39.2" +version = "1.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daa4fb1bc778bd6f04cbfc4bb2d06a7396a8f299dc33ea1900cedaa316f467b1" +checksum = "5cec9b21b0450273377fc97bd4c33a8acffc8c996c987a7c5b319a0083707551" dependencies = [ "backtrace", "bytes", + "libc", + "mio", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys 0.52.0", +] + +[[package]] +name = "tokio-macros" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.94", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f6d0975eaace0cf0fcadee4e4aaa5da15b5c079146f2cffb67c113be122bf37" +dependencies = [ + "rustls", + "tokio", +] + +[[package]] +name = "tokio-stream" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", "pin-project-lite", + "tokio", ] [[package]] @@ -3900,7 +5388,7 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit 0.22.20", + "toml_edit 0.22.22", ] [[package]] @@ -3918,7 +5406,7 @@ version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.3.0", + "indexmap 2.7.0", "serde", "serde_spanned", "toml_datetime", @@ -3927,22 +5415,49 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.22.20" +version = "0.22.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d" +checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" dependencies = [ - "indexmap 2.3.0", + "indexmap 2.7.0", "serde", "serde_spanned", "toml_datetime", - "winnow 0.6.18", + "winnow 0.6.22", +] + +[[package]] +name = "tower" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper", + "tokio", + "tower-layer", + "tower-service", ] +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + [[package]] name = "tracing" -version = "0.1.40" +version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" dependencies = [ "pin-project-lite", "tracing-attributes", @@ -3951,20 +5466,20 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.27" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.94", ] [[package]] name = "tracing-core" -version = "0.1.32" +version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" dependencies = [ "once_cell", "valuable", @@ -3983,9 +5498,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.18" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" dependencies = [ "matchers", "nu-ansi-term", @@ -4001,18 +5516,23 @@ dependencies = [ [[package]] name = "tree_magic_mini" -version = "3.1.5" +version = "3.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "469a727cac55b41448315cc10427c069c618ac59bb6a4480283fcd811749bdc2" +checksum = "aac5e8971f245c3389a5a76e648bfc80803ae066a1243a75db0064d7c1129d63" dependencies = [ "fnv", - "home", "memchr", "nom", "once_cell", "petgraph", ] +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + [[package]] name = "typemap-ors" version = "1.0.0" @@ -4028,32 +5548,17 @@ version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" -[[package]] -name = "unicode-bidi" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" - [[package]] name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "unicode-normalization" -version = "0.1.23" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" -dependencies = [ - "tinyvec", -] +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" [[package]] name = "unicode-segmentation" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" [[package]] name = "universal-hash" @@ -4080,11 +5585,17 @@ version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + [[package]] name = "url" -version = "2.5.2" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" dependencies = [ "form_urlencoded", "idna", @@ -4104,11 +5615,23 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" +[[package]] +name = "utf16_iter" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + [[package]] name = "uuid" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" +checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" dependencies = [ "getrandom 0.2.15", "serde", @@ -4117,13 +5640,13 @@ dependencies = [ [[package]] name = "uuid-macro-internal" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee1cd046f83ea2c4e920d6ee9f7c3537ef928d75dce5d84a87c2c5d6b3999a3a" +checksum = "6b91f57fe13a38d0ce9e28a03463d8d3c2468ed03d75375110ec71d93b449a08" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.94", ] [[package]] @@ -4186,6 +5709,15 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + [[package]] name = "wasi" version = "0.9.0+wasi-snapshot-preview1" @@ -4200,46 +5732,47 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.92" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +checksum = "a474f6281d1d70c17ae7aa6a613c87fce69a127e2624002df63dcb39d6cf6396" dependencies = [ "cfg-if", + "once_cell", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.92" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +checksum = "5f89bb38646b4f81674e8f5c3fb81b562be1fd936d84320f3264486418519c79" dependencies = [ "bumpalo", "log", - "once_cell", "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.94", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.42" +version = "0.4.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" +checksum = "38176d9b44ea84e9184eff0bc34cc167ed044f816accfe5922e54d84cf48eca2" dependencies = [ "cfg-if", "js-sys", + "once_cell", "wasm-bindgen", "web-sys", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.92" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +checksum = "2cc6181fd9a7492eef6fef1f33961e3695e4579b9872a6f7c83aee556666d4fe" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -4247,28 +5780,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.92" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.94", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.92" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" +checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6" [[package]] name = "wayland-backend" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90e11ce2ca99c97b940ee83edbae9da2d56a08f9ea8158550fd77fa31722993" +checksum = "056535ced7a150d45159d3a8dc30f91a2e2d588ca0b23f70e56033622b8016f6" dependencies = [ "cc", "downcast-rs", @@ -4280,9 +5813,9 @@ dependencies = [ [[package]] name = "wayland-client" -version = "0.31.5" +version = "0.31.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e321577a0a165911bdcfb39cf029302479d7527b517ee58ab0f6ad09edf0943" +checksum = "b66249d3fc69f76fd74c82cc319300faa554e9d865dab1f7cd66cc20db10b280" dependencies = [ "bitflags 2.6.0", "rustix", @@ -4317,20 +5850,20 @@ dependencies = [ [[package]] name = "wayland-scanner" -version = "0.31.4" +version = "0.31.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7b56f89937f1cf2ee1f1259cf2936a17a1f45d8f0aa1019fae6d470d304cfa6" +checksum = "597f2001b2e5fc1121e3d5b9791d3e78f05ba6bfa4641053846248e3a13661c3" dependencies = [ "proc-macro2", - "quick-xml 0.34.0", + "quick-xml 0.36.2", "quote", ] [[package]] name = "wayland-sys" -version = "0.31.4" +version = "0.31.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43676fe2daf68754ecf1d72026e4e6c15483198b5d24e888b74d3f22f887a148" +checksum = "efa8ac0d8e8ed3e3b5c9fc92c7881406a268e11555abe36493efabe649a29e09" dependencies = [ "dlib", "log", @@ -4339,9 +5872,19 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.69" +version = "0.3.76" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04dd7223427d52553d3702c004d3b2fe07c148165faa56313cb00211e31c12bc" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web-time" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" dependencies = [ "js-sys", "wasm-bindgen", @@ -4394,6 +5937,15 @@ dependencies = [ "system-deps 6.2.2", ] +[[package]] +name = "webpki-roots" +version = "0.26.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d642ff16b7e79272ae451b7322067cdc17cadf68c23264be9d94a32319efe7e" +dependencies = [ + "rustls-pki-types", +] + [[package]] name = "webview2-com" version = "0.19.1" @@ -4426,7 +5978,7 @@ dependencies = [ "regex", "serde", "serde_json", - "thiserror", + "thiserror 1.0.69", "windows 0.39.0", "windows-bindgen", "windows-metadata", @@ -4540,6 +6092,36 @@ version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ee5e275231f07c6e240d14f34e1b635bf1faa1c76c57cfd59a5cdb9848e4278" +[[package]] +name = "windows-registry" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" +dependencies = [ + "windows-result", + "windows-strings", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-result" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-strings" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +dependencies = [ + "windows-result", + "windows-targets 0.52.6", +] + [[package]] name = "windows-sys" version = "0.42.0" @@ -4831,9 +6413,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.6.18" +version = "0.6.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" +checksum = "39281189af81c07ec09db316b302a3e67bf9bd7cbf6c820b50e35fee9c2fa980" dependencies = [ "memchr", ] @@ -4860,7 +6442,7 @@ dependencies = [ "nix", "os_pipe", "tempfile", - "thiserror", + "thiserror 1.0.69", "tree_magic_mini", "wayland-backend", "wayland-client", @@ -4868,11 +6450,23 @@ dependencies = [ "wayland-protocols-wlr", ] +[[package]] +name = "write16" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" + +[[package]] +name = "writeable" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" + [[package]] name = "wry" -version = "0.24.10" +version = "0.24.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00711278ed357350d44c749c286786ecac644e044e4da410d466212152383b45" +checksum = "c55c80b12287eb1ff7c365fc2f7a5037cb6181bd44c9fce81c8d1cf7605ffad6" dependencies = [ "base64 0.13.1", "block", @@ -4885,7 +6479,7 @@ dependencies = [ "glib", "gtk", "html5ever", - "http", + "http 0.2.12", "kuchikiki", "libc", "log", @@ -4897,7 +6491,7 @@ dependencies = [ "sha2", "soup2", "tao", - "thiserror", + "thiserror 1.0.69", "url", "webkit2gtk", "webkit2gtk-sys", @@ -4955,11 +6549,41 @@ dependencies = [ "rustix", ] +[[package]] +name = "xml-rs" +version = "0.8.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea8b391c9a790b496184c29f7f93b9ed5b16abb306c05415b68bcc16e4d06432" + +[[package]] +name = "yoke" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.94", + "synstructure", +] + [[package]] name = "zerocopy" -version = "0.6.6" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "854e949ac82d619ee9a14c66a1b674ac730422372ccb759ce0c39cabcf2bf8e6" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ "byteorder", "zerocopy-derive", @@ -4967,11 +6591,60 @@ dependencies = [ [[package]] name = "zerocopy-derive" -version = "0.6.6" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.94", +] + +[[package]] +name = "zerofrom" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.94", + "synstructure", +] + +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" + +[[package]] +name = "zerovec" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "125139de3f6b9d625c39e2efdd73d41bdac468ccd556556440e322be0e1bbd91" +checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.94", ] diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index cfe32e0..27f1854 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -35,23 +35,25 @@ tokio = { version = "1", features = [ "time" ] } ## Adding "devtools" to features list enables devtools in production; But in mac it uses private api ## Tauri rust features are listed in the doc home page https://docs.rs/tauri/1.5.4/tauri/ ## Also see 'allowlist' in tauri.conf.json where we need to enable some of these APIs -tauri = { version = "1.7.1", features = ["clipboard-all", "dialog-all", "global-shortcut-all", "path-all", "process-exit", "shell-all"] } +tauri = { version = "1.8.1", features = ["clipboard-all", "dialog-all", "global-shortcut-all", "path-all", "process-exit", "shell-all"] } ## using from the local crate during development -## onekeepass-core = {path = "../../onekeepass-core", version = "0.15.0"} +## onekeepass-core = {path = "../../onekeepass-core", version = "0.16.0"} ## Need to use the git ref for release -onekeepass-core = {git = "https://github.com/OneKeePass/onekeepass-core.git" , tag="v0.15.0" } +onekeepass-core = {git = "https://github.com/OneKeePass/onekeepass-core.git" , tag="v0.16.0" } [build-dependencies] -tauri-build = { version = "1.5.3", features = [] } +tauri-build = { version = "1.5.5", features = [] } ## Need to use specific revision from git to ensure we can build for both 'aarch64' and 'x86_64' targets [target."cfg(target_os = \"macos\")".dependencies] -swift-rs = {git = "https://github.com/Brendonovich/swift-rs.git" , rev="973c22215734d1d5b97c496601d658371e537ece" } +swift-rs = "1.0.7" +## swift-rs = {git = "https://github.com/Brendonovich/swift-rs.git" , rev="973c22215734d1d5b97c496601d658371e537ece" } [target."cfg(target_os = \"macos\")".build-dependencies] -swift-rs = {git = "https://github.com/Brendonovich/swift-rs.git" , rev="973c22215734d1d5b97c496601d658371e537ece", features = ["build"] } +swift-rs = { version = "1.0.7", features = ["build"] } +## swift-rs = {git = "https://github.com/Brendonovich/swift-rs.git" , rev="973c22215734d1d5b97c496601d658371e537ece", features = ["build"] } [features] default = ["custom-protocol"] diff --git a/src-tauri/src/commands.rs b/src-tauri/src/commands.rs index 75f6e23..ecaf75c 100644 --- a/src-tauri/src/commands.rs +++ b/src-tauri/src/commands.rs @@ -553,7 +553,7 @@ pub(crate) async fn save_attachment_as_temp_file( name: &str, data_hash_str: &str, ) -> Result { - let data_hash = kp_service::parse_attachment_hash(data_hash_str)?; + let data_hash = kp_service::service_util::parse_attachment_hash(data_hash_str)?; Ok(kp_service::save_attachment_as_temp_file( db_key, name, &data_hash, )?) @@ -565,7 +565,7 @@ pub(crate) async fn save_attachment_as( full_file_name: &str, data_hash_str: &str, ) -> Result<()> { - let data_hash = kp_service::parse_attachment_hash(data_hash_str)?; + let data_hash = kp_service::service_util::parse_attachment_hash(data_hash_str)?; Ok(kp_service::save_attachment_as( db_key, full_file_name, @@ -585,7 +585,7 @@ pub(crate) async fn save_as_kdbx( //key_secure::delete_key(db_key); - // Appends this file name to the most recently opned file list + // Appends this file name to the most recently opened file list app_state .preference .lock() diff --git a/src-tauri/src/key_secure/macos.rs b/src-tauri/src/key_secure/macos.rs index 4f4fd7c..33e57f7 100644 --- a/src-tauri/src/key_secure/macos.rs +++ b/src-tauri/src/key_secure/macos.rs @@ -12,7 +12,7 @@ pub struct KeyStoreServiceImpl { #[inline] fn formatted_key(db_key: &str) -> SRString { - format!("OKP-{}", kp_service::string_to_simple_hash(db_key)) + format!("OKP-{}", kp_service::service_util::string_to_simple_hash(db_key)) .as_str() .into() } diff --git a/src-tauri/src/utils.rs b/src-tauri/src/utils.rs index be4c0f3..4a8a90f 100644 --- a/src-tauri/src/utils.rs +++ b/src-tauri/src/utils.rs @@ -221,7 +221,7 @@ pub fn generate_backup_file_name(backup_dir_path: PathBuf, db_file_name: &str) - |s| s.to_string_lossy().to_string(), ); - let n = kp_service::string_to_simple_hash(&parent_dir).to_string(); + let n = kp_service::service_util::string_to_simple_hash(&parent_dir).to_string(); // The backup_file_name will be of form "MyPassword_10084644638414928086.kdbx" for // the original file name "MyPassword.kdbx" where 10084644638414928086 is a hash of the dir part of full path diff --git a/src-tauri/swift-lib/Package.resolved b/src-tauri/swift-lib/Package.resolved index 093b610..4f1994b 100644 --- a/src-tauri/swift-lib/Package.resolved +++ b/src-tauri/swift-lib/Package.resolved @@ -6,8 +6,8 @@ "repositoryURL": "https://github.com/Brendonovich/swift-rs", "state": { "branch": null, - "revision": "a1578d5808b22b5a3461d36a6c8add5cd83a2ddf", - "version": "1.0.5" + "revision": "f64a4514de07f450ec5b6aa297624cd3479d9579", + "version": "1.0.7" } } ] diff --git a/src-tauri/swift-lib/Package.swift b/src-tauri/swift-lib/Package.swift index 3351e7e..70b7c4e 100644 --- a/src-tauri/swift-lib/Package.swift +++ b/src-tauri/swift-lib/Package.swift @@ -16,7 +16,7 @@ let package = Package( targets: ["swift-lib"]), ], dependencies: [ - .package(name: "SwiftRs", url: "https://github.com/Brendonovich/swift-rs", from: "1.0.5") + .package(name: "SwiftRs", url: "https://github.com/Brendonovich/swift-rs", from: "1.0.7") ], targets: [ // Targets are the basic building blocks of a package. A target can define a module or a test suite. diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index c59e009..90bc1dd 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -1,7 +1,7 @@ { "package": { "productName": "OneKeePass", - "version": "0.14.0" + "version": "0.15.0" }, "build": { "distDir": "../resources/public", diff --git a/yarn.lock b/yarn.lock index 8c4bb81..f4832a9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -110,16 +110,16 @@ resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz#1d572bfbbe14b7704e0ba0f39b74815b84870d70" integrity sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw== -"@emotion/babel-plugin@^11.12.0": - version "11.12.0" - resolved "https://registry.yarnpkg.com/@emotion/babel-plugin/-/babel-plugin-11.12.0.tgz#7b43debb250c313101b3f885eba634f1d723fcc2" - integrity sha512-y2WQb+oP8Jqvvclh8Q55gLUyb7UFvgv7eJfsj7td5TToBrIUtPay2kMrZi4xjq9qw2vD0ZR5fSho0yqoFgX7Rw== +"@emotion/babel-plugin@^11.13.5": + version "11.13.5" + resolved "https://registry.yarnpkg.com/@emotion/babel-plugin/-/babel-plugin-11.13.5.tgz#eab8d65dbded74e0ecfd28dc218e75607c4e7bc0" + integrity sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ== dependencies: "@babel/helper-module-imports" "^7.16.7" "@babel/runtime" "^7.18.3" "@emotion/hash" "^0.9.2" "@emotion/memoize" "^0.9.0" - "@emotion/serialize" "^1.2.0" + "@emotion/serialize" "^1.3.3" babel-plugin-macros "^3.1.0" convert-source-map "^1.5.0" escape-string-regexp "^4.0.0" @@ -127,14 +127,14 @@ source-map "^0.5.7" stylis "4.2.0" -"@emotion/cache@^11.11.0", "@emotion/cache@^11.13.0": - version "11.13.1" - resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-11.13.1.tgz#fecfc54d51810beebf05bf2a161271a1a91895d7" - integrity sha512-iqouYkuEblRcXmylXIwwOodiEK5Ifl7JcX7o6V4jI3iW4mLXX3dmt5xwBtIkJiQEXFAI+pC8X0i67yiPkH9Ucw== +"@emotion/cache@^11.13.5", "@emotion/cache@^11.14.0": + version "11.14.0" + resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-11.14.0.tgz#ee44b26986eeb93c8be82bb92f1f7a9b21b2ed76" + integrity sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA== dependencies: "@emotion/memoize" "^0.9.0" "@emotion/sheet" "^1.4.0" - "@emotion/utils" "^1.4.0" + "@emotion/utils" "^1.4.2" "@emotion/weak-memoize" "^0.4.0" stylis "4.2.0" @@ -155,29 +155,29 @@ resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.9.0.tgz#745969d649977776b43fc7648c556aaa462b4102" integrity sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ== -"@emotion/react@^11.13.0": - version "11.13.0" - resolved "https://registry.yarnpkg.com/@emotion/react/-/react-11.13.0.tgz#a9ebf827b98220255e5760dac89fa2d38ca7b43d" - integrity sha512-WkL+bw1REC2VNV1goQyfxjx1GYJkcc23CRQkXX+vZNLINyfI7o+uUn/rTGPt/xJ3bJHd5GcljgnxHf4wRw5VWQ== +"@emotion/react@^11.14.0": + version "11.14.0" + resolved "https://registry.yarnpkg.com/@emotion/react/-/react-11.14.0.tgz#cfaae35ebc67dd9ef4ea2e9acc6cd29e157dd05d" + integrity sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA== dependencies: "@babel/runtime" "^7.18.3" - "@emotion/babel-plugin" "^11.12.0" - "@emotion/cache" "^11.13.0" - "@emotion/serialize" "^1.3.0" - "@emotion/use-insertion-effect-with-fallbacks" "^1.1.0" - "@emotion/utils" "^1.4.0" + "@emotion/babel-plugin" "^11.13.5" + "@emotion/cache" "^11.14.0" + "@emotion/serialize" "^1.3.3" + "@emotion/use-insertion-effect-with-fallbacks" "^1.2.0" + "@emotion/utils" "^1.4.2" "@emotion/weak-memoize" "^0.4.0" hoist-non-react-statics "^3.3.1" -"@emotion/serialize@^1.2.0", "@emotion/serialize@^1.3.0": - version "1.3.0" - resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-1.3.0.tgz#e07cadfc967a4e7816e0c3ffaff4c6ce05cb598d" - integrity sha512-jACuBa9SlYajnpIVXB+XOXnfJHyckDfe6fOpORIM6yhBDlqGuExvDdZYHDQGoDf3bZXGv7tNr+LpLjJqiEQ6EA== +"@emotion/serialize@^1.3.3": + version "1.3.3" + resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-1.3.3.tgz#d291531005f17d704d0463a032fe679f376509e8" + integrity sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA== dependencies: "@emotion/hash" "^0.9.2" "@emotion/memoize" "^0.9.0" - "@emotion/unitless" "^0.9.0" - "@emotion/utils" "^1.4.0" + "@emotion/unitless" "^0.10.0" + "@emotion/utils" "^1.4.2" csstype "^3.0.2" "@emotion/sheet@^1.4.0": @@ -185,32 +185,32 @@ resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-1.4.0.tgz#c9299c34d248bc26e82563735f78953d2efca83c" integrity sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg== -"@emotion/styled@^11.13.0": - version "11.13.0" - resolved "https://registry.yarnpkg.com/@emotion/styled/-/styled-11.13.0.tgz#633fd700db701472c7a5dbef54d6f9834e9fb190" - integrity sha512-tkzkY7nQhW/zC4hztlwucpT8QEZ6eUzpXDRhww/Eej4tFfO0FxQYWRyg/c5CCXa4d/f174kqeXYjuQRnhzf6dA== +"@emotion/styled@^11.14.0": + version "11.14.0" + resolved "https://registry.yarnpkg.com/@emotion/styled/-/styled-11.14.0.tgz#f47ca7219b1a295186d7661583376fcea95f0ff3" + integrity sha512-XxfOnXFffatap2IyCeJyNov3kiDQWoR08gPUQxvbL7fxKryGBKUZUkG6Hz48DZwVrJSVh9sJboyV1Ds4OW6SgA== dependencies: "@babel/runtime" "^7.18.3" - "@emotion/babel-plugin" "^11.12.0" + "@emotion/babel-plugin" "^11.13.5" "@emotion/is-prop-valid" "^1.3.0" - "@emotion/serialize" "^1.3.0" - "@emotion/use-insertion-effect-with-fallbacks" "^1.1.0" - "@emotion/utils" "^1.4.0" + "@emotion/serialize" "^1.3.3" + "@emotion/use-insertion-effect-with-fallbacks" "^1.2.0" + "@emotion/utils" "^1.4.2" -"@emotion/unitless@^0.9.0": - version "0.9.0" - resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.9.0.tgz#8e5548f072bd67b8271877e51c0f95c76a66cbe2" - integrity sha512-TP6GgNZtmtFaFcsOgExdnfxLLpRDla4Q66tnenA9CktvVSdNKDvMVuUah4QvWPIpNjrWsGg3qeGo9a43QooGZQ== +"@emotion/unitless@^0.10.0": + version "0.10.0" + resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.10.0.tgz#2af2f7c7e5150f497bdabd848ce7b218a27cf745" + integrity sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg== -"@emotion/use-insertion-effect-with-fallbacks@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.1.0.tgz#1a818a0b2c481efba0cf34e5ab1e0cb2dcb9dfaf" - integrity sha512-+wBOcIV5snwGgI2ya3u99D7/FJquOIniQT1IKyDsBmEgwvpxMNeS65Oib7OnE2d2aY+3BU4OiH+0Wchf8yk3Hw== +"@emotion/use-insertion-effect-with-fallbacks@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.2.0.tgz#8a8cb77b590e09affb960f4ff1e9a89e532738bf" + integrity sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg== -"@emotion/utils@^1.4.0": - version "1.4.0" - resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-1.4.0.tgz#262f1d02aaedb2ec91c83a0955dd47822ad5fbdd" - integrity sha512-spEnrA1b6hDR/C68lC2M7m6ALPUHZC0lIY7jAS/B/9DuuO1ZP04eov8SMv/6fwRd8pzmsn2AuJEznRREWlQrlQ== +"@emotion/utils@^1.4.2": + version "1.4.2" + resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-1.4.2.tgz#6df6c45881fcb1c412d6688a311a98b7f59c1b52" + integrity sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA== "@emotion/weak-memoize@^0.4.0": version "0.4.0" @@ -289,7 +289,20 @@ "@jridgewell/resolve-uri" "^3.1.0" "@jridgewell/sourcemap-codec" "^1.4.14" -"@mui/base@5.0.0-beta.40", "@mui/base@^5.0.0-beta.20", "@mui/base@^5.0.0-beta.22": +"@mui/base@5.0.0-beta.40-0": + version "5.0.0-beta.40-0" + resolved "https://registry.yarnpkg.com/@mui/base/-/base-5.0.0-beta.40-0.tgz#4e211724d3feefa3dd1546952502b87491137e89" + integrity sha512-hG3atoDUxlvEy+0mqdMpWd04wca8HKr2IHjW/fAjlkCHQolSLazhZM46vnHjOf15M4ESu25mV/3PgjczyjVM4w== + dependencies: + "@babel/runtime" "^7.23.9" + "@floating-ui/react-dom" "^2.0.8" + "@mui/types" "^7.2.15" + "@mui/utils" "^5.16.12" + "@popperjs/core" "^2.11.8" + clsx "^2.1.0" + prop-types "^15.8.1" + +"@mui/base@^5.0.0-beta.20", "@mui/base@^5.0.0-beta.22": version "5.0.0-beta.40" resolved "https://registry.yarnpkg.com/@mui/base/-/base-5.0.0-beta.40.tgz#1f8a782f1fbf3f84a961e954c8176b187de3dae2" integrity sha512-I/lGHztkCzvwlXpjD2+SNmvNQvB4227xBXhISPjEaJUXGImOQ9f3D2Yj/T3KasSI/h0MLWy74X0J6clhPmsRbQ== @@ -302,78 +315,78 @@ clsx "^2.1.0" prop-types "^15.8.1" -"@mui/core-downloads-tracker@^5.16.7": - version "5.16.7" - resolved "https://registry.yarnpkg.com/@mui/core-downloads-tracker/-/core-downloads-tracker-5.16.7.tgz#182a325a520f7ebd75de051fceabfc0314cfd004" - integrity sha512-RtsCt4Geed2/v74sbihWzzRs+HsIQCfclHeORh5Ynu2fS4icIKozcSubwuG7vtzq2uW3fOR1zITSP84TNt2GoQ== +"@mui/core-downloads-tracker@^5.16.13": + version "5.16.13" + resolved "https://registry.yarnpkg.com/@mui/core-downloads-tracker/-/core-downloads-tracker-5.16.13.tgz#ac17c0d9ca9cdce6002168373b53e76af2606b35" + integrity sha512-xe5RwI0Q2O709Bd2Y7l1W1NIwNmln0y+xaGk5VgX3vDJbkQEqzdfTFZ73e0CkEZgJwyiWgk5HY0l8R4nysOxjw== -"@mui/icons-material@^5.16.6": - version "5.16.7" - resolved "https://registry.yarnpkg.com/@mui/icons-material/-/icons-material-5.16.7.tgz#e27f901af792065efc9f3d75d74a66af7529a10a" - integrity sha512-UrGwDJCXEszbDI7yV047BYU5A28eGJ79keTCP4cc74WyncuVrnurlmIRxaHL8YK+LI1Kzq+/JM52IAkNnv4u+Q== +"@mui/icons-material@^5.16.13": + version "5.16.13" + resolved "https://registry.yarnpkg.com/@mui/icons-material/-/icons-material-5.16.13.tgz#c89043915826a60dfbbe776ae6192480a8aa7844" + integrity sha512-aWyOgGDEqj37m3K4F6qUfn7JrEccwiDynJtGQMFbxp94EqyGwO13TKcZ4O8aHdwW3tG63hpbION8KyUoBWI4JQ== dependencies: "@babel/runtime" "^7.23.9" -"@mui/lab@^5.0.0-alpha.173": - version "5.0.0-alpha.173" - resolved "https://registry.yarnpkg.com/@mui/lab/-/lab-5.0.0-alpha.173.tgz#a0f9696d93a765b48d69a7da5aaca0affa510ae8" - integrity sha512-Gt5zopIWwxDgGy/MXcp6GueD84xFFugFai4hYiXY0zowJpTVnIrTQCQXV004Q7rejJ7aaCntX9hpPJqCrioshA== +"@mui/lab@^5.0.0-alpha.175": + version "5.0.0-alpha.175" + resolved "https://registry.yarnpkg.com/@mui/lab/-/lab-5.0.0-alpha.175.tgz#eb3bc607b96d164455c4beafe8d7f718bb1971fe" + integrity sha512-AvM0Nvnnj7vHc9+pkkQkoE1i+dEbr6gsMdnSfy7X4w3Ljgcj1yrjZhIt3jGTCLzyKVLa6uve5eLluOcGkvMqUA== dependencies: "@babel/runtime" "^7.23.9" - "@mui/base" "5.0.0-beta.40" - "@mui/system" "^5.16.5" + "@mui/base" "5.0.0-beta.40-0" + "@mui/system" "^5.16.12" "@mui/types" "^7.2.15" - "@mui/utils" "^5.16.5" + "@mui/utils" "^5.16.12" clsx "^2.1.0" prop-types "^15.8.1" -"@mui/material@^5.16.6": - version "5.16.7" - resolved "https://registry.yarnpkg.com/@mui/material/-/material-5.16.7.tgz#6e814e2eefdaf065a769cecf549c3569e107a50b" - integrity sha512-cwwVQxBhK60OIOqZOVLFt55t01zmarKJiJUWbk0+8s/Ix5IaUzAShqlJchxsIQ4mSrWqgcKCCXKtIlG5H+/Jmg== +"@mui/material@^5.16.13": + version "5.16.13" + resolved "https://registry.yarnpkg.com/@mui/material/-/material-5.16.13.tgz#ff44d6bbeb7304fb10ba64b820313942e26a9331" + integrity sha512-FhLDkDPYDzvrWCHFsdXzRArhS4AdYufU8d69rmLL+bwhodPcbm2C7cS8Gq5VR32PsW6aKZb58gvAgvEVaiiJbA== dependencies: "@babel/runtime" "^7.23.9" - "@mui/core-downloads-tracker" "^5.16.7" - "@mui/system" "^5.16.7" + "@mui/core-downloads-tracker" "^5.16.13" + "@mui/system" "^5.16.13" "@mui/types" "^7.2.15" - "@mui/utils" "^5.16.6" + "@mui/utils" "^5.16.13" "@popperjs/core" "^2.11.8" "@types/react-transition-group" "^4.4.10" clsx "^2.1.0" csstype "^3.1.3" prop-types "^15.8.1" - react-is "^18.3.1" + react-is "^19.0.0" react-transition-group "^4.4.5" -"@mui/private-theming@^5.16.6": - version "5.16.6" - resolved "https://registry.yarnpkg.com/@mui/private-theming/-/private-theming-5.16.6.tgz#547671e7ae3f86b68d1289a0b90af04dfcc1c8c9" - integrity sha512-rAk+Rh8Clg7Cd7shZhyt2HGTTE5wYKNSJ5sspf28Fqm/PZ69Er9o6KX25g03/FG2dfpg5GCwZh/xOojiTfm3hw== +"@mui/private-theming@^5.16.13": + version "5.16.13" + resolved "https://registry.yarnpkg.com/@mui/private-theming/-/private-theming-5.16.13.tgz#0ea25eb5272c2d16f555803bf804b31867d8eed9" + integrity sha512-+s0FklvDvO7j0yBZn19DIIT3rLfub2fWvXGtMX49rG/xHfDFcP7fbWbZKHZMMP/2/IoTRDrZCbY1iP0xZlmuJA== dependencies: "@babel/runtime" "^7.23.9" - "@mui/utils" "^5.16.6" + "@mui/utils" "^5.16.13" prop-types "^15.8.1" -"@mui/styled-engine@^5.16.6": - version "5.16.6" - resolved "https://registry.yarnpkg.com/@mui/styled-engine/-/styled-engine-5.16.6.tgz#60110c106dd482dfdb7e2aa94fd6490a0a3f8852" - integrity sha512-zaThmS67ZmtHSWToTiHslbI8jwrmITcN93LQaR2lKArbvS7Z3iLkwRoiikNWutx9MBs8Q6okKvbZq1RQYB3v7g== +"@mui/styled-engine@^5.16.13": + version "5.16.13" + resolved "https://registry.yarnpkg.com/@mui/styled-engine/-/styled-engine-5.16.13.tgz#b87205cd36b7a6b104f1151e8745bf7a19346987" + integrity sha512-2XNHEG8/o1ucSLhTA9J+HIIXjzlnEc0OV7kneeUQ5JukErPYT2zc6KYBDLjlKWrzQyvnQzbiffjjspgHUColZg== dependencies: "@babel/runtime" "^7.23.9" - "@emotion/cache" "^11.11.0" + "@emotion/cache" "^11.13.5" csstype "^3.1.3" prop-types "^15.8.1" -"@mui/system@^5.16.5", "@mui/system@^5.16.7": - version "5.16.7" - resolved "https://registry.yarnpkg.com/@mui/system/-/system-5.16.7.tgz#4583ca5bf3b38942e02c15a1e622ba869ac51393" - integrity sha512-Jncvs/r/d/itkxh7O7opOunTqbbSSzMTHzZkNLM+FjAOg+cYAZHrPDlYe1ZGKUYORwwb2XexlWnpZp0kZ4AHuA== +"@mui/system@^5.16.12", "@mui/system@^5.16.13": + version "5.16.13" + resolved "https://registry.yarnpkg.com/@mui/system/-/system-5.16.13.tgz#2ebbda08e962e378ecec9cf5a3e50ac9b098472d" + integrity sha512-JnO3VH3yNoAmgyr44/2jiS1tcNwshwAqAaG5fTEEjHQbkuZT/mvPYj2GC1cON0zEQ5V03xrCNl/D+gU9AXibpw== dependencies: "@babel/runtime" "^7.23.9" - "@mui/private-theming" "^5.16.6" - "@mui/styled-engine" "^5.16.6" + "@mui/private-theming" "^5.16.13" + "@mui/styled-engine" "^5.16.13" "@mui/types" "^7.2.15" - "@mui/utils" "^5.16.6" + "@mui/utils" "^5.16.13" clsx "^2.1.0" csstype "^3.1.3" prop-types "^15.8.1" @@ -383,7 +396,7 @@ resolved "https://registry.yarnpkg.com/@mui/types/-/types-7.2.15.tgz#dadd232fe9a70be0d526630675dff3b110f30b53" integrity sha512-nbo7yPhtKJkdf9kcVOF8JZHPZTmqXjJ/tI0bdWgHg5tp9AnIN4Y7f7wm9T+0SyGYJk76+GYZ8Q5XaTYAsUHN0Q== -"@mui/utils@^5.14.14", "@mui/utils@^5.14.16", "@mui/utils@^5.15.14", "@mui/utils@^5.16.5", "@mui/utils@^5.16.6": +"@mui/utils@^5.14.14", "@mui/utils@^5.14.16", "@mui/utils@^5.15.14": version "5.16.6" resolved "https://registry.yarnpkg.com/@mui/utils/-/utils-5.16.6.tgz#905875bbc58d3dcc24531c3314a6807aba22a711" integrity sha512-tWiQqlhxAt3KENNiSRL+DIn9H5xNVK6Jjf70x3PnfQPz1MPBdh7yyIcAyVBT9xiw7hP3SomRhPR7hzBMBCjqEA== @@ -395,6 +408,18 @@ prop-types "^15.8.1" react-is "^18.3.1" +"@mui/utils@^5.16.12", "@mui/utils@^5.16.13": + version "5.16.13" + resolved "https://registry.yarnpkg.com/@mui/utils/-/utils-5.16.13.tgz#6276eafd15e2c6778cdb6aeb07017c996d3fda52" + integrity sha512-35kLiShnDPByk57Mz4PP66fQUodCFiOD92HfpW6dK9lc7kjhZsKHRKeYPgWuwEHeXwYsCSFtBCW4RZh/8WT+TQ== + dependencies: + "@babel/runtime" "^7.23.9" + "@mui/types" "^7.2.15" + "@types/prop-types" "^15.7.12" + clsx "^2.1.1" + prop-types "^15.8.1" + react-is "^19.0.0" + "@mui/x-date-pickers@^6.20.2": version "6.20.2" resolved "https://registry.yarnpkg.com/@mui/x-date-pickers/-/x-date-pickers-6.20.2.tgz#b1b1e4862daafb750496cc77a1645caeac28a739" @@ -431,73 +456,75 @@ resolved "https://registry.yarnpkg.com/@tauri-apps/api/-/api-1.6.0.tgz#745b7e4e26782c3b2ad9510d558fa5bb2cf29186" integrity sha512-rqI++FWClU5I2UBp4HXFvl+sBWkdigBkxnpJDQUWttNyG7IZP4FwQGhTNL5EOw0vI8i6eSAJ5frLqO7n7jbJdg== -"@tauri-apps/cli-darwin-arm64@1.6.0": - version "1.6.0" - resolved "https://registry.yarnpkg.com/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-1.6.0.tgz#cddb151935f44fc82e9e47866fb72c429ab9f28e" - integrity sha512-SNRwUD9nqGxY47mbY1CGTt/jqyQOU7Ps7Mx/mpgahL0FVUDiCEY/5L9QfEPPhEgccgcelEVn7i6aQHIkHyUtCA== - -"@tauri-apps/cli-darwin-x64@1.6.0": - version "1.6.0" - resolved "https://registry.yarnpkg.com/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-1.6.0.tgz#ea94c169dd6bb9597e0edc0fdac91f116a697c0b" - integrity sha512-g2/uDR/eeH2arvuawA4WwaEOqv/7jDO/ZLNI3JlBjP5Pk8GGb3Kdy0ro1xQzF94mtk2mOnOXa4dMgAet4sUJ1A== - -"@tauri-apps/cli-linux-arm-gnueabihf@1.6.0": - version "1.6.0" - resolved "https://registry.yarnpkg.com/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-1.6.0.tgz#b17a5b48481a454265271b3741698c333590b62b" - integrity sha512-EVwf4oRkQyG8BpSrk0gqO7oA0sDM2MdNDtJpMfleYFEgCxLIOGZKNqaOW3M7U+0Y4qikmG3TtRK+ngc8Ymtrjg== - -"@tauri-apps/cli-linux-arm64-gnu@1.6.0": - version "1.6.0" - resolved "https://registry.yarnpkg.com/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-1.6.0.tgz#1157c3fbda02a4b9e21d3ef40a769fec7ae06bff" - integrity sha512-YdpY17cAySrhK9dX4BUVEmhAxE2o+6skIEFg8iN/xrDwRxhaNPI9I80YXPatUTX54Kx55T5++25VJG9+3iw83A== - -"@tauri-apps/cli-linux-arm64-musl@1.6.0": - version "1.6.0" - resolved "https://registry.yarnpkg.com/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-1.6.0.tgz#47837d9bdb52e3dae3a071ffcb383fb1c726700a" - integrity sha512-4U628tuf2U8pMr4tIBJhEkrFwt+46dwhXrDlpdyWSZtnop5RJAVKHODm0KbWns4xGKfTW1F3r6sSv+2ZxLcISA== - -"@tauri-apps/cli-linux-x64-gnu@1.6.0": - version "1.6.0" - resolved "https://registry.yarnpkg.com/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-1.6.0.tgz#ece8cb45af7f47e174ac4125130553c8a84a402e" - integrity sha512-AKRzp76fVUaJyXj5KRJT9bJyhwZyUnRQU0RqIRqOtZCT5yr6qGP8rjtQ7YhCIzWrseBlOllc3Qvbgw3Yl0VQcA== - -"@tauri-apps/cli-linux-x64-musl@1.6.0": - version "1.6.0" - resolved "https://registry.yarnpkg.com/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-1.6.0.tgz#d5f54c7bd8956d0b80603381eb6fea4cb11bea08" - integrity sha512-0edIdq6aMBTaRMIXddHfyAFL361JqulLLd2Wi2aoOie7DkQ2MYh6gv3hA7NB9gqFwNIGE+xtJ4BkXIP2tSGPlg== - -"@tauri-apps/cli-win32-arm64-msvc@1.6.0": - version "1.6.0" - resolved "https://registry.yarnpkg.com/@tauri-apps/cli-win32-arm64-msvc/-/cli-win32-arm64-msvc-1.6.0.tgz#df53c67147915e933141af2b2bfd4bee64792bdf" - integrity sha512-QwWpWk4ubcwJ1rljsRAmINgB2AwkyzZhpYbalA+MmzyYMREcdXWGkyixWbRZgqc6fEWEBmq5UG73qz5eBJiIKg== - -"@tauri-apps/cli-win32-ia32-msvc@1.6.0": - version "1.6.0" - resolved "https://registry.yarnpkg.com/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-1.6.0.tgz#5608e4235277753ad67f1ac471a95902be265a77" - integrity sha512-Vtw0yxO9+aEFuhuxQ57ALG43tjECopRimRuKGbtZYDCriB/ty5TrT3QWMdy0dxBkpDTu3Rqsz30sbDzw6tlP3Q== - -"@tauri-apps/cli-win32-x64-msvc@1.6.0": - version "1.6.0" - resolved "https://registry.yarnpkg.com/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-1.6.0.tgz#dd43cc78e3ca8839948c358829a877cf47d4e6f4" - integrity sha512-h54FHOvGi7+LIfRchzgZYSCHB1HDlP599vWXQQJ/XnwJY+6Rwr2E5bOe/EhqoG8rbGkfK0xX3KPAvXPbUlmggg== - -"@tauri-apps/cli@1.6.0": - version "1.6.0" - resolved "https://registry.yarnpkg.com/@tauri-apps/cli/-/cli-1.6.0.tgz#cd1b54c2774291fb879d9b5ae5f70cf253f48c25" - integrity sha512-DBBpBl6GhTzm8ImMbKkfaZ4fDTykWrC7Q5OXP4XqD91recmDEn2LExuvuiiS3HYe7uP8Eb5B9NPHhqJb+Zo7qQ== +"@tauri-apps/cli-darwin-arm64@1.6.3": + version "1.6.3" + resolved "https://registry.yarnpkg.com/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-1.6.3.tgz#a204b9c686c88d774b7a67e0344cf660a0704558" + integrity sha512-fQN6IYSL8bG4NvkdKE4sAGF4dF/QqqQq4hOAU+t8ksOzHJr0hUlJYfncFeJYutr/MMkdF7hYKadSb0j5EE9r0A== + +"@tauri-apps/cli-darwin-x64@1.6.3": + version "1.6.3" + resolved "https://registry.yarnpkg.com/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-1.6.3.tgz#2486f54c0b3beddf9f007b76d0b31d4da7b80e5d" + integrity sha512-1yTXZzLajKAYINJOJhZfmMhCzweHSgKQ3bEgJSn6t+1vFkOgY8Yx4oFgWcybrrWI5J1ZLZAl47+LPOY81dLcyA== + +"@tauri-apps/cli-linux-arm-gnueabihf@1.6.3": + version "1.6.3" + resolved "https://registry.yarnpkg.com/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-1.6.3.tgz#53066f4e8292f33c1967ab5732ec9c53a0fe8531" + integrity sha512-CjTEr9r9xgjcvos09AQw8QMRPuH152B1jvlZt4PfAsyJNPFigzuwed5/SF7XAd8bFikA7zArP4UT12RdBxrx7w== + +"@tauri-apps/cli-linux-arm64-gnu@1.6.3": + version "1.6.3" + resolved "https://registry.yarnpkg.com/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-1.6.3.tgz#e204925e9f229d36cf8af17df59545ca88becfeb" + integrity sha512-G9EUUS4M8M/Jz1UKZqvJmQQCKOzgTb8/0jZKvfBuGfh5AjFBu8LHvlFpwkKVm1l4951Xg4ulUp6P9Q7WRJ9XSA== + +"@tauri-apps/cli-linux-arm64-musl@1.6.3": + version "1.6.3" + resolved "https://registry.yarnpkg.com/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-1.6.3.tgz#a3753b2fa8d3c68bd8ebdd4af08d4b9a83bbf127" + integrity sha512-MuBTHJyNpZRbPVG8IZBN8+Zs7aKqwD22tkWVBcL1yOGL4zNNTJlkfL+zs5qxRnHlUsn6YAlbW/5HKocfpxVwBw== + +"@tauri-apps/cli-linux-x64-gnu@1.6.3": + version "1.6.3" + resolved "https://registry.yarnpkg.com/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-1.6.3.tgz#9a22f12f310ed2af9ff46cc6251203f6d2b81aee" + integrity sha512-Uvi7M+NK3tAjCZEY1WGel+dFlzJmqcvu3KND+nqa22762NFmOuBIZ4KJR/IQHfpEYqKFNUhJfCGnpUDfiC3Oxg== + +"@tauri-apps/cli-linux-x64-musl@1.6.3": + version "1.6.3" + resolved "https://registry.yarnpkg.com/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-1.6.3.tgz#c5b022f26c869b4877898589baf8dabf87a79096" + integrity sha512-rc6B342C0ra8VezB/OJom9j/N+9oW4VRA4qMxS2f4bHY2B/z3J9NPOe6GOILeg4v/CV62ojkLsC3/K/CeF3fqQ== + +"@tauri-apps/cli-win32-arm64-msvc@1.6.3": + version "1.6.3" + resolved "https://registry.yarnpkg.com/@tauri-apps/cli-win32-arm64-msvc/-/cli-win32-arm64-msvc-1.6.3.tgz#5a871f96a7d58da5adacae07c848e5a0f3e82286" + integrity sha512-cSH2qOBYuYC4UVIFtrc1YsGfc5tfYrotoHrpTvRjUGu0VywvmyNk82+ZsHEnWZ2UHmu3l3lXIGRqSWveLln0xg== + +"@tauri-apps/cli-win32-ia32-msvc@1.6.3": + version "1.6.3" + resolved "https://registry.yarnpkg.com/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-1.6.3.tgz#cbec8e197a1cf0a63d329661ee45dcd7a31d05eb" + integrity sha512-T8V6SJQqE4PSWmYBl0ChQVmS6AR2hXFHURH2DwAhgSGSQ6uBXgwlYFcfIeQpBQA727K2Eq8X2hGfvmoySyHMRw== + +"@tauri-apps/cli-win32-x64-msvc@1.6.3": + version "1.6.3" + resolved "https://registry.yarnpkg.com/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-1.6.3.tgz#a78f5ccabbaca1d7ac3ce2acab2b1bd0276b53c4" + integrity sha512-HUkWZ+lYHI/Gjkh2QjHD/OBDpqLVmvjZGpLK9losur1Eg974Jip6k+vsoTUxQBCBDfj30eDBct9E1FvXOspWeg== + +"@tauri-apps/cli@1.6.3": + version "1.6.3" + resolved "https://registry.yarnpkg.com/@tauri-apps/cli/-/cli-1.6.3.tgz#75e23dea0b67774fc6f150d637a0dbecf1f9592c" + integrity sha512-q46umd6QLRKDd4Gg6WyZBGa2fWvk0pbeUA5vFomm4uOs1/17LIciHv2iQ4UD+2Yv5H7AO8YiE1t50V0POiEGEw== + dependencies: + semver ">=7.5.2" optionalDependencies: - "@tauri-apps/cli-darwin-arm64" "1.6.0" - "@tauri-apps/cli-darwin-x64" "1.6.0" - "@tauri-apps/cli-linux-arm-gnueabihf" "1.6.0" - "@tauri-apps/cli-linux-arm64-gnu" "1.6.0" - "@tauri-apps/cli-linux-arm64-musl" "1.6.0" - "@tauri-apps/cli-linux-x64-gnu" "1.6.0" - "@tauri-apps/cli-linux-x64-musl" "1.6.0" - "@tauri-apps/cli-win32-arm64-msvc" "1.6.0" - "@tauri-apps/cli-win32-ia32-msvc" "1.6.0" - "@tauri-apps/cli-win32-x64-msvc" "1.6.0" - -"@types/eslint-scope@^3.7.3": + "@tauri-apps/cli-darwin-arm64" "1.6.3" + "@tauri-apps/cli-darwin-x64" "1.6.3" + "@tauri-apps/cli-linux-arm-gnueabihf" "1.6.3" + "@tauri-apps/cli-linux-arm64-gnu" "1.6.3" + "@tauri-apps/cli-linux-arm64-musl" "1.6.3" + "@tauri-apps/cli-linux-x64-gnu" "1.6.3" + "@tauri-apps/cli-linux-x64-musl" "1.6.3" + "@tauri-apps/cli-win32-arm64-msvc" "1.6.3" + "@tauri-apps/cli-win32-ia32-msvc" "1.6.3" + "@tauri-apps/cli-win32-x64-msvc" "1.6.3" + +"@types/eslint-scope@^3.7.7": version "3.7.7" resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.7.tgz#3108bd5f18b0cdb277c867b3dd449c9ed7079ac5" integrity sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg== @@ -513,11 +540,16 @@ "@types/estree" "*" "@types/json-schema" "*" -"@types/estree@*", "@types/estree@^1.0.5": +"@types/estree@*": version "1.0.5" resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4" integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw== +"@types/estree@^1.0.6": + version "1.0.6" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.6.tgz#628effeeae2064a1b4e79f78e81d87b7e5fc7b50" + integrity sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw== + "@types/json-schema@*", "@types/json-schema@^7.0.8": version "7.0.15" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" @@ -555,143 +587,141 @@ "@types/prop-types" "*" csstype "^3.0.2" -"@webassemblyjs/ast@1.12.1", "@webassemblyjs/ast@^1.12.1": - version "1.12.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.12.1.tgz#bb16a0e8b1914f979f45864c23819cc3e3f0d4bb" - integrity sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg== +"@webassemblyjs/ast@1.14.1", "@webassemblyjs/ast@^1.14.1": + version "1.14.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.14.1.tgz#a9f6a07f2b03c95c8d38c4536a1fdfb521ff55b6" + integrity sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ== dependencies: - "@webassemblyjs/helper-numbers" "1.11.6" - "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + "@webassemblyjs/helper-numbers" "1.13.2" + "@webassemblyjs/helper-wasm-bytecode" "1.13.2" -"@webassemblyjs/floating-point-hex-parser@1.11.6": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz#dacbcb95aff135c8260f77fa3b4c5fea600a6431" - integrity sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw== +"@webassemblyjs/floating-point-hex-parser@1.13.2": + version "1.13.2" + resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz#fcca1eeddb1cc4e7b6eed4fc7956d6813b21b9fb" + integrity sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA== -"@webassemblyjs/helper-api-error@1.11.6": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz#6132f68c4acd59dcd141c44b18cbebbd9f2fa768" - integrity sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q== +"@webassemblyjs/helper-api-error@1.13.2": + version "1.13.2" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz#e0a16152248bc38daee76dd7e21f15c5ef3ab1e7" + integrity sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ== -"@webassemblyjs/helper-buffer@1.12.1": - version "1.12.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz#6df20d272ea5439bf20ab3492b7fb70e9bfcb3f6" - integrity sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw== +"@webassemblyjs/helper-buffer@1.14.1": + version "1.14.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz#822a9bc603166531f7d5df84e67b5bf99b72b96b" + integrity sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA== -"@webassemblyjs/helper-numbers@1.11.6": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz#cbce5e7e0c1bd32cf4905ae444ef64cea919f1b5" - integrity sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g== +"@webassemblyjs/helper-numbers@1.13.2": + version "1.13.2" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz#dbd932548e7119f4b8a7877fd5a8d20e63490b2d" + integrity sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA== dependencies: - "@webassemblyjs/floating-point-hex-parser" "1.11.6" - "@webassemblyjs/helper-api-error" "1.11.6" + "@webassemblyjs/floating-point-hex-parser" "1.13.2" + "@webassemblyjs/helper-api-error" "1.13.2" "@xtuc/long" "4.2.2" -"@webassemblyjs/helper-wasm-bytecode@1.11.6": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz#bb2ebdb3b83aa26d9baad4c46d4315283acd51e9" - integrity sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA== +"@webassemblyjs/helper-wasm-bytecode@1.13.2": + version "1.13.2" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz#e556108758f448aae84c850e593ce18a0eb31e0b" + integrity sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA== -"@webassemblyjs/helper-wasm-section@1.12.1": - version "1.12.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz#3da623233ae1a60409b509a52ade9bc22a37f7bf" - integrity sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g== +"@webassemblyjs/helper-wasm-section@1.14.1": + version "1.14.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz#9629dda9c4430eab54b591053d6dc6f3ba050348" + integrity sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw== dependencies: - "@webassemblyjs/ast" "1.12.1" - "@webassemblyjs/helper-buffer" "1.12.1" - "@webassemblyjs/helper-wasm-bytecode" "1.11.6" - "@webassemblyjs/wasm-gen" "1.12.1" + "@webassemblyjs/ast" "1.14.1" + "@webassemblyjs/helper-buffer" "1.14.1" + "@webassemblyjs/helper-wasm-bytecode" "1.13.2" + "@webassemblyjs/wasm-gen" "1.14.1" -"@webassemblyjs/ieee754@1.11.6": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz#bb665c91d0b14fffceb0e38298c329af043c6e3a" - integrity sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg== +"@webassemblyjs/ieee754@1.13.2": + version "1.13.2" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz#1c5eaace1d606ada2c7fd7045ea9356c59ee0dba" + integrity sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw== dependencies: "@xtuc/ieee754" "^1.2.0" -"@webassemblyjs/leb128@1.11.6": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.11.6.tgz#70e60e5e82f9ac81118bc25381a0b283893240d7" - integrity sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ== +"@webassemblyjs/leb128@1.13.2": + version "1.13.2" + resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.13.2.tgz#57c5c3deb0105d02ce25fa3fd74f4ebc9fd0bbb0" + integrity sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw== dependencies: "@xtuc/long" "4.2.2" -"@webassemblyjs/utf8@1.11.6": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.11.6.tgz#90f8bc34c561595fe156603be7253cdbcd0fab5a" - integrity sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA== - -"@webassemblyjs/wasm-edit@^1.12.1": - version "1.12.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz#9f9f3ff52a14c980939be0ef9d5df9ebc678ae3b" - integrity sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g== - dependencies: - "@webassemblyjs/ast" "1.12.1" - "@webassemblyjs/helper-buffer" "1.12.1" - "@webassemblyjs/helper-wasm-bytecode" "1.11.6" - "@webassemblyjs/helper-wasm-section" "1.12.1" - "@webassemblyjs/wasm-gen" "1.12.1" - "@webassemblyjs/wasm-opt" "1.12.1" - "@webassemblyjs/wasm-parser" "1.12.1" - "@webassemblyjs/wast-printer" "1.12.1" - -"@webassemblyjs/wasm-gen@1.12.1": - version "1.12.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz#a6520601da1b5700448273666a71ad0a45d78547" - integrity sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w== - dependencies: - "@webassemblyjs/ast" "1.12.1" - "@webassemblyjs/helper-wasm-bytecode" "1.11.6" - "@webassemblyjs/ieee754" "1.11.6" - "@webassemblyjs/leb128" "1.11.6" - "@webassemblyjs/utf8" "1.11.6" - -"@webassemblyjs/wasm-opt@1.12.1": - version "1.12.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz#9e6e81475dfcfb62dab574ac2dda38226c232bc5" - integrity sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg== - dependencies: - "@webassemblyjs/ast" "1.12.1" - "@webassemblyjs/helper-buffer" "1.12.1" - "@webassemblyjs/wasm-gen" "1.12.1" - "@webassemblyjs/wasm-parser" "1.12.1" - -"@webassemblyjs/wasm-parser@1.12.1", "@webassemblyjs/wasm-parser@^1.12.1": - version "1.12.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz#c47acb90e6f083391e3fa61d113650eea1e95937" - integrity sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ== - dependencies: - "@webassemblyjs/ast" "1.12.1" - "@webassemblyjs/helper-api-error" "1.11.6" - "@webassemblyjs/helper-wasm-bytecode" "1.11.6" - "@webassemblyjs/ieee754" "1.11.6" - "@webassemblyjs/leb128" "1.11.6" - "@webassemblyjs/utf8" "1.11.6" - -"@webassemblyjs/wast-printer@1.12.1": - version "1.12.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz#bcecf661d7d1abdaf989d8341a4833e33e2b31ac" - integrity sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA== - dependencies: - "@webassemblyjs/ast" "1.12.1" +"@webassemblyjs/utf8@1.13.2": + version "1.13.2" + resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.13.2.tgz#917a20e93f71ad5602966c2d685ae0c6c21f60f1" + integrity sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ== + +"@webassemblyjs/wasm-edit@^1.14.1": + version "1.14.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz#ac6689f502219b59198ddec42dcd496b1004d597" + integrity sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ== + dependencies: + "@webassemblyjs/ast" "1.14.1" + "@webassemblyjs/helper-buffer" "1.14.1" + "@webassemblyjs/helper-wasm-bytecode" "1.13.2" + "@webassemblyjs/helper-wasm-section" "1.14.1" + "@webassemblyjs/wasm-gen" "1.14.1" + "@webassemblyjs/wasm-opt" "1.14.1" + "@webassemblyjs/wasm-parser" "1.14.1" + "@webassemblyjs/wast-printer" "1.14.1" + +"@webassemblyjs/wasm-gen@1.14.1": + version "1.14.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz#991e7f0c090cb0bb62bbac882076e3d219da9570" + integrity sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg== + dependencies: + "@webassemblyjs/ast" "1.14.1" + "@webassemblyjs/helper-wasm-bytecode" "1.13.2" + "@webassemblyjs/ieee754" "1.13.2" + "@webassemblyjs/leb128" "1.13.2" + "@webassemblyjs/utf8" "1.13.2" + +"@webassemblyjs/wasm-opt@1.14.1": + version "1.14.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz#e6f71ed7ccae46781c206017d3c14c50efa8106b" + integrity sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw== + dependencies: + "@webassemblyjs/ast" "1.14.1" + "@webassemblyjs/helper-buffer" "1.14.1" + "@webassemblyjs/wasm-gen" "1.14.1" + "@webassemblyjs/wasm-parser" "1.14.1" + +"@webassemblyjs/wasm-parser@1.14.1", "@webassemblyjs/wasm-parser@^1.14.1": + version "1.14.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz#b3e13f1893605ca78b52c68e54cf6a865f90b9fb" + integrity sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ== + dependencies: + "@webassemblyjs/ast" "1.14.1" + "@webassemblyjs/helper-api-error" "1.13.2" + "@webassemblyjs/helper-wasm-bytecode" "1.13.2" + "@webassemblyjs/ieee754" "1.13.2" + "@webassemblyjs/leb128" "1.13.2" + "@webassemblyjs/utf8" "1.13.2" + +"@webassemblyjs/wast-printer@1.14.1": + version "1.14.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz#3bb3e9638a8ae5fdaf9610e7a06b4d9f9aa6fe07" + integrity sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw== + dependencies: + "@webassemblyjs/ast" "1.14.1" "@xtuc/long" "4.2.2" -"@webpack-cli/configtest@^1.2.0": - version "1.2.0" - resolved "https://registry.yarnpkg.com/@webpack-cli/configtest/-/configtest-1.2.0.tgz#7b20ce1c12533912c3b217ea68262365fa29a6f5" - integrity sha512-4FB8Tj6xyVkyqjj1OaTqCjXYULB9FMkqQ8yGrZjRDrYh0nOE+7Lhs45WioWQQMV+ceFlE368Ukhe6xdvJM9Egg== +"@webpack-cli/configtest@^2.1.1": + version "2.1.1" + resolved "https://registry.yarnpkg.com/@webpack-cli/configtest/-/configtest-2.1.1.tgz#3b2f852e91dac6e3b85fb2a314fb8bef46d94646" + integrity sha512-wy0mglZpDSiSS0XHrVR+BAdId2+yxPSoJW8fsna3ZpYSlufjvxnP4YbKTCBZnNIcGN4r6ZPXV55X4mYExOfLmw== -"@webpack-cli/info@^1.5.0": - version "1.5.0" - resolved "https://registry.yarnpkg.com/@webpack-cli/info/-/info-1.5.0.tgz#6c78c13c5874852d6e2dd17f08a41f3fe4c261b1" - integrity sha512-e8tSXZpw2hPl2uMJY6fsMswaok5FdlGNRTktvFk2sD8RjH0hE2+XistawJx1vmKteh4NmGmNUrp+Tb2w+udPcQ== - dependencies: - envinfo "^7.7.3" +"@webpack-cli/info@^2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@webpack-cli/info/-/info-2.0.2.tgz#cc3fbf22efeb88ff62310cf885c5b09f44ae0fdd" + integrity sha512-zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A== -"@webpack-cli/serve@^1.7.0": - version "1.7.0" - resolved "https://registry.yarnpkg.com/@webpack-cli/serve/-/serve-1.7.0.tgz#e1993689ac42d2b16e9194376cfb6753f6254db1" - integrity sha512-oxnCNGj88fL+xzV+dacXs44HcDwf1ovs3AuEzvP7mqXw7fQntqIhQ1BRmynh4qEKQSSSRSWVyXRjmTbZIX9V2Q== +"@webpack-cli/serve@^2.0.5": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@webpack-cli/serve/-/serve-2.0.5.tgz#325db42395cd49fe6c14057f9a900e427df8810e" + integrity sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ== "@xtuc/ieee754@^1.2.0": version "1.2.0" @@ -703,12 +733,12 @@ resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d" integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== -acorn-import-attributes@^1.9.5: - version "1.9.5" - resolved "https://registry.yarnpkg.com/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz#7eb1557b1ba05ef18b5ed0ec67591bfab04688ef" - integrity sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ== +acorn@^8.14.0: + version "8.14.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.14.0.tgz#063e2c70cac5fb4f6467f0b11152e04c682795b0" + integrity sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA== -acorn@^8.7.1, acorn@^8.8.2: +acorn@^8.8.2: version "8.12.1" resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.12.1.tgz#71616bdccbe25e27a54439e0046e89ca76df2248" integrity sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg== @@ -744,15 +774,15 @@ babel-plugin-macros@^3.1.0: cosmiconfig "^7.0.0" resolve "^1.19.0" -browserslist@^4.21.10: - version "4.23.3" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.23.3.tgz#debb029d3c93ebc97ffbc8d9cbb03403e227c800" - integrity sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA== +browserslist@^4.24.0: + version "4.24.3" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.24.3.tgz#5fc2725ca8fb3c1432e13dac278c7cc103e026d2" + integrity sha512-1CPmv8iobE2fyRMV97dAcMVegvvWKxmq94hkLiAkUGwKVTyDLw33K+ZxiFrREKmmps4rIw6grcCFCnTMSZ/YiA== dependencies: - caniuse-lite "^1.0.30001646" - electron-to-chromium "^1.5.4" - node-releases "^2.0.18" - update-browserslist-db "^1.1.0" + caniuse-lite "^1.0.30001688" + electron-to-chromium "^1.5.73" + node-releases "^2.0.19" + update-browserslist-db "^1.1.1" buffer-from@^1.0.0: version "1.1.2" @@ -764,10 +794,10 @@ callsites@^3.0.0: resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== -caniuse-lite@^1.0.30001646: - version "1.0.30001651" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001651.tgz#52de59529e8b02b1aedcaaf5c05d9e23c0c28138" - integrity sha512-9Cf+Xv1jJNe1xPZLGuUXLNkE1BoDkqRqYyFJ9TDYSqhduqA4hu4oR9HluGoWYQC/aj8WHjsGVV+bwkh0+tegRg== +caniuse-lite@^1.0.30001688: + version "1.0.30001690" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001690.tgz#f2d15e3aaf8e18f76b2b8c1481abde063b8104c8" + integrity sha512-5ExiE3qQN6oF8Clf8ifIDcMRCRE/dMGcETG/XGMD8/XiXm6HXQgQTh1yZYLXXpSOsEUlJm1Xr7kGULZTuGtP/w== chalk@^2.4.2: version "2.4.2" @@ -814,16 +844,16 @@ colorette@^2.0.14: resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.20.tgz#9eb793e6833067f7235902fcd3b09917a000a95a" integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w== +commander@^10.0.1: + version "10.0.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-10.0.1.tgz#881ee46b4f77d1c1dccc5823433aa39b022cbe06" + integrity sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug== + commander@^2.20.0: version "2.20.3" resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== -commander@^7.0.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7" - integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw== - convert-source-map@^1.5.0: version "1.9.0" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.9.0.tgz#7faae62353fb4213366d0ca98358d22e8368b05f" @@ -876,15 +906,15 @@ dom-helpers@^5.0.1: "@babel/runtime" "^7.8.7" csstype "^3.0.2" -electron-to-chromium@^1.5.4: - version "1.5.6" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.6.tgz#c81d9938b5a877314ad370feb73b4e5409b36abd" - integrity sha512-jwXWsM5RPf6j9dPYzaorcBSUg6AiqocPEyMpkchkvntaH9HGfOOMZwxMJjDY/XEs3T5dM7uyH1VhRMkqUU9qVw== +electron-to-chromium@^1.5.73: + version "1.5.76" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.76.tgz#db20295c5061b68f07c8ea4dfcbd701485d94a3d" + integrity sha512-CjVQyG7n7Sr+eBXE86HIulnL5N8xZY1sgmOPGuq/F0Rr0FJq63lg0kEtOIDfZBk44FnDLf6FUJ+dsJcuiUDdDQ== -enhanced-resolve@^5.17.0: - version "5.17.1" - resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz#67bfbbcc2f81d511be77d686a90267ef7f898a15" - integrity sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg== +enhanced-resolve@^5.17.1: + version "5.18.0" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.18.0.tgz#91eb1db193896b9801251eeff1c6980278b1e404" + integrity sha512-0/r0MySGYG8YqlayBZ6MuCfECmHFdJ5qyPh8s8wa5Hnm6SaFLSK1VYCbj+NKp090Nm1caZhD+QTnmxO7esYGyQ== dependencies: graceful-fs "^4.2.4" tapable "^2.2.0" @@ -906,10 +936,10 @@ es-module-lexer@^1.2.1: resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-1.5.4.tgz#a8efec3a3da991e60efa6b633a7cad6ab8d26b78" integrity sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw== -escalade@^3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.2.tgz#54076e9ab29ea5bf3d8f1ed62acffbb88272df27" - integrity sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA== +escalade@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" + integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== escape-string-regexp@^1.0.5: version "1.0.5" @@ -1058,10 +1088,10 @@ import-local@^3.0.2: pkg-dir "^4.2.0" resolve-cwd "^3.0.0" -interpret@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/interpret/-/interpret-2.2.0.tgz#1a78a0b5965c40a5416d007ad6f50ad27c417df9" - integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw== +interpret@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-3.1.1.tgz#5be0ceed67ca79c6c4bc5cf0d7ee843dcea110c4" + integrity sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ== is-arrayish@^0.2.1: version "0.2.1" @@ -1075,6 +1105,13 @@ is-core-module@^2.13.0: dependencies: hasown "^2.0.2" +is-core-module@^2.16.0: + version "2.16.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.16.1.tgz#2a98801a849f43e2add644fbb6bc6229b19a4ef4" + integrity sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w== + dependencies: + hasown "^2.0.2" + is-plain-object@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" @@ -1182,10 +1219,10 @@ neo-async@^2.6.2: resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== -node-releases@^2.0.18: - version "2.0.18" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.18.tgz#f010e8d35e2fe8d6b2944f03f70213ecedc4ca3f" - integrity sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g== +node-releases@^2.0.19: + version "2.0.19" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.19.tgz#9e445a52950951ec4d177d843af370b411caf314" + integrity sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw== object-assign@^4.1.1: version "4.1.1" @@ -1251,11 +1288,16 @@ path-type@^4.0.0: resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== -picocolors@^1.0.0, picocolors@^1.0.1: +picocolors@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.1.tgz#a8ad579b571952f0e5d25892de5445bcfe25aaa1" integrity sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew== +picocolors@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" + integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== + pkg-dir@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" @@ -1315,6 +1357,11 @@ react-is@^18.3.1: resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e" integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg== +react-is@^19.0.0: + version "19.0.0" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-19.0.0.tgz#d6669fd389ff022a9684f708cf6fa4962d1fea7a" + integrity sha512-H91OHcwjZsbq3ClIDHMzBShc1rotbfACdWENsmEf0IFvZ3FgGPtdHMcsv45bQ1hAbgdfiA8SnxTKfDS+x/8m2g== + react-lifecycles-compat@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362" @@ -1366,12 +1413,12 @@ react@^18.2.0: dependencies: loose-envify "^1.1.0" -rechoir@^0.7.0: - version "0.7.1" - resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.7.1.tgz#9478a96a1ca135b5e88fc027f03ee92d6c645686" - integrity sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg== +rechoir@^0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.8.0.tgz#49f866e0d32146142da3ad8f0eff352b3215ff22" + integrity sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ== dependencies: - resolve "^1.9.0" + resolve "^1.20.0" regenerator-runtime@^0.14.0: version "0.14.1" @@ -1395,7 +1442,7 @@ resolve-from@^5.0.0: resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== -resolve@^1.19.0, resolve@^1.9.0: +resolve@^1.19.0: version "1.22.8" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== @@ -1404,6 +1451,15 @@ resolve@^1.19.0, resolve@^1.9.0: path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" +resolve@^1.20.0: + version "1.22.10" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.10.tgz#b663e83ffb09bbf2386944736baae803029b8b39" + integrity sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w== + dependencies: + is-core-module "^2.16.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + safe-buffer@^5.1.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" @@ -1425,6 +1481,11 @@ schema-utils@^3.1.1, schema-utils@^3.2.0: ajv "^6.12.5" ajv-keywords "^3.5.2" +semver@>=7.5.2: + version "7.6.3" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" + integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== + serialize-javascript@^6.0.1: version "6.0.2" resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.2.tgz#defa1e055c83bf6d59ea805d8da862254eb6a6c2" @@ -1534,13 +1595,13 @@ undici-types@~6.13.0: resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.13.0.tgz#e3e79220ab8c81ed1496b5812471afd7cf075ea5" integrity sha512-xtFJHudx8S2DSoujjMd1WeWvn7KKWFRESZTMeL1RptAYERu29D6jphMjjY+vn96jvN3kVPDNxU/E13VTaXj6jg== -update-browserslist-db@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz#7ca61c0d8650766090728046e416a8cde682859e" - integrity sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ== +update-browserslist-db@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz#80846fba1d79e82547fb661f8d141e0945755fe5" + integrity sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A== dependencies: - escalade "^3.1.2" - picocolors "^1.0.1" + escalade "^3.2.0" + picocolors "^1.1.0" uri-js@^4.2.2: version "4.4.1" @@ -1562,22 +1623,23 @@ watchpack@^2.4.1: glob-to-regexp "^0.4.1" graceful-fs "^4.1.2" -webpack-cli@^4.8.0: - version "4.10.0" - resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-4.10.0.tgz#37c1d69c8d85214c5a65e589378f53aec64dab31" - integrity sha512-NLhDfH/h4O6UOy+0LSso42xvYypClINuMNBVVzX4vX98TmTaTUxwRbXdhucbFMd2qLaCTcLq/PdYrvi8onw90w== +webpack-cli@^5.1.4: + version "5.1.4" + resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-5.1.4.tgz#c8e046ba7eaae4911d7e71e2b25b776fcc35759b" + integrity sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg== dependencies: "@discoveryjs/json-ext" "^0.5.0" - "@webpack-cli/configtest" "^1.2.0" - "@webpack-cli/info" "^1.5.0" - "@webpack-cli/serve" "^1.7.0" + "@webpack-cli/configtest" "^2.1.1" + "@webpack-cli/info" "^2.0.2" + "@webpack-cli/serve" "^2.0.5" colorette "^2.0.14" - commander "^7.0.0" + commander "^10.0.1" cross-spawn "^7.0.3" + envinfo "^7.7.3" fastest-levenshtein "^1.0.12" import-local "^3.0.2" - interpret "^2.2.0" - rechoir "^0.7.0" + interpret "^3.1.1" + rechoir "^0.8.0" webpack-merge "^5.7.3" webpack-merge@^5.7.3: @@ -1594,21 +1656,20 @@ webpack-sources@^3.2.3: resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde" integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== -webpack@^5.55.1: - version "5.93.0" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.93.0.tgz#2e89ec7035579bdfba9760d26c63ac5c3462a5e5" - integrity sha512-Y0m5oEY1LRuwly578VqluorkXbvXKh7U3rLoQCEO04M97ScRr44afGVkI0FQFsXzysk5OgFAxjZAb9rsGQVihA== - dependencies: - "@types/eslint-scope" "^3.7.3" - "@types/estree" "^1.0.5" - "@webassemblyjs/ast" "^1.12.1" - "@webassemblyjs/wasm-edit" "^1.12.1" - "@webassemblyjs/wasm-parser" "^1.12.1" - acorn "^8.7.1" - acorn-import-attributes "^1.9.5" - browserslist "^4.21.10" +webpack@^5.97.1: + version "5.97.1" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.97.1.tgz#972a8320a438b56ff0f1d94ade9e82eac155fa58" + integrity sha512-EksG6gFY3L1eFMROS/7Wzgrii5mBAFe4rIr3r2BTfo7bcc+DWwFZ4OJ/miOuHJO/A85HwyI4eQ0F6IKXesO7Fg== + dependencies: + "@types/eslint-scope" "^3.7.7" + "@types/estree" "^1.0.6" + "@webassemblyjs/ast" "^1.14.1" + "@webassemblyjs/wasm-edit" "^1.14.1" + "@webassemblyjs/wasm-parser" "^1.14.1" + acorn "^8.14.0" + browserslist "^4.24.0" chrome-trace-event "^1.0.2" - enhanced-resolve "^5.17.0" + enhanced-resolve "^5.17.1" es-module-lexer "^1.2.1" eslint-scope "5.1.1" events "^3.2.0" From fa88313f9be6354216fcaf512d51b7c597805eab Mon Sep 17 00:00:00 2001 From: jeyasankar Date: Fri, 10 Jan 2025 08:40:59 -0800 Subject: [PATCH 02/15] Backend API works for pass phrase generation; Refactored mid layer rust calls --- src-tauri/Cargo.lock | 100 +++++- src-tauri/Cargo.toml | 6 +- src-tauri/src/app_paths.rs | 119 +++++++ .../src/{preference.rs => app_preference.rs} | 60 +++- src-tauri/src/{utils.rs => app_state.rs} | 295 ++---------------- src-tauri/src/commands.rs | 48 +-- src-tauri/src/constants.rs | 5 + src-tauri/src/file_util.rs | 48 +++ src-tauri/src/main.rs | 29 +- src-tauri/src/menu.rs | 2 +- src-tauri/src/password_gen_preference.rs | 56 ++++ src-tauri/src/translation.rs | 177 +++++++++++ src/main/onekeepass/frontend/background.cljs | 85 +---- .../frontend/background_common.cljs | 76 +++++ .../frontend/background_password.cljs | 40 +++ 15 files changed, 738 insertions(+), 408 deletions(-) create mode 100644 src-tauri/src/app_paths.rs rename src-tauri/src/{preference.rs => app_preference.rs} (83%) rename src-tauri/src/{utils.rs => app_state.rs} (53%) create mode 100644 src-tauri/src/file_util.rs create mode 100644 src-tauri/src/password_gen_preference.rs create mode 100644 src-tauri/src/translation.rs create mode 100644 src/main/onekeepass/frontend/background_common.cljs create mode 100644 src/main/onekeepass/frontend/background_password.cljs diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 198dab0..afde56f 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -543,6 +543,18 @@ dependencies = [ "cpufeatures", ] +[[package]] +name = "chbs" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45a7298287f1443f422d3f46e8ce9f855e75f0e43c06605adb4c52a262faeabd" +dependencies = [ + "derive_builder", + "getrandom 0.2.15", + "rand 0.8.5", + "thiserror 1.0.69", +] + [[package]] name = "chrono" version = "0.4.39" @@ -893,14 +905,38 @@ dependencies = [ "syn 2.0.94", ] +[[package]] +name = "darling" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f2c43f534ea4b0b049015d00269734195e6d3f0f6635cb692251aca6f9f8b3c" +dependencies = [ + "darling_core 0.12.4", + "darling_macro 0.12.4", +] + [[package]] name = "darling" version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" dependencies = [ - "darling_core", - "darling_macro", + "darling_core 0.20.10", + "darling_macro 0.20.10", +] + +[[package]] +name = "darling_core" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e91455b86830a1c21799d94524df0845183fa55bafd9aa137b01c7d1065fa36" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim 0.10.0", + "syn 1.0.109", ] [[package]] @@ -913,17 +949,28 @@ dependencies = [ "ident_case", "proc-macro2", "quote", - "strsim", + "strsim 0.11.1", "syn 2.0.94", ] +[[package]] +name = "darling_macro" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29b5acf0dea37a7f66f7b25d2c5e93fd46f8f6968b1a5d7a3e02e97768afc95a" +dependencies = [ + "darling_core 0.12.4", + "quote", + "syn 1.0.109", +] + [[package]] name = "darling_macro" version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ - "darling_core", + "darling_core 0.20.10", "quote", "syn 2.0.94", ] @@ -977,6 +1024,37 @@ dependencies = [ "syn 2.0.94", ] +[[package]] +name = "derive_builder" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d13202debe11181040ae9063d739fa32cfcaaebe2275fe387703460ae2365b30" +dependencies = [ + "derive_builder_macro", +] + +[[package]] +name = "derive_builder_core" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66e616858f6187ed828df7c64a6d71720d83767a7f19740b2d1b6fe6327b36e5" +dependencies = [ + "darling 0.12.4", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "derive_builder_macro" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58a94ace95092c5acb1e97a7e846b310cfbd499652f72297da7493f618a98d73" +dependencies = [ + "derive_builder_core", + "syn 1.0.109", +] + [[package]] name = "derive_more" version = "0.99.18" @@ -2991,8 +3069,7 @@ checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "onekeepass-core" -version = "0.16.0" -source = "git+https://github.com/OneKeePass/onekeepass-core.git?tag=v0.16.0#54298e1f21d41381037c9b62a4079c3f7be8b8e2" +version = "0.17.0" dependencies = [ "aes 0.7.5", "aes-gcm", @@ -3003,6 +3080,7 @@ dependencies = [ "botan", "cfg-if", "chacha20 0.7.3", + "chbs", "chrono", "chrono-tz", "cipher 0.3.0", @@ -3059,7 +3137,7 @@ dependencies = [ "tauri", "tauri-build", "tokio", - "toml 0.5.11", + "toml 0.8.19", "uuid", ] @@ -4463,7 +4541,7 @@ version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d00caa5193a3c8362ac2b73be6b9e768aa5a4b2f721d8f4b339600c3cb51f8e" dependencies = [ - "darling", + "darling 0.20.10", "proc-macro2", "quote", "syn 2.0.94", @@ -4759,6 +4837,12 @@ dependencies = [ "quote", ] +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + [[package]] name = "strsim" version = "0.11.1" diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 27f1854..b483b2e 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -18,7 +18,7 @@ serde = { version = "1.0", features = ["derive"] } chrono = {version = "0.4.19", features = ["serde"] } log = "0.4.17" log4rs = "1.1.1" -toml = "0.5.9" +toml = "0.8.19" once_cell = "1.18.0" secstr = "0.5.1" hex = "0.4.3" @@ -38,10 +38,10 @@ tokio = { version = "1", features = [ "time" ] } tauri = { version = "1.8.1", features = ["clipboard-all", "dialog-all", "global-shortcut-all", "path-all", "process-exit", "shell-all"] } ## using from the local crate during development -## onekeepass-core = {path = "../../onekeepass-core", version = "0.16.0"} +onekeepass-core = {path = "../../onekeepass-core", version = "0.17.0"} ## Need to use the git ref for release -onekeepass-core = {git = "https://github.com/OneKeePass/onekeepass-core.git" , tag="v0.16.0" } +## onekeepass-core = {git = "https://github.com/OneKeePass/onekeepass-core.git" , tag="v0.16.0" } [build-dependencies] tauri-build = { version = "1.5.5", features = [] } diff --git a/src-tauri/src/app_paths.rs b/src-tauri/src/app_paths.rs new file mode 100644 index 0000000..926b183 --- /dev/null +++ b/src-tauri/src/app_paths.rs @@ -0,0 +1,119 @@ +use std::{ + fs, + path::{Path, PathBuf}, +}; + +use tauri::{ + api::path::{home_dir, resolve_path, BaseDirectory}, + Env, Runtime, +}; + +use crate::file_util; + +// Should be called on app startup so that all app dirs are created +pub(crate) fn init_app_paths() { + let app_dir = app_home_dir(); + let log_dir = app_logs_dir(); + let backups_dir = app_backup_dir(); + let word_list_dir = wordlists_dir(); + + if !app_dir.exists() { + let _ = fs::create_dir_all(&app_dir); + } + + if !backups_dir.exists() { + let _ = fs::create_dir_all(&backups_dir); + } + + if !log_dir.exists() { + let _ = fs::create_dir_all(&log_dir); + } else { + // Each time we remove any old log file. + // TODO: Explore the use file rotation + let _r = file_util::remove_dir_files(&log_dir); + } + + if !word_list_dir.exists() { + if let Err(e) = fs::create_dir_all(&word_list_dir) { + log::error!( + "Creating dir {:?} failed with error: {} ", + &word_list_dir, + e + ); + } + } +} + +// IMPORTANT: unwrap() is used. What is the alternative ? +pub(crate) fn app_home_dir() -> PathBuf { + #[cfg(not(feature = "onekeepass-dev"))] + let p = home_dir() + .unwrap() + .join(Path::new(".onekeepass")) + .join(Path::new("prod")); + + // To activate this feature during development, we need to use 'cargo tauri dev -f onekeepass-dev' + #[cfg(feature = "onekeepass-dev")] + let p = home_dir() + .unwrap() + .join(Path::new(".onekeepass")) + .join(Path::new("dev")); + p +} + +// All fns getting app dir should be called only after 'init_app_paths' is called + +pub(crate) fn app_logs_dir() -> PathBuf { + app_home_dir().join("logs") +} + +pub(crate) fn app_backup_dir() -> PathBuf { + app_home_dir().join("backups") +} + +pub(crate) fn wordlists_dir() -> PathBuf { + app_home_dir().join("wordlists") +} + +#[allow(dead_code)] +pub fn create_sub_dir_path>(root_dir: P, sub: &str) -> PathBuf { + // Initialize with the root_dir itself + let mut final_full_path_dir = Path::new(root_dir.as_ref()).to_path_buf(); + + let full_path_dir = Path::new(root_dir.as_ref()).join(sub); + + if !full_path_dir.exists() { + if let Err(e) = std::fs::create_dir_all(&full_path_dir) { + // This should not happen! + log::error!( + "Directory at {} creation failed {:?}", + &full_path_dir.display(), + e + ); + } else { + // As fallback use the full_path_dir of root_dir + final_full_path_dir = full_path_dir; + } + } else { + final_full_path_dir = full_path_dir; + } + final_full_path_dir +} + +pub(crate) fn app_resources_dir(app: tauri::AppHandle) -> Result { + if let Ok(path) = resolve_path( + &app.config(), + app.package_info(), + &Env::default(), + "../resources/public/", + Some(BaseDirectory::Resource), + ) { + path + .as_path() + .to_str() + .map(|s| s.into()) + .ok_or("Could not resolve resource public dir".into()) + } else { + Err("Could not resolve resource public dir".into()) + } +} diff --git a/src-tauri/src/preference.rs b/src-tauri/src/app_preference.rs similarity index 83% rename from src-tauri/src/preference.rs rename to src-tauri/src/app_preference.rs index 56fe43f..4d87df3 100644 --- a/src-tauri/src/preference.rs +++ b/src-tauri/src/app_preference.rs @@ -3,10 +3,11 @@ use serde::{Deserialize, Serialize}; use std::fs; use crate::{ - constants::{standard_file_names::APP_PREFERENCE_FILE, themes::LIGHT}, - utils::{self, *}, + app_paths::app_backup_dir, constants::{standard_file_names::APP_PREFERENCE_FILE, themes::LIGHT}, password_gen_preference::PasswordGeneratorPreference, translation }; +use crate::app_paths::app_home_dir; + #[derive(Clone, Serialize, Deserialize, Debug)] pub struct BackupPreference { pub(crate) enabled: bool, @@ -30,17 +31,39 @@ pub struct PreferenceData { pub theme: Option, pub language: Option, } - -#[derive(Serialize, Deserialize)] +// Old preference used before introduction of fields clipboard_timeout,theme ,language +// Leaving it here for documentation purpose only +// #[derive(Serialize, Deserialize)] +// pub struct Preference1 { +// pub version: String, +// // In minutes +// pub session_timeout: u8, +// pub default_entry_category_groupings: String, //Types,Categories,Groups +// pub recent_files: Vec, +// pub backup: BackupPreference, +// } + +// Old preference used in the earlier version v0.14.0 +#[derive(Clone, Serialize, Deserialize, Debug)] pub struct Preference1 { pub version: String, // In minutes pub session_timeout: u8, - pub default_entry_category_groupings: String, //Types,Categories,Groups + // In seconds + pub clipboard_timeout: u16, + // Determines the theme colors etc + pub theme: String, + // Should be a two letters language id + pub language: String, + //Valid values one of Types,Categories,Groups,Tags + pub default_entry_category_groupings: String, + pub recent_files: Vec, + pub backup: BackupPreference, } +// Introducing 'password_gen_preference' in v0.15.0 #[derive(Clone, Serialize, Deserialize, Debug)] pub struct Preference { pub version: String, @@ -58,22 +81,25 @@ pub struct Preference { pub recent_files: Vec, pub backup: BackupPreference, + + pub password_gen_preference:PasswordGeneratorPreference, } impl Default for Preference { fn default() -> Self { Self { - // Same as in tauri.conf.json. This is for doc purpose only as - // this will be reset to the latest version from tauri.conf.json + // Same as in tauri.conf.json. This is for doc purpose only as + // this will be reset to the latest version from tauri.conf.json // after parsing the toml pref file in read_toml and pref file is updated accordingly - version: "0.14.0".into(), + version: "0.15.0".into(), session_timeout: (15 as u8), clipboard_timeout: (30 as u16), theme: LIGHT.into(), - language: utils::current_locale_language(), + language: translation::current_locale_language(), default_entry_category_groupings: "Groups".into(), recent_files: vec![], backup: BackupPreference::default(), + password_gen_preference:PasswordGeneratorPreference::default(), } } } @@ -142,13 +168,22 @@ impl Preference { fn read_previous_preference(pref_str: &str) -> Option { if let Ok(p1) = toml::from_str::(&pref_str) { - info!("Found previous version of Preference and using that"); + + // As the logging is not enabled, we will see this logging output + // info!("Found previous version of Preference and using that"); + #[cfg(feature = "onekeepass-dev")] + println!("Found previous version of Preference and using that"); + let mut p = Preference::default(); p.session_timeout = p1.session_timeout; p.backup = p1.backup; p.recent_files = p1.recent_files; p.default_entry_category_groupings = p1.default_entry_category_groupings; p.version = p1.version; + p.language = p1.language; + p.theme = p1.theme; + p.clipboard_timeout = p1.clipboard_timeout; + Some(p) } else { None @@ -189,7 +224,7 @@ impl Preference { } // Update the preference with any non null values - pub fn update(&mut self,preference_data:PreferenceData) { + pub fn update(&mut self, preference_data: PreferenceData) { let mut updated = false; if let Some(v) = preference_data.language { self.language = v; @@ -216,10 +251,9 @@ impl Preference { updated = true; } - if updated { + if updated { self.write_toml(); } - } /// Reads the previously stored preference if any and returns the newly created Preference instance diff --git a/src-tauri/src/utils.rs b/src-tauri/src/app_state.rs similarity index 53% rename from src-tauri/src/utils.rs rename to src-tauri/src/app_state.rs index 4a8a90f..c49368e 100644 --- a/src-tauri/src/utils.rs +++ b/src-tauri/src/app_state.rs @@ -9,24 +9,24 @@ use serde::{Deserialize, Serialize}; use log::info; use std::collections::HashMap; use std::fs; -use std::io; -use std::path::{Path, PathBuf}; -use std::result::Result; +use std::path::PathBuf; use std::sync::{Arc, Mutex}; -use sys_locale::get_locale; use tauri::{ - api::path::{document_dir, home_dir, resolve_path, BaseDirectory}, + api::path::{document_dir, resolve_path, BaseDirectory}, App, Env, Manager, Runtime, }; +use crate::{app_paths, file_util}; use crate::biometric; use crate::constants::standard_file_names::APP_PREFERENCE_FILE; use crate::key_secure; -use crate::preference::{Preference, PreferenceData}; - -use onekeepass_core::db_service as kp_service; +use crate::app_preference::{Preference, PreferenceData}; +use crate::translation::current_locale_language; +// IMPORTANT: +// Need to keep all state fields behind Mutex if we need to mutuate as +// we cann't get &mut self of 'AppState' pub struct AppState { // Here we're using an Arc to share memory among threads, // and the data - Preference struct - inside the Arc is protected with a mutex. @@ -80,7 +80,6 @@ impl AppState { *store_pref = pref; } - pub fn update_preference(&self, preference_data: PreferenceData) { let mut store_pref = self.preference.lock().unwrap(); store_pref.update(preference_data); @@ -103,7 +102,7 @@ impl AppState { let backup_dir_path = if let Some(pa) = &store_pref.backup.dir { PathBuf::from(pa) } else { - app_backup_dir() + app_paths::app_backup_dir() }; // Ensure that the backup dir exists. If not, there will not any backup written @@ -117,7 +116,7 @@ impl AppState { match backup_files.get(db_file_name) { Some(s) => Some(s.clone()), - None => match generate_backup_file_name(backup_dir_path, db_file_name) { + None => match file_util::generate_backup_file_name(backup_dir_path, db_file_name) { Some(v) => { backup_files.insert(db_file_name.into(), v.clone()); Some(v) @@ -172,69 +171,6 @@ impl SystemInfoWithPreference { } } -// IMPORTANT: unwrap() is used. What is the alternative ? -pub fn app_home_dir() -> PathBuf { - #[cfg(not(feature = "onekeepass-dev"))] - let p = home_dir() - .unwrap() - .join(Path::new(".onekeepass")) - .join(Path::new("prod")); - - // To activate this feature during development, we need to use 'cargo tauri dev -f onekeepass-dev' - #[cfg(feature = "onekeepass-dev")] - let p = home_dir() - .unwrap() - .join(Path::new(".onekeepass")) - .join(Path::new("dev")); - p -} - -pub fn app_logs_dir() -> PathBuf { - app_home_dir().join("logs") -} - -pub fn app_backup_dir() -> PathBuf { - app_home_dir().join("backups") -} - -fn remove_dir_contents>(path: P) -> io::Result<()> { - for entry in fs::read_dir(path)? { - fs::remove_file(entry?.path())?; - } - Ok(()) -} - -// Generates the complete backup file name for an existing database file -pub fn generate_backup_file_name(backup_dir_path: PathBuf, db_file_name: &str) -> Option { - if db_file_name.trim().is_empty() { - return None; - } - - let db_path = Path::new(db_file_name); - let parent_dir = db_path.parent().map_or_else( - || "Root".into(), - |p| p.as_os_str().to_string_lossy().to_string(), - ); - - let fname_no_extension = db_path.file_stem().map_or_else( - || "DB_FILE_NAME".into(), - |s| s.to_string_lossy().to_string(), - ); - - let n = kp_service::service_util::string_to_simple_hash(&parent_dir).to_string(); - - // The backup_file_name will be of form "MyPassword_10084644638414928086.kdbx" for - // the original file name "MyPassword.kdbx" where 10084644638414928086 is a hash of the dir part of full path - let backup_file_name = vec![fname_no_extension.as_str(), "_", &n, ".kdbx"].join(""); - - debug!("backup_file_name is {}", backup_file_name); - // Should not use any explicit / like .join("/") while joing components - backup_dir_path - .join(backup_file_name) - .to_str() - .map(|s| s.to_string()) -} - pub fn init_app(app: &App) { // An example of using Short Cut Key to use with menus and auto typing use tauri::GlobalShortcutManager; @@ -246,30 +182,14 @@ pub fn init_app(app: &App) { }); //// - let app_dir = app_home_dir(); - let log_dir = app_logs_dir(); - let backups_dir = app_backup_dir(); - - if !app_dir.exists() { - fs::create_dir_all(&app_dir).unwrap(); - } - - if !backups_dir.exists() { - fs::create_dir_all(&backups_dir).unwrap(); - } - - if !log_dir.exists() { - fs::create_dir_all(&log_dir).unwrap(); - } else { - // Each time we remove any old log file. - // TODO: Explore the use file rotation - let _r = remove_dir_contents(&log_dir); - } - + // Ensure that all app dir paths are created if required and available + app_paths::init_app_paths(); + let state = app.state::(); + // loggings still not yet setup state.read_preference(app); - init_log(&log_dir); + init_log(&app_paths::app_logs_dir()); // Now onwards all loggings calls will be effective key_secure::init_key_main_store(); @@ -279,24 +199,6 @@ pub fn init_app(app: &App) { info!("{}", "Intit app is done"); } -pub fn app_resources_dir(app: tauri::AppHandle) -> Result { - if let Ok(path) = resolve_path( - &app.config(), - app.package_info(), - &Env::default(), - "../resources/public/", - Some(BaseDirectory::Resource), - ) { - path - .as_path() - .to_str() - .map(|s| s.into()) - .ok_or("Could not resolve resource public dir".into()) - } else { - Err("Could not resolve resource public dir".into()) - } -} - // TODO Return Result> pub fn load_custom_svg_icons(app: tauri::AppHandle) -> HashMap { //IMPORTANT: @@ -342,171 +244,10 @@ pub fn read_language_selection(preference_file_content: &str) -> String { } pub fn read_preference_file() -> String { - let pref_file_name = app_home_dir().join(APP_PREFERENCE_FILE); + let pref_file_name = app_paths::app_home_dir().join(APP_PREFERENCE_FILE); fs::read_to_string(pref_file_name).unwrap_or("".into()) } -#[inline] -pub fn current_locale_language() -> String { - // "en-US" language+region - // We use the language part only to locate translation json files - let lng = get_locale().unwrap_or_else(|| String::from("en")); - - // Returns the language id ( two letters) - lng - .split("-") - .map(|s| s.to_string()) - .next() - .unwrap_or_else(|| String::from("en")) -} - -#[derive(Serialize, Deserialize)] -pub struct TranslationResource { - current_locale_language: String, - prefered_language: String, - translations: HashMap, -} - -// "../resources/public/translations" should be included in "resources" key in /desktop/src-tauri/tauri.conf.json -const TRANSLATION_RESOURCE_DIR: &str = "../resources/public/translations"; - -// Loads language translation strings for the passed language ids -// Typically it should be en and the preferedd or the locale language -pub fn load_language_translations( - app: tauri::AppHandle, - language_ids: Vec, -) -> kp_service::Result { - let current_locale_lng = current_locale_language(); //get_locale().unwrap_or_else(|| String::from("en")); // "en-US" language+region - debug!("current_locale is {}", ¤t_locale_lng); - - let state = app.state::(); - - // prefered_language as stored in Preference is either current locale language or - // language selected by user in App settings screen - let prefered_language = state.prefered_language(); - - debug!("prefered_language is {}", &prefered_language); - - let language_ids_to_load = if !language_ids.is_empty() { - language_ids - } else { - if prefered_language != "en" { - vec![String::from("en"), prefered_language.clone()] - } else { - // locale is 'en' - vec![String::from("en")] - } - }; - - //IMPORTANT: - // "../resources/public/translations" should be included in "resources" key in /desktop/src-tauri/tauri.conf.json - // Note: ../ in path will add _up_ - - let path = resolve_path( - &app.config(), - app.package_info(), - &Env::default(), - TRANSLATION_RESOURCE_DIR, - Some(BaseDirectory::Resource), - ) - .map_err(|e| { - kp_service::Error::UnexpectedError(format!( - "Resource translations dir locations not found. Error is {} ", - e - )) - })?; - - info!("Translation files root dir for i18n is {:?} ", &path); - - let mut translations: HashMap = HashMap::new(); - - for lng in language_ids_to_load { - - let p = path.join(format!("{}.json",&lng)); - //debug!("Going to load translation file {:?} ",&p); - - let data = fs::read_to_string(p) - .ok() - .map_or_else(|| "{}".to_string(), |d| d); - //let data = fs::read_to_string(p)?; - - translations.insert(lng, data); - } - - Ok(TranslationResource { - current_locale_language: current_locale_lng, - prefered_language, - translations, - }) -} - -// As this struct has only "system_menus" field, serde json deserialization -// will parse only that part of data from the file translation.json -#[derive(Debug, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct SystemMenuTranslation { - system_menus: HashMap>, -} - -impl SystemMenuTranslation { - // Gets the translated string for a main menu from "main" map - pub fn main_menu(&self, name: &str) -> String { - let d = HashMap::default(); - let s = self.system_menus.get("main").map_or_else(|| &d, |n| n); - s.get(name).map_or_else(|| name.into(), |v| v.into()) - } - - // Gets the translated string for a submenu from the "subMenus" map - pub fn sub_menu(&self, menu_id: &str, default_name: &str) -> String { - let d = HashMap::default(); - let s = self.system_menus.get("subMenus").map_or_else(|| &d, |n| n); - let sm = s - .get(menu_id) - .map_or_else(|| default_name.into(), |v| v.into()); - debug!("Submenu for menu_id {} is {}", menu_id, &sm); - sm - } -} - -// Called to load the menu string translations before building the app -pub fn load_system_menu_translations( - language: &str, - config: &tauri::Config, - package_info: &tauri::PackageInfo, -) -> SystemMenuTranslation { - let mut system_menu_tr = SystemMenuTranslation { - system_menus: HashMap::default(), - }; - - let Ok(path) = resolve_path( - &config, - &package_info, - &Env::default(), - TRANSLATION_RESOURCE_DIR, - Some(BaseDirectory::Resource), - ) else { - return system_menu_tr; - }; - - let p = path.join(format!("{}.json",&language)); - - //println!("Json file is {:?}", &p); - - let data = fs::read_to_string(p) - .ok() - .map_or_else(|| "{}".to_string(), |d| d); - - // As SystemMenuTranslation struct has only "system_menus" field, serde json deserialization - // will parse only that part of data from the file translation.json - - system_menu_tr = - serde_json::from_str::(&data).map_or(system_menu_tr, |v| v); - - //println!("Loaded system menus {:?}", system_menu_tr); - - system_menu_tr -} - fn init_log(log_dir: &PathBuf) { let local_time = Local::now().format("%Y-%m-%d-%H%M%S").to_string(); let log_file = format!("{}.log", local_time); @@ -538,11 +279,11 @@ fn init_log(log_dir: &PathBuf) { #[cfg(test)] mod tests { - use crate::utils::Preference; + use crate::app_state::Preference; use std::{collections::HashMap, fs, path::PathBuf}; use toml::Value; - use super::generate_backup_file_name; + use crate::file_util::generate_backup_file_name; #[test] fn verify_preference_reading() { let pref_file_name = "/Users/jeyasankar/.onekeepass/dev/preference.toml"; diff --git a/src-tauri/src/commands.rs b/src-tauri/src/commands.rs index ecaf75c..6c6b426 100644 --- a/src-tauri/src/commands.rs +++ b/src-tauri/src/commands.rs @@ -12,10 +12,11 @@ use std::fs::read_to_string; use std::path::Path; use uuid::Uuid; +use crate::app_state::SystemInfoWithPreference; use crate::menu::{self, MenuActionRequest, MenuTitleChangeRequest}; -use crate::utils::SystemInfoWithPreference; +use crate::{app_paths, translation}; +use crate::{app_preference, app_state}; use crate::{auto_type, biometric, OTP_TOKEN_UPDATE_EVENT}; -use crate::{preference, utils}; use onekeepass_core::async_service as kp_async_service; use onekeepass_core::db_service as kp_service; @@ -37,7 +38,7 @@ pub type Result = std::result::Result; pub(crate) async fn init_timers( _app: tauri::AppHandle, window: tauri::Window, - app_state: State<'_, utils::AppState>, + app_state: State<'_, app_state::AppState>, ) -> Result<()> { // Need to ensure, we call init_entry_channels once only and // also spawn fn should be called once @@ -114,7 +115,7 @@ pub(crate) async fn load_kdbx( db_file_name: &str, password: Option<&str>, key_file_name: Option<&str>, - app_state: State<'_, utils::AppState>, + app_state: State<'_, app_state::AppState>, ) -> Result { // key_file_name.as_deref() converts Option to Option<&str> - https://stackoverflow.com/questions/31233938/converting-from-optionstring-to-optionstr @@ -190,7 +191,7 @@ pub(crate) async fn standard_paths( ); } - match utils::app_resources_dir(app) { + match app_paths::app_resources_dir(app) { Ok(r) => { info!("Resource dir is {}", r); m.insert("resources-dir".into(), Some(r)); @@ -204,30 +205,30 @@ pub(crate) async fn standard_paths( #[tauri::command] pub(crate) async fn read_app_preference( - app_state: State<'_, utils::AppState>, -) -> Result { + app_state: State<'_, app_state::AppState>, +) -> Result { let g = app_state.preference.lock().unwrap(); Ok(g.clone()) } #[tauri::command] pub(crate) async fn system_info_with_preference( - app_state: State<'_, utils::AppState>, + app_state: State<'_, app_state::AppState>, ) -> Result { Ok(SystemInfoWithPreference::init(app_state.inner())) } #[tauri::command] pub(crate) async fn update_preference( - app_state: State<'_, utils::AppState>, - preference_data: preference::PreferenceData, + app_state: State<'_, app_state::AppState>, + preference_data: app_preference::PreferenceData, ) -> Result<()> { Ok(app_state.update_preference(preference_data)) } //clear_recent_files #[tauri::command] -pub(crate) async fn clear_recent_files(app_state: State<'_, utils::AppState>) -> Result<()> { +pub(crate) async fn clear_recent_files(app_state: State<'_, app_state::AppState>) -> Result<()> { Ok(app_state.clear_recent_files()) } @@ -253,7 +254,7 @@ pub(crate) async fn generate_key_file(key_file_name: &str) -> Result<()> { #[tauri::command] pub(crate) async fn create_kdbx( new_db: kp_service::NewDatabase, - app_state: State<'_, utils::AppState>, + app_state: State<'_, app_state::AppState>, ) -> Result { let r = kp_service::create_kdbx(new_db)?; // Appends this file name to the most recently opned file list @@ -577,7 +578,7 @@ pub(crate) async fn save_attachment_as( pub(crate) async fn save_as_kdbx( db_key: &str, db_file_name: &str, - app_state: State<'_, utils::AppState>, + app_state: State<'_, app_state::AppState>, ) -> Result { //key_secure::copy_key(db_key, db_file_name)?; @@ -598,7 +599,7 @@ pub(crate) async fn save_as_kdbx( pub(crate) async fn save_kdbx( db_key: &str, overwrite: bool, - app_state: State<'_, utils::AppState>, + app_state: State<'_, app_state::AppState>, ) -> Result { // db_key is the full database file name and backup file name is derived from that let backup_file_name = app_state.get_backup_file(db_key); @@ -617,7 +618,7 @@ pub(crate) async fn save_to_db_file(db_key: &str, full_file_name: &str) -> Resul #[tauri::command] pub(crate) async fn save_all_modified_dbs( db_keys: Vec, - app_state: State<'_, utils::AppState>, + app_state: State<'_, app_state::AppState>, ) -> Result> { // Need to prepare back file paths for all db_keys let dbs_with_backups: Vec<(String, Option)> = db_keys @@ -689,12 +690,19 @@ pub(crate) async fn search_term(db_key: &str, term: &str) -> Result Result { - Ok(kp_service::analyzed_password(password_options)?) + Ok(password_options.analyzed_password()?) +} + +#[command] +pub(crate) async fn generate_password_phrase( + password_phrase_options: kp_service::PassphraseGenerationOptions, +) -> Result { + Ok(password_phrase_options.generate()?) } #[command] pub(crate) async fn score_password(password: &str) -> Result { - Ok(kp_service::score_password(password)) + Ok(password.into()) } #[command] @@ -716,15 +724,15 @@ pub(crate) async fn export_as_xml(db_key: &str, xml_file_name: &str) -> Result<( pub async fn load_language_translations( app: tauri::AppHandle, language_ids: Vec, -) -> Result { - Ok(utils::load_language_translations(app, language_ids)?) +) -> Result { + Ok(translation::load_language_translations(app, language_ids)?) } #[tauri::command] pub async fn load_custom_svg_icons( app: tauri::AppHandle, ) -> Result> { - Ok(utils::load_custom_svg_icons(app)) + Ok(app_state::load_custom_svg_icons(app)) } // TODO: Remove this or need to clean up if required diff --git a/src-tauri/src/constants.rs b/src-tauri/src/constants.rs index 415c10a..d2e047d 100644 --- a/src-tauri/src/constants.rs +++ b/src-tauri/src/constants.rs @@ -9,6 +9,7 @@ pub mod event_action_names { pub const CLOSE_REQUESTED: &str = "CloseRequested"; } +#[allow(dead_code)] pub mod themes { pub const LIGHT: &str ="light"; pub const DARK: &str ="dark"; @@ -17,3 +18,7 @@ pub mod themes { pub mod standard_file_names { pub const APP_PREFERENCE_FILE: &str ="preference.toml"; } + +pub mod standard_dirs { + pub const BACKUP_DIR : &str = ""; +} \ No newline at end of file diff --git a/src-tauri/src/file_util.rs b/src-tauri/src/file_util.rs new file mode 100644 index 0000000..ba01c13 --- /dev/null +++ b/src-tauri/src/file_util.rs @@ -0,0 +1,48 @@ +use std::{ + fs, io, + path::{Path, PathBuf}, +}; + +use log::debug; +use onekeepass_core::db_service as kp_service; + +// Generates the complete backup file name for an existing database file +pub(crate) fn generate_backup_file_name( + backup_dir_path: PathBuf, + db_file_name: &str, +) -> Option { + if db_file_name.trim().is_empty() { + return None; + } + + let db_path = Path::new(db_file_name); + let parent_dir = db_path.parent().map_or_else( + || "Root".into(), + |p| p.as_os_str().to_string_lossy().to_string(), + ); + + let fname_no_extension = db_path.file_stem().map_or_else( + || "DB_FILE_NAME".into(), + |s| s.to_string_lossy().to_string(), + ); + + let n = kp_service::service_util::string_to_simple_hash(&parent_dir).to_string(); + + // The backup_file_name will be of form "MyPassword_10084644638414928086.kdbx" for + // the original file name "MyPassword.kdbx" where 10084644638414928086 is a hash of the dir part of full path + let backup_file_name = vec![fname_no_extension.as_str(), "_", &n, ".kdbx"].join(""); + + debug!("backup_file_name is {}", backup_file_name); + // Should not use any explicit / like .join("/") while joing components + backup_dir_path + .join(backup_file_name) + .to_str() + .map(|s| s.to_string()) +} + +pub(crate) fn remove_dir_files>(path: P) -> io::Result<()> { + for entry in fs::read_dir(path)? { + fs::remove_file(entry?.path())?; + } + Ok(()) +} diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 8a87383..40ebe2a 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -3,14 +3,18 @@ windows_subsystem = "windows" )] +mod app_paths; +mod app_preference; +mod app_state; mod auto_type; mod biometric; mod commands; mod constants; +mod file_util; mod key_secure; mod menu; -mod preference; -mod utils; +mod translation; +mod password_gen_preference; use constants::event_action_names::*; use constants::event_names::*; @@ -41,20 +45,20 @@ fn main() { // for the current prefered language from the resource dir in order to prepare Menus let context = tauri::generate_context!(); - // TODO: Reuse this preference file content in Preference::read_toml - let pref_str = utils::read_preference_file(); - let lng = utils::read_language_selection(&pref_str); + // TODO: Reuse this preference file content in Preference::read_toml + let pref_str = app_state::read_preference_file(); + let lng = app_state::read_language_selection(&pref_str); //println!("lng to use is {}", &lng); // This loaded tranalation data is passed to menus creation call (builder.menu(..)) and there they are used - // in preparing the system menu names in the current prefered language. + // in preparing the system menu names in the current prefered language. // If user changes the prefered language the app needs to be restarted. This is because - // the system menus's titles can not be changed without restarting though all sub menus's titles - // can be changed dynamically. + // the system menus's titles can not be changed without restarting though all sub menus's titles + // can be changed dynamically. let menu_translation = - utils::load_system_menu_translations(&lng, &context.config(), &context.package_info()); + translation::load_system_menu_translations(&lng, &context.config(), &context.package_info()); // let rc_dir = tauri::api::path::resource_dir(context.package_info(),&tauri::Env::default()); // println!("== Resource dir from context is {:?}",&rc_dir); @@ -64,8 +68,8 @@ fn main() { // See below let app = tauri::Builder::default() - .manage(utils::AppState::new()) - .setup(|app| Ok(utils::init_app(app))) + .manage(app_state::AppState::new()) + .setup(|app| Ok(app_state::init_app(app))) // .on_window_event(|event| match event.event() { // tauri::WindowEvent::Focused(focused) => { // if !focused { @@ -104,6 +108,7 @@ fn main() { commands::export_main_content_as_xml, commands::form_otp_url, commands::generate_key_file, + commands::generate_password_phrase, commands::get_db_settings, commands::get_entry_form_data_by_id, commands::get_group_by_id, @@ -161,7 +166,7 @@ fn main() { commands::update_entry_from_form_data, commands::update_group, commands::upload_entry_attachment, - commands:: update_preference, + commands::update_preference, ]) .build(context) .expect("error while building tauri application"); diff --git a/src-tauri/src/menu.rs b/src-tauri/src/menu.rs index 72d7f63..9b4aa13 100644 --- a/src-tauri/src/menu.rs +++ b/src-tauri/src/menu.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use crate::{constants::event_names::TAURI_MENU_EVENT, utils::SystemMenuTranslation}; +use crate::{constants::event_names::TAURI_MENU_EVENT, translation::SystemMenuTranslation}; use log::info; use onekeepass_core::db_service as kp_service; use serde::{Deserialize, Serialize}; diff --git a/src-tauri/src/password_gen_preference.rs b/src-tauri/src/password_gen_preference.rs new file mode 100644 index 0000000..bc0e426 --- /dev/null +++ b/src-tauri/src/password_gen_preference.rs @@ -0,0 +1,56 @@ +use std::{ + fs, io, + path::{Path, PathBuf}, + }; + + use log::debug; + use onekeepass_core::db_service as kp_service; +use serde::{Deserialize, Serialize}; + + use crate::app_paths; + + + #[derive(Clone, Serialize, Deserialize, Debug)] +pub(crate) struct PasswordGeneratorPreference { + phrase_generator_options: kp_service::PassphraseGenerationOptions, +} + +impl Default for PasswordGeneratorPreference { + fn default() -> Self { + Self { phrase_generator_options: Default::default() } + } +} + +impl PasswordGeneratorPreference { + // Copies the words list file to app's internal dir for later use + pub(crate) fn copy_wordlist_file>( + picked_full_file_path: P, + ) -> kp_service::Result { + let source = Path::new(picked_full_file_path.as_ref()); + let file_name = source + .file_name() + .ok_or_else(|| kp_service::Error::DataError("Wordlist file name is not found"))?; + + let target = app_paths::wordlists_dir().join(file_name); + + debug!( + "Copying picked worlist file {:?} as {:?} ", + &source, &target + ); + + fs::copy(&source, &target)?; + + debug!("Worlist file is copied"); + + Ok(target) + } + + pub(crate) fn remove_word_list_file>(full_file_path: P) { + let _ = fs::remove_file(full_file_path); + } + + pub(crate) fn word_list_deleted(file_name: &str) { + let p = app_paths::wordlists_dir().join(file_name); + Self::remove_word_list_file(&p); + } +} \ No newline at end of file diff --git a/src-tauri/src/translation.rs b/src-tauri/src/translation.rs new file mode 100644 index 0000000..239396f --- /dev/null +++ b/src-tauri/src/translation.rs @@ -0,0 +1,177 @@ +use log::debug; +use serde::{Deserialize, Serialize}; + +use log::info; +use std::collections::HashMap; +use std::fs; + +use sys_locale::get_locale; + +use tauri::{ + api::path::{resolve_path, BaseDirectory}, + Env, Manager, Runtime, +}; + +use crate::app_state::AppState; + +use onekeepass_core::db_service as kp_service; + +#[inline] +pub fn current_locale_language() -> String { + // "en-US" language+region + // We use the language part only to locate translation json files + let lng = get_locale().unwrap_or_else(|| String::from("en")); + + // Returns the language id ( two letters) + lng + .split("-") + .map(|s| s.to_string()) + .next() + .unwrap_or_else(|| String::from("en")) +} + +#[derive(Serialize, Deserialize)] +pub struct TranslationResource { + current_locale_language: String, + prefered_language: String, + translations: HashMap, +} + +// "../resources/public/translations" should be included in "resources" key in /desktop/src-tauri/tauri.conf.json +const TRANSLATION_RESOURCE_DIR: &str = "../resources/public/translations"; + +// Loads language translation strings for the passed language ids +// Typically it should be en and the preferedd or the locale language +pub fn load_language_translations( + app: tauri::AppHandle, + language_ids: Vec, +) -> kp_service::Result { + let current_locale_lng = current_locale_language(); //get_locale().unwrap_or_else(|| String::from("en")); // "en-US" language+region + debug!("current_locale is {}", ¤t_locale_lng); + + let state = app.state::(); + + // prefered_language as stored in Preference is either current locale language or + // language selected by user in App settings screen + let prefered_language = state.prefered_language(); + + debug!("prefered_language is {}", &prefered_language); + + let language_ids_to_load = if !language_ids.is_empty() { + language_ids + } else { + if prefered_language != "en" { + vec![String::from("en"), prefered_language.clone()] + } else { + // locale is 'en' + vec![String::from("en")] + } + }; + + //IMPORTANT: + // "../resources/public/translations" should be included in "resources" key in /desktop/src-tauri/tauri.conf.json + // Note: ../ in path will add _up_ + + let path = resolve_path( + &app.config(), + app.package_info(), + &Env::default(), + TRANSLATION_RESOURCE_DIR, + Some(BaseDirectory::Resource), + ) + .map_err(|e| { + kp_service::Error::UnexpectedError(format!( + "Resource translations dir locations not found. Error is {} ", + e + )) + })?; + + info!("Translation files root dir for i18n is {:?} ", &path); + + let mut translations: HashMap = HashMap::new(); + + for lng in language_ids_to_load { + let p = path.join(format!("{}.json", &lng)); + //debug!("Going to load translation file {:?} ",&p); + + let data = fs::read_to_string(p) + .ok() + .map_or_else(|| "{}".to_string(), |d| d); + //let data = fs::read_to_string(p)?; + + translations.insert(lng, data); + } + + Ok(TranslationResource { + current_locale_language: current_locale_lng, + prefered_language, + translations, + }) +} + +// As this struct has only "system_menus" field, serde json deserialization +// will parse only that part of data from the file translation.json +#[derive(Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct SystemMenuTranslation { + system_menus: HashMap>, +} + +impl SystemMenuTranslation { + // Gets the translated string for a main menu from "main" map + pub fn main_menu(&self, name: &str) -> String { + let d = HashMap::default(); + let s = self.system_menus.get("main").map_or_else(|| &d, |n| n); + s.get(name).map_or_else(|| name.into(), |v| v.into()) + } + + // Gets the translated string for a submenu from the "subMenus" map + pub fn sub_menu(&self, menu_id: &str, default_name: &str) -> String { + let d = HashMap::default(); + let s = self.system_menus.get("subMenus").map_or_else(|| &d, |n| n); + let sm = s + .get(menu_id) + .map_or_else(|| default_name.into(), |v| v.into()); + debug!("Submenu for menu_id {} is {}", menu_id, &sm); + sm + } +} + +// Called to load the menu string translations before building the app +pub fn load_system_menu_translations( + language: &str, + config: &tauri::Config, + package_info: &tauri::PackageInfo, +) -> SystemMenuTranslation { + let mut system_menu_tr = SystemMenuTranslation { + system_menus: HashMap::default(), + }; + + let Ok(path) = resolve_path( + &config, + &package_info, + &Env::default(), + TRANSLATION_RESOURCE_DIR, + Some(BaseDirectory::Resource), + ) else { + return system_menu_tr; + }; + + let p = path.join(format!("{}.json", &language)); + + //println!("Json file is {:?}", &p); + + let data = fs::read_to_string(p) + .ok() + .map_or_else(|| "{}".to_string(), |d| d); + + // As SystemMenuTranslation struct has only "system_menus" field, serde json deserialization + // will parse only that part of data from the file translation.json + + system_menu_tr = + serde_json::from_str::(&data).map_or(system_menu_tr, |v| v); + + //println!("Loaded system menus {:?}", system_menu_tr); + + system_menu_tr +} diff --git a/src/main/onekeepass/frontend/background.cljs b/src/main/onekeepass/frontend/background.cljs index 097cc35..d85304c 100644 --- a/src/main/onekeepass/frontend/background.cljs +++ b/src/main/onekeepass/frontend/background.cljs @@ -7,14 +7,17 @@ [camel-snake-kebab.extras :as cske] [camel-snake-kebab.core :as csk] [onekeepass.frontend.utils :refer [contains-val?]] + + [onekeepass.frontend.background-common :as bg-cmn] + [onekeepass.frontend.background-password :as bg-pwd] ;; All tauri side corresponding endpoint command apis can be found in - ;; https://github.com/tauri-apps/tauri/blob/tauri-v1.5.0/core/tauri/src/endpoints + ;; https://github.com/tauri-apps/tauri/tree/tauri-v1.8.1/core/tauri/src/endpoints ;; The api implementation is in - ;; https://github.com/tauri-apps/tauri/tree/tauri-v1.5.0/core/tauri/src/api - + ;; https://github.com/tauri-apps/tauri/tree/tauri-v1.8.1/core/tauri/src/api + ["@tauri-apps/api/dialog" :refer (open,save)] - ["@tauri-apps/api/tauri" :refer (invoke)] + #_["@tauri-apps/api/tauri" :refer (invoke)] ["@tauri-apps/api/clipboard" :refer [writeText readText]] ["@tauri-apps/api/event" :as tauri-event] ["@tauri-apps/api/shell" :as tauri-shell] @@ -26,62 +29,11 @@ (set! *warn-on-infer* true) -(defn invoke-api - "Invokes the backend command API calls using the tauri's 'invoke' command. - Args - 'name' is the tauri command name - 'api-args' is the argument map that is passed to the tauri command. The args must be serializable by the tauri API. - 'dispatch-fn' is a function that will be called when the tauri command call's promise is resolved or in error. - The call back function 'distach-fn' should accept a map (keys are :result, :error) as input arg +(def invoke-api bg-cmn/invoke-api) - IMPORTANT: If the returned value is a string instead of a map or any other type - and we want the string as {:result \"some string value\"}, then we need to pass :convert-response false - " - [name api-args dispatch-fn & - {:keys [convert-request convert-response convert-response-fn] - :or {convert-request true convert-response true}}] - (go - (try - (let [;; when convert-request is false, the api-args is assumed to be a js object - ;; that can deserialized to Rust names and types as expected by the 'command' api - ;; When convert-request is true, the api args are converted to 'camelCaseString' as expected by tauri command fns - ;; so that args can be deserialized to tauri types - ;; When convert-request is true and api-args is a js object, (cske/transform-keys csk/->camelCaseString) - ;; does not make any changes as expected to be in a proper deserilaizable format - args (if convert-request - ;; changes all keys to camelCase (e.g db-key -> dbKey) - ;; Tauri expects all API arguments names passed in JS api to be in camelCase which - ;; are in turn deserialized as snake_case to match rust argument names used in - ;; tauri commands. - ;; Note - ;; Only the api argument names are expected to be in camelCase. The keys of value passed are not changed to cameCase - ;; and they deserialized by the the corresponding struct serde definition. As result, mostly convert-request = false - (->> api-args (cske/transform-keys csk/->camelCaseString) clj->js) - api-args) - r ( r js->clj convert-response-fn) ;; custom transformer of response - - (and convert-response (string? r)) - (csk/->kebab-case-keyword r) - - convert-response - (->> r js->clj (cske/transform-keys csk/->kebab-case-keyword)) - - ;; No conversion is done and just js->clj - :else - (js->clj r))}) - ;; Just to track db modifications if any - (dispatch [:common/db-api-call-completed name])) - (catch js/Error err - (do - ;;Call the dispatch-fn with any error returned by the backend API - (dispatch-fn {:error (ex-cause err)}) - (js/console.log (ex-cause err))))))) +(def analyzed-password bg-pwd/analyzed-password) + +(def score-password bg-pwd/score-password) (def ^:private tauri-event-listeners "This is a map where keys are the event name (kw) values tauri listeners" (atom {})) @@ -581,21 +533,6 @@ [db-key entry-type-uuid dispatch-fn] (invoke-api "delete_custom_entry_type" {:db-key db-key :entry-type-uuid entry-type-uuid} dispatch-fn)) -(defn analyzed-password - "Generates a password with the given options and returns the - generated password with its analysis" - [password-options dispatch-fn] - (invoke-api "analyzed_password" - (clj->js - {:passwordOptions - (->> password-options - (cske/transform-keys csk/->snake_case))}) - dispatch-fn - :convert-request false)) - -(defn score-password [password dispatch-fn] - (invoke-api "score_password" {:password password} dispatch-fn)) - (defn parse-auto-type-sequence [sequence entry-fields dispatch-fn] (let [api-args {:sequence sequence :entryFields entry-fields}] diff --git a/src/main/onekeepass/frontend/background_common.cljs b/src/main/onekeepass/frontend/background_common.cljs new file mode 100644 index 0000000..3f050a6 --- /dev/null +++ b/src/main/onekeepass/frontend/background_common.cljs @@ -0,0 +1,76 @@ +(ns onekeepass.frontend.background-common + (:require + [re-frame.core :refer [dispatch]] + [cljs.core.async :refer [go]] + [cljs.core.async.interop :refer-macros [camelCaseString) + ;; does not make any changes as expected to be in a proper deserilaizable format + args (if convert-request + ;; changes all keys to camelCase (e.g db-key -> dbKey) + ;; Tauri expects all API arguments names passed in JS api to be in camelCase which + ;; are in turn deserialized as snake_case to match rust argument names used in + ;; tauri commands. + ;; Note + ;; Only the api argument names are expected to be in camelCase. The keys of value passed are not changed to cameCase + ;; and they deserialized by the the corresponding struct serde definition. As result, mostly convert-request = false + (->> api-args (cske/transform-keys csk/->camelCaseString) clj->js) + api-args) + r ( r js->clj convert-response-fn) ;; custom transformer of response + + (and convert-response (string? r)) + (csk/->kebab-case-keyword r) + + convert-response + (->> r js->clj (cske/transform-keys csk/->kebab-case-keyword)) + + ;; No conversion is done and just js->clj + :else + (js->clj r))}) + ;; Just to track db modifications if any + (dispatch [:common/db-api-call-completed name])) + (catch js/Error err + (do + ;;Call the dispatch-fn with any error returned by the backend API + (dispatch-fn {:error (ex-cause err)}) + (js/console.log (ex-cause err))))))) diff --git a/src/main/onekeepass/frontend/background_password.cljs b/src/main/onekeepass/frontend/background_password.cljs new file mode 100644 index 0000000..445c939 --- /dev/null +++ b/src/main/onekeepass/frontend/background_password.cljs @@ -0,0 +1,40 @@ +(ns onekeepass.frontend.background-password + (:require + [camel-snake-kebab.extras :as cske] + [camel-snake-kebab.core :as csk] + [onekeepass.frontend.background-common :as bg-cmn :refer [invoke-api]])) + + +(defn analyzed-password + "Generates a password with the given options and returns the + generated password with its analysis" + [password-options dispatch-fn] + ;; passwordOptions should be in camelCase as it is the tauri command fn arg + ;; However we use 'snake_case' to deserialize the struc 'PasswordGenerationOptions' + (invoke-api "analyzed_password" + (clj->js + {:passwordOptions + (->> password-options + (cske/transform-keys csk/->snake_case))}) + dispatch-fn + :convert-request false)) + +(defn score-password [password dispatch-fn] + (invoke-api "score_password" {:password password} dispatch-fn)) + +(defn generate-password-phrase [password-phrase-options dispatch-fn] + (invoke-api "generate_password_phrase" + (clj->js {:passwordPhraseOptions + (->> password-phrase-options + (cske/transform-keys csk/->snake_case))}) + dispatch-fn :convert-request false)) + + +(comment + (-> @re-frame.db/app-db keys) + (def db-key (:current-db-file-name @re-frame.db/app-db)) + (-> @re-frame.db/app-db (get db-key) keys) + (-> (get @re-frame.db/app-db db-key) :entry-form-data) + ;;{:name "EFFLarge"} + (def a {:word-list-source {:name "EFFShort2"} :words 5 :separator "-" :capitalize-first {:type-name "Always"} :capitalize-words {:type-name "Never"}}) + ) \ No newline at end of file From c361a01c468db595939c9d3d80dd364634a73741 Mon Sep 17 00:00:00 2001 From: jeyasankar Date: Mon, 13 Jan 2025 16:53:27 -0800 Subject: [PATCH 03/15] Base UI works for pass phrase options; Callback support added to load wordlist from app's resource dir --- .../wordlists/french-diceware-wordlist.txt | 7776 +++++++++++++++++ .../wordlists/german-diceware-wordlist.txt | 7776 +++++++++++++++++ ...gle-10000-english-usa-no-swears-medium.txt | 5460 ++++++++++++ src-tauri/Cargo.lock | 27 +- src-tauri/src/app_state.rs | 159 +- src-tauri/src/callback_service_provider.rs | 56 + src-tauri/src/main.rs | 1 + src-tauri/tauri.conf.json | 3 +- .../frontend/background_password.cljs | 7 +- .../frontend/common_components.cljs | 110 +- .../frontend/entry_form/dialogs.cljs | 7 +- .../frontend/entry_form/fields.cljs | 4 +- .../onekeepass/frontend/entry_form_ex.cljs | 2 + .../onekeepass/frontend/events/common.cljs | 10 +- .../frontend/events/password_generator.cljs | 126 +- .../frontend/password_generator.cljs | 445 +- 16 files changed, 21702 insertions(+), 267 deletions(-) create mode 100755 resources/public/wordlists/french-diceware-wordlist.txt create mode 100644 resources/public/wordlists/german-diceware-wordlist.txt create mode 100644 resources/public/wordlists/google-10000-english-usa-no-swears-medium.txt create mode 100644 src-tauri/src/callback_service_provider.rs diff --git a/resources/public/wordlists/french-diceware-wordlist.txt b/resources/public/wordlists/french-diceware-wordlist.txt new file mode 100755 index 0000000..c0d137c --- /dev/null +++ b/resources/public/wordlists/french-diceware-wordlist.txt @@ -0,0 +1,7776 @@ +=== +== += +--- +-- +- +; +:-( +:-) +:( +:) +: +!!! +!! +! +??? +?? +? +"""" +() +( +) +@ +$$$ +$$ +$ +*** +** +* +& +### +## +# +%%% +%% +% ++++ +++ ++ + +0 +1 +10 +100 +1000 +101 +11 +111 +1111 +12 +123 +1234 +13 +14 +1492 +15 +1500 +16 +1600 +17 +1700 +18 +1800 +19 +1900 +1910 +1920 +1925 +1930 +1935 +1940 +1945 +1950 +1955 +1960 +1965 +1970 +1975 +1980 +1985 +1990 +1991 +1992 +1993 +1994 +1995 +1996 +1997 +1998 +1999 +2 +20 +200 +2000 +2001 +2002 +2003 +2004 +2005 +2006 +2007 +2008 +2009 +2010 +2015 +2020 +2030 +2035 +2040 +2045 +2050 +21 +22 +222 +2222 +23 +234 +2345 +24 +2468 +25 +26 +27 +28 +29 +3 +30 +300 +3000 +31 +32 +33 +333 +3333 +34 +345 +3456 +35 +36 +37 +38 +39 +4 +40 +400 +4000 +41 +42 +43 +4321 +44 +444 +4444 +45 +456 +4567 +46 +47 +48 +49 +5 +50 +500 +5000 +51 +52 +53 +54 +55 +555 +5555 +56 +567 +5678 +57 +58 +59 +6 +60 +600 +6000 +61 +62 +63 +64 +65 +66 +666 +6666 +67 +678 +6789 +68 +69 +7 +70 +700 +7000 +71 +72 +73 +74 +75 +76 +77 +777 +7777 +78 +789 +79 +8 +80 +800 +8000 +81 +82 +83 +84 +85 +86 +87 +88 +888 +8888 +89 +9 +90 +900 +9000 +91 +92 +93 +94 +95 +96 +97 +98 +9876 +99 +999 +9999 +a +aa +aaa +aaaa +ab +abaque +abat +abatee +abbaye +abbe +abc +abces +abject +aboi +abois +abord +abot +about +abri +abrupt +absent +abside +absolu +abus +abusif +abysse +ac +acabit +acacia +acajou +acarus +acaule +accent +acces +accise +accord +accort +accot +accroc +accu +ace +acerbe +achat +acheen +acide +acier +acini +acinus +acme +acne +acon +aconit +acore +acquit +acre +acte +acteur +actif +action +active +actuel +acuite +ad +adage +adagio +adent +adepte +adieu +adne +adnee +adonis +ados +adret +adroit +adulte +ae +aede +aequo +aerien +af +affect +affete +affide +affin +affine +affixe +afflux +affres +afghan +afin +afocal +afro +ag +agami +agape +agaric +agate +agave +agence +agenda +agent +agha +agile +agio +agnat +agneau +agora +agouti +agres +agrile +agrion +agrume +aguets +agui +ah +ahan +ai +aiche +aide +aigle +aiglon +aigre +aigu +ail +aile +ailee +ailier +aine +ainsi +air +airain +airbus +aire +ais +aise +aisee +aisy +aj +ajonc +ajour +ajout +ak +al +alaire +alaise +alarme +albedo +albite +albugo +album +alcade +alcali +alcene +alcool +alcyne +alcyon +aldin +aldine +aldol +ale +alea +aleph +alerte +alevin +alezan +alfa +algide +algie +algine +algol +algue +alias +alibi +alinea +alios +alise +alisme +alize +allant +allene +aller +allure +allyle +almee +aloes +alogie +aloi +alors +alose +aloyau +alpaga +alpage +alpax +alpe +alpha +alpin +alpine +altier +altise +alto +alun +alvin +alvine +alyte +am +amadou +amande +amant +amante +amaril +amarre +amas +ambigu +ambon +ambre +amen +amende +amer +amere +ami +amibe +amical +amict +amide +amidon +amie +amine +aminee +amiral +amitie +amnios +amont +amoral +amorce +amour +ampere +amphi +ample +ampli +amusie +amyle +an +ana +anal +anale +ananas +anche +ancien +ancre +andain +andin +andine +aneth +ange +angine +angle +anglet +angon +angor +angora +animal +anion +anis +annal +annale +anneau +annee +annexe +annone +annuel +anode +anodin +anomal +anomie +anorak +anoure +anse +ansee +antan +ante +antre +anurie +anus +ao +aorte +ap +apache +aparte +apex +aphone +aphte +api +apical +apiol +apion +aplat +aplomb +apnee +apode +apogee +aporie +appas +appeau +appel +apport +appui +apres +apside +apte +aptere +aq +aqueux +ar +ara +arabe +arable +araire +aramon +arbre +arc +arcade +arcane +arceau +archal +arche +archer +archet +arcure +ardent +ardeur +ardu +ardue +are +arec +arene +areole +argas +argent +argile +argon +argot +argus +aria +aride +arien +arille +arioso +armada +arme +armet +armon +armure +arnica +aronde +arpege +arpent +arpete +arpion +arrhes +arrobe +arroyo +ars +arsin +arsine +art +artel +artere +arum +aryen +aryle +as +ascese +ascete +ascite +asexue +ashram +asile +aspe +aspect +aspic +asque +assai +assaut +asse +assez +assidu +astate +aster +asthme +asti +astral +astre +astuce +at +ataxie +atele +athee +atlas +atoll +atome +atonal +atone +atonie +atour +atours +atout +atrium +atroce +au +aubade +aube +aubere +aubier +aubin +auburn +aucuba +aucun +aucune +audace +audio +audit +auge +auget +augure +aulne +aune +aupres +auquel +aurige +aurore +aussi +autant +autel +auteur +auto +autour +autre +autrui +auvent +auxine +av +aval +avance +avanie +avant +avare +avarie +avatar +avec +aven +avenir +avenu +avenue +avers +averse +aveu +avide +avion +aviron +avis +aviso +avocat +avoine +avril +aw +ax +axe +axile +axiome +axis +axone +axonge +ay +az +azalee +azimut +azote +azotee +azur +azure +azygos +azyme +b +baba +babil +babine +baby +bac +bachot +bacon +bacul +badge +badine +baffer +baffle +bagad +bagage +bagne +bagou +bagout +bague +baguer +bah +bahut +baie +bail +bailli +bain +baiser +bajoue +bal +balade +balai +balane +balata +balcon +bales +ballet +ballon +ballot +balsa +balte +bambin +bambou +ban +banale +banane +banc +banche +banco +bander +bandit +bang +banian +banjo +banlon +banner +bannir +banque +baobab +baquet +bar +baraka +barbe +barber +barbet +barbon +barbue +bard +barder +bardis +bardot +bareme +barge +baril +barman +barmen +barn +baroud +barouf +barque +barrer +barrot +barye +baryon +baryte +baryum +bas +basale +basane +base +baser +basic +baside +basin +basket +basque +basse +basset +bassin +basson +baste +bastos +bateau +bath +batik +batte +battee +battre +baud +baudet +bauge +bauger +baume +baux +bavoir +bavure +bayou +bazar +bb +bbb +bbbb +bc +bcd +bd +be +beagle +beance +beante +beate +beau +beauf +beaute +bebe +be-bop +bec +becane +becot +becter +bedane +bedeau +bedon +bee +begu +begue +begum +beige +beigne +beke +bel +belge +belier +belle +belon +belote +beluga +bemol +ben +benef +benin +benir +benite +benne +benzol +bequer +ber +bercer +beret +berge +berlue +berme +berner +beryl +besace +besant +besef +besoin +betail +betel +beton +bette +betyle +beur +beurre +bevue +bey +bf +bg +bh +bi +biais +bibi +bibine +bible +bic +biceps +biche +bichof +bicot +bide +bident +bidet +bidon +bidule +bief +bielle +bien +biere +biface +biffer +biffin +bifide +bigame +bigler +bigote +bigre +bigue +bijou +bikini +bilame +bilan +bile +biler +bill +bille +billet +billon +billot +bimane +binage +binard +biner +bingo +biniou +bipale +bipede +bipied +biplan +bique +birbe +bireme +bis +bise +biseau +biser +biset +bison +bisou +bisque +bisser +bistre +bistro +bit +biter +bitord +bitos +bitter +bitume +biveau +bizut +bj +bk +bl +blabla +black +blair +blanc +blaser +blason +blatte +blazer +ble +bleche +bled +blende +bleser +blette +bleue +bleuet +bleuir +bloc +blocus +blonde +blouse +blues +bluff +bluter +bm +bn +bo +boa +bob +bobard +bobo +bocage +bocal +bocard +bocaux +boche +bock +boeuf +bof +boghei +bogie +bogue +boheme +boille +boire +bois +boiser +boite +bol +boldo +bolduc +bolee +bolero +bolet +bolide +bolier +bombe +bombee +bomber +bombyx +bonace +bonbon +bonde +bondee +bonder +bondon +boni +bonite +bonne +bonnet +bonte +bonus +bonze +boom +boots +bop +bora +borate +borax +bord +bordel +border +bore +borgne +borner +bort +bosco +boss +bosse +bosser +bossue +boston +bote +botter +bottin +boubou +bouc +boucan +boucau +bouder +boudin +boue +bouee +boueur +bouger +bougie +bougre +bouif +boule +bouler +boulin +boulon +boum +bourbe +bourg +bourse +bouse +bousin +bout +bouter +bouton +boutre +bouvet +bovide +bovin +box +boxe +boxer +boxeur +boy +boyard +boyau +bp +bq +br +bradel +brader +brai +braise +brame +bramer +bran +brande +brandy +branle +brante +bras +braser +braver +bravo +brayer +break +brebis +breche +brelan +breler +breme +bresil +breton +breve +brevet +briard +bribes +bric +brick +brider +bridge +bridon +brie +brifer +brimer +brin +brio +bris +brise +briser +brisis +briska +broc +broder +brome +bronze +brook +brou +brouet +broum +brout +broyer +brrr +bru +bruant +bruche +bruine +bruir +bruit +brume +brunch +brune +brunir +brute +bryone +bs +bt +bu +bubale +bubon +buccin +budget +buee +buffet +buffle +buggy +bugle +buire +buis +bulbe +bulle +buna +bunker +bure +bureau +burgau +burin +buron +busard +busc +buse +bush +bushes +buste +but +butane +buter +buteur +butin +butoir +butome +butor +butte +butter +buvard +buvee +bv +bw +bx +by +bye +byssus +bz +c +cab +cabale +caban +cabane +cabas +cabiai +cabine +cabot +cabrer +cabri +cabus +caca +cacao +cacher +cachet +cachot +cachou +cactus +caddie +caddy +cade +cadeau +cadi +cadmie +cadran +cadrat +cadrer +caduc +caecum +cafard +cafe +cafre +caftan +cafter +cage +cageot +caget +cagibi +cagote +cahier +cahot +cahute +cairn +caisse +cajou +cajun +cake +cal +calage +calame +calao +calcin +calcul +caler +calf +calfat +calice +calier +calife +calmar +calmer +calo +calot +calter +calva +camail +came +camee +camera +camion +camp +camper +campos +campus +camus +canada +canal +canape +canard +canari +canaux +cancan +cancel +cancer +canche +cancre +candir +cane +cangue +canif +canine +canna +canne +canner +canon +canope +canot +cantal +canter +canton +cantre +canule +canut +canyon +caoua +cap +cape +capot +cappa +capron +captal +capter +capuce +caquer +caquet +car +carabe +caraco +carafe +carat +carcan +carcel +cardan +carder +cardia +cardon +carene +carex +cargo +cari +carie +carier +carmer +carmin +carne +carnee +carnet +carpe +carre +carrer +carry +carte +cartel +carter +carton +cas +casbah +caser +cash +casher +casier +casino +casoar +casque +casser +cassis +casson +caste +castel +castor +catch +cati +catin +cation +cauri +cauris +causer +causse +cavale +caveau +caver +cavet +caviar +cavite +cb +cc +ccc +cccc +cd +cde +ce +ceans +ceci +cecite +ceder +cedex +cedrat +cedre +cedule +celer +celeri +cella +celle +celte +celui +cement +cendre +cene +cens +censee +cent +cenure +cep +cepage +cepe +cerame +cerat +cerce +cerf +cerise +cerite +cerium +cerner +certes +ceruse +cesar +cesium +cesser +ceste +cesure +cet +cetace +cetane +cetera +cetone +cette +ceux +cf +cg +ch +chabot +chacal +chacun +chah +chahut +chai +chaire +chaise +chalet +chalut +champ +champi +chance +change +chant +chaos +chape +chapee +chapon +chaque +char +charte +chas +chaste +chaton +chatte +chaude +chauve +chaux +chebec +cheche +cheffe +cheik +cheikh +cheire +chelem +chemin +chenal +chenet +chenil +chenue +cheque +chere +cherie +cherif +cherir +cherot +cherte +cheval +chevet +cheveu +chevre +chez +chic +chiche +chichi +chicon +chicot +chier +chiffe +chiite +chimie +chinee +chiner +chintz +chiot +chiper +chipie +chips +chique +chiton +chiure +chlore +choc +choeur +choix +chope +choper +choree +chorus +chose +chott +chou +chouan +choyer +christ +chrome +chromo +chrono +chut +chuter +chyle +chyme +ci +ciao +cible +cicero +cidre +ciel +cierge +cieux +cigale +cigare +cil +cilice +ciliee +ciller +cime +ciment +cimier +cincle +cine +cinema +cinq +cipaye +cippe +cirage +cirer +ciron +cirque +cirre +cirrus +ciseau +ciste +cistre +citer +citron +citrus +civile +cj +ck +cl +clabot +clade +claie +claire +clam +clamer +clamp +clan +clande +clapet +clarte +clause +claver +clayon +cle +clebs +clef +clerc +clerge +clic +cliche +climat +clin +clip +clique +cliver +cloche +clodo +clone +clope +cloque +clore +close +clou +clouer +clown +club +cluse +cm +cn +co +coach +coati +cobalt +cobaye +cobea +cobol +cobra +coca +coccyx +cocher +cocker +coco +cocon +cocu +codage +coder +codex +codon +coeur +coffin +cogito +cognac +cognat +cogner +cohue +coi +coin +coing +coite +coke +col +cola +colere +colin +colis +colite +coller +collet +colley +colt +colza +coma +combat +combe +comete +comice +comics +comite +comma +comme +compas +comput +comte +con +conde +condom +condor +confer +conga +conge +congre +conque +consul +conte +conter +convoi +cool +coolie +copain +copal +copeau +copier +copra +coprah +copte +coq +coque +coquer +cor +corail +coran +coraux +corbin +corder +cordon +cornac +corner +cornue +coron +corozo +corps +corpus +corral +corser +corset +cortex +corvee +coryza +cosmos +cossue +cosy +coteau +coter +cotir +coton +cotte +cou +couac +coucou +couder +couic +couler +coulis +coup +coupe +couper +coupon +cour +courge +course +courte +coutil +coutre +couver +coxale +coyau +coyote +cp +cq +cr +crabe +crabot +crac +crack +cracra +crado +craie +crambe +cramer +crampe +cran +craner +crase +crash +crave +crawl +crayon +credit +credo +creer +creme +crener +creole +crepir +crepon +crepue +creuse +creve +crever +cri +cric +cricri +crier +crime +crin +crique +crise +croate +croc +crocus +croire +croix +cross +crosse +croupe +cruche +crypte +cs +ct +cu +cubage +cube +cuber +cuesta +cuir +cuisse +cul +culer +culex +culot +culte +cumin +cumul +cupide +cupule +curage +curare +cure +curer +curium +curry +cursus +curule +cutine +cutter +cuvage +cuveau +cuver +cuvier +cv +cw +cx +cy +cyan +cycas +cycle +cygne +cynips +cypres +cyprin +cytise +cz +czar +d +dada +dadais +dague +daguer +daguet +dahir +dahlia +daim +daine +dais +daleau +daller +dalot +dalton +dam +damage +daman +dame +damer +damier +damner +dan +dandin +dandy +danger +danser +daphne +darce +dard +darder +darne +darse +dartre +datage +datcha +dater +dation +dative +datte +datura +daube +dauber +davier +db +dc +dd +ddd +dddd +de +dealer +debet +debile +debit +deblai +debord +debout +debris +debut +deca +decade +decadi +decan +deces +deche +dechet +deci +decile +declic +declin +decor +decote +decret +decri +dedain +dedale +dedans +dedier +dedire +deesse +def +defaut +defi +defier +degel +degre +dehors +deisme +deiste +deite +delai +delco +delice +delier +delit +delot +delta +deluge +demain +deme +demie +demon +dengue +deni +denier +denree +dense +dent +dentee +denuee +denuer +dep +depart +depens +depit +deport +depuis +der +derby +derme +derny +des +design +desir +desman +dessin +dessus +destin +detail +detors +detour +dette +deuil +deux +devant +devers +devier +devin +devis +devoir +devot +devote +dextre +dey +df +dg +dh +di +dia +diable +diacre +diane +diapo +diaule +dico +dicter +dicton +didyme +diese +diesel +diete +dieu +diffa +diffus +digit +digne +digon +digue +diktat +diluer +dinar +dinde +dindon +ding +dinghy +dingo +diode +dionee +dipode +dirham +dirhem +disco +dispos +disque +dito +diurne +div +diva +divan +divine +divise +dix +dizain +dj +djinn +dk +dl +dm +dn +do +docile +dock +docker +docte +dodine +dodo +dodue +doge +dogger +dogme +dogue +doigt +doigte +dol +dolce +doleau +doler +dolic +doline +dollar +dolman +dolmen +dom +domino +don +donc +dondon +donjon +donner +dont +dopage +doper +doping +dorade +dorage +dorer +doris +dorure +dosage +dose +doser +doseur +dosse +dot +dotale +doter +douane +douar +douce +douche +doucin +doucir +douee +douer +doum +douro +douter +douve +douze +dp +dq +dr +dragee +dragon +drain +drame +drap +draper +drave +drayer +drege +drelin +drenne +drill +drille +dring +drink +drisse +driver +drogue +droite +dronte +drop +droper +drue +druide +drupe +dry +dryade +ds +dt +du +duale +duc +ducale +ducat +duce +duche +duegne +duel +duetto +dugong +duit +duite +dulie +dundee +dune +duo +duodi +duper +duplex +duquel +dur +durant +durcir +duree +durete +durion +durit +duvet +dv +dw +dx +dy +dyade +dynamo +dz +e +eau +eb +ebat +ebene +eburne +ec +ecang +ecart +eche +echec +echine +echo +eclair +eclat +ecluse +ecole +ecorce +ecot +ecote +ecotee +ecoute +ecran +ecrin +ecrou +ecru +ecrue +ecu +ecueil +ecume +ecurie +ecuyer +eczema +ed +edam +eden +edile +edit +ee +eee +eeee +ef +efendi +effet +effort +effroi +efg +eg +egal +egale +egard +egeen +egerie +egide +eglise +Église +ego +egout +eh +ehonte +ei +eider +ej +ek +el +elaeis +elan +elave +elavee +elbeuf +elbot +elegie +eleis +eleve +elfe +elite +elixir +elle +elodee +eloge +elusif +elytre +em +emacie +email +embase +embout +eme +emeri +emeu +emeute +emir +emirat +emoi +emotif +emou +empan +emploi +empois +emport +empuse +emule +en +en-but +encan +encart +en-cas +encas +encens +enclin +encore +encre +endive +endos +enduro +enfant +enfer +enfeu +enfin +engin +enieme +enigme +enjeu +ennemi +ennui +enorme +entier +entite +entoir +entour +entre +entree +enture +envers +envie +envine +envoi +envol +enzyme +eo +eocene +eolien +eon +eosine +ep +epacte +epair +epais +epar +epars +eparse +epaule +epave +epee +epeire +eperdu +eperon +ephebe +ephod +ephore +epi +epiage +epice +epicea +epieu +epieur +epige +epigee +epine +epique +epite +eplore +epode +eponte +epopee +epoque +epouse +epulie +epulis +epulon +epurge +eq +equide +equin +equine +equipe +equite +er +erable +erbine +erbium +ere +erg +ergot +erigne +erine +ermite +eros +erosif +errata +erreur +errone +ersatz +erseau +erudit +es +escale +escape +escot +escroc +escudo +espace +espada +espar +espece +espion +espoir +esprit +esquif +essai +essaim +essart +esse +essieu +essor +est +ester +estime +estoc +estran +et +etable +etage +etai +etain +etal +etalon +etang +etape +etat +etau +etaux +etc +ete +eteuf +eteule +ethane +ether +ethere +ethnie +ethuse +ethyle +etiage +etier +etique +etisie +etoc +etoffe +etoile +etole +etoupe +etrave +etrier +etrive +etroit +etron +etude +etui +etuve +etymon +eu +euh +euro +eux +ev +evasif +eveil +event +evier +evohe +evzone +ew +ex +exact +exacte +examen +exces +excuse +exedre +exempt +exigu +exil +exit +exocet +exode +exorde +expert +expres +exquis +extase +extra +ey +ez +f +fable +face +facho +facies +facile +facto +factum +fade +fader +fadeur +fading +fado +fafiot +fagne +fagot +faible +faim +faisan +fakir +falote +falun +falzar +famee +famine +fanage +fanal +faner +fange +fanion +fanon +faon +faquin +far +farad +farce +farcin +farcir +fard +farder +farine +faro +fart +farter +fascee +fascia +faste +fat +fatale +fatma +fatras +fatum +fauber +faucon +faucre +faufil +faune +faute +fauve +faux +favela +faveur +favori +favus +fax +faxer +fayard +fayot +fb +fc +fd +fe +feale +fecale +fecial +fecule +fee +feerie +felide +feline +fellah +femme +femur +fendre +fenil +fennec +fente +fenton +fer +fera +feriee +ferler +fermer +feroce +ferrer +ferret +ferry +ferue +ferule +fesser +fessue +festin +feston +fetide +fetu +feu +feue +feuil +feve +fevier +fez +ff +fff +ffff +fg +fgh +fh +fi +fiable +fiacre +fiasco +fiat +fibre +fibule +fic +fichet +ficus +fidele +fief +fiel +fier +fiere +fierte +fiesta +fieu +fievre +fifre +fig +figaro +figer +figue +fil +filage +filer +filet +filin +fille +film +filmer +filon +filou +finage +finale +fine +finir +finish +fiole +fion +firman +firme +fisc +fiston +fistot +fixage +fixer +fixing +fixite +fj +fjeld +fjord +fk +fl +fla +flac +flache +flacon +flair +flamme +flan +flanc +flapie +flaque +flash +fleau +fleche +flegme +flein +flemme +fleole +fletan +flette +fleur +fleuve +flic +flint +flipot +flirt +floc +floche +flocon +flood +flop +flopee +flore +flores +florin +flot +floue +flouer +flouve +flouze +fluage +fluate +fluide +fluor +flush +flux +fluxer +fm +fn +fo +foc +focale +foehn +foetus +foie +foin +foire +foison +fol +folie +foliee +folio +foliot +folk +folle +follet +foncer +fonder +fondre +fongus +fonte +fontis +foot +for +forage +forban +forcer +forer +foret +forger +forint +format +former +formol +forte +fortin +forum +forure +fosse +fou +fouace +fouage +foudre +fouee +fouet +foufou +fougue +fouine +fouir +fouler +foulon +four +fourbe +fourme +fourmi +fovea +fox +foxee +foyer +fp +fq +fr +frac +fracas +fragon +frai +framee +franc +franco +frange +frape +frasil +frater +frayer +frein +frelon +freon +frere +frerot +fret +freter +fretin +freux +fric +friche +fricot +frigo +frimas +frimer +friper +frire +friser +frite +fritz +froc +froide +fronde +front +fruit +fruste +fs +ft +fu +fucus +fuel +fugace +fugue +fuite +full +fumage +fumer +fumet +fumier +fumoir +fumure +funin +funky +fur +furax +furet +fureur +furia +furie +furole +fusain +fuseau +fusee +fusel +fuser +fusil +fusion +futaie +futee +futile +futur +future +fv +fw +fx +fy +fz +g +gabare +gabbro +gabier +gabion +gade +gadget +gadin +gadoue +gaffer +gag +gaga +gager +gagman +gagmen +gagner +gaie +gaiete +gaine +gainer +gal +gala +galber +gale +galene +galere +galgal +galion +gallec +gallo +gallon +gallup +galon +galop +galure +gamba +gambe +gambit +gamete +gamine +gamme +gammee +gandin +gang +ganga +gangue +ganse +ganser +gant +ganter +gap +garage +garce +garder +gardon +garer +garnir +garou +garrot +gars +gasoil +gatte +gauche +gaucho +gaude +gaufre +gaule +gauler +gaulis +gaupe +gaur +gauss +gavage +gaver +gavial +gay +gayal +gaz +gazage +gazer +gazole +gazon +gb +gc +gd +ge +geai +geante +gecko +geisha +gel +geler +gelive +gelose +gelule +gelure +gemeau +gemir +gemme +gemmer +gendre +gene +genepi +genese +genet +genie +genome +genou +genre +gens +gent +gentry +geode +gerbe +gerber +gercer +gerer +germen +germer +germon +gerome +gesier +gesine +gesse +geste +geyser +gf +gg +ggg +gggg +gh +ghetto +ghi +ghilde +gi +giaour +gibbon +gibet +gibier +gibus +giclee +gifler +gigolo +gigot +gigue +gilde +gilet +gille +gin +gindre +ginkgo +girafe +girie +girl +giron +gitane +giton +givrer +gj +gk +gl +glabre +glacer +glacis +glaire +glaise +glaive +glande +glaner +glapir +glas +glass +glebe +glene +gliome +globe +gloire +glome +gloria +gloser +glotte +glu +gluau +glui +glume +gluten +glycol +glyphe +gm +gn +gneiss +gnome +gnomon +gnon +gnose +gnosie +gnou +go +goal +gober +gobie +godage +godet +godron +goemon +goglu +gogo +goitre +golden +golf +golfe +gombo +gommer +gonade +gond +gonder +gong +gonze +gord +goret +gorfou +gorger +gorget +gosier +gospel +gosse +goton +gouape +gouda +gouet +gouge +gouine +goujat +goujon +goulag +goule +goulee +goulet +goulot +goulue +goum +goupil +gour +gourbi +gourde +gourer +gourme +gourou +gousse +goy +goyave +goyim +gp +gq +gr +grabat +graben +grade +gradee +grader +gradin +gradus +graine +gramen +gramme +grande +grange +granit +graphe +grappe +grasse +gratin +gratis +grau +graver +gravir +gre +grebe +grec +green +greer +grege +grelin +grelot +gremil +grenat +grener +grenue +gres +greser +gresil +grever +grief +grigou +grigri +gril +grill +grimer +gringe +gringo +grisbi +grise +griser +griset +grisou +grive +grog +groggy +groin +grole +grolle +groom +grosse +grotte +group +grouse +gruau +grue +gruger +grume +gs +gt +gu +guai +guais +guano +gue +guebre +guede +gueer +guelfe +guelte +guenon +guere +gueres +gueret +guerir +guerre +guet +guete +gueuse +gui +guibre +guiche +guider +guidon +guigne +guilde +guimpe +guinee +guiper +guipon +guise +gulden +gunite +guppy +guru +gus +guss +guzla +gv +gw +gx +gy +gym +gypse +gyrin +gz +h +habile +habit +habler +hache +hacher +hachis +hadith +hadji +haie +haine +haire +halage +halbi +haler +hall +halle +halo +halte +halva +hamac +hamada +hameau +hammam +hampe +han +hanap +hanche +hangar +hanse +hanter +hapax +happer +haquet +haras +harde +harder +hardie +harem +hareng +hargne +harki +harle +haro +harpe +harper +harpie +harpon +hart +hasard +hasch +hase +hast +hastee +hauban +haute +hautin +havage +havane +haver +havir +havre +hayon +hb +hc +hd +he +heaume +hebreu +hecto +hegire +hein +heler +helice +helion +helium +helix +hello +hem +hemine +henne +hennin +hennir +henry +hep +heraut +herbe +herbu +herbue +here +hernie +heron +heros +herpe +herpes +herse +herser +hertz +hetman +heu +heur +heure +heurt +hevea +hexose +hf +hg +hh +hhh +hhhh +hi +hiatal +hiatus +hibou +hic +hideur +hie +hieble +hiemal +hier +hi-fi +hi-han +hij +hilare +hindi +hindou +hippie +hippy +hircin +hisser +hiver +hj +hk +hl +hm +hn +ho +hobby +hocco +hocher +hochet +hockey +hoir +hoirie +homard +home +homme +homo +hongre +honnir +honte +hop +hoquet +horde +horion +hormis +hors +horst +hostie +hosto +hotte +hottee +hou +houdan +houe +houer +houka +houle +houp +houppe +houque +hourd +houri +hourra +housse +houx +hoyau +hp +hq +hr +hs +ht +hu +huard +huart +hublot +huche +hucher +huchet +huer +huerta +hui +huile +huit +hum +humage +humain +humble +humer +humeur +humide +humour +humus +hune +hunier +huppe +huppee +hure +hurler +hurrah +hutte +hv +hw +hx +hy +hyalin +hydne +hydre +hydrie +hyene +hymen +hymne +hypoge +hysope +hz +i +iambe +ib +ibere +ibidem +ibis +ic +icaque +ichor +ici +ictere +ictus +id +ide +ideal +ideale +idee +ideel +idem +ides +idiome +idiot +idiote +idoine +idole +idylle +ie +if +ig +igloo +igname +ignare +igne +ignee +iguane +igue +ih +ii +iii +iiii +ij +ijk +ik +il +ileal +ileale +ileite +ileon +ileus +ilion +illico +ilote +im +image +imago +imam +imamat +imanat +imbu +imbue +imide +immun +immune +impact +impair +impala +impaye +imper +impie +impoli +impuni +impur +impure +in +inapte +inca +incise +incree +incuit +incuse +inde +index +indice +indien +indigo +indium +indole +indu +indue +indult +inedit +inegal +inepte +inerme +inerte +infant +infect +infime +infini +infixe +influx +infra +infule +infus +infuse +ingenu +ingrat +inique +injure +inlay +inne +innee +innome +inox +input +insane +instar +insu +intact +inter +inti +intime +intrus +inuit +inule +io +iodate +iode +iodure +ion +ionien +ionone +iota +iourte +ip +ipeca +ipomee +iq +ir +ire +iridie +iris +irisee +iritis +irone +ironie +irreel +is +isard +isatis +isba +islam +isolat +isopet +issant +issu +issue +isthme +it +item +itou +iu +iule +iv +ive +ivette +ivoire +ivraie +ivre +iw +ix +ixia +ixode +iy +iz +j +jabiru +jabler +jabot +jacee +jack +jacket +jacot +jade +jadis +jaguar +jais +jalap +jale +jalon +jamais +jambe +jambee +jambon +jan +jante +janv +japon +jar +jarde +jardin +jardon +jargon +jarre +jarret +jars +jas +jasmin +jasper +jatte +jattee +jauger +jaune +jaunir +java +javart +javeau +javel +jazz +jb +jc +jd +je +jean +jeep +jenny +jerez +jerk +jersey +jesus +jet +jetage +jeter +jeton +jeu +jeudi +jeun +jeune +jf +jg +jh +ji +jigger +jj +jjj +jjjj +jk +jkl +jl +jm +jn +jo +job +jockey +jodler +joie +joint +joker +jolie +jonc +joncer +jonque +joseph +jota +joual +jouer +jouet +joug +joujou +joule +jour +joute +joyau +jp +jq +jr +js +jt +ju +jube +jucher +judas +judo +judoka +jugale +juger +juif +juill +juin +juive +jujube +julep +jules +jumbo +jumeau +jumel +jument +jungle +junior +junker +junte +jupe +jupon +jurat +jurer +jureur +juron +jury +jus +jusant +jusee +jusqu +jusque +juste +jute +juter +jv +jw +jx +jy +jz +k +kabuki +kabyle +kacha +kache +kaiser +kaki +kali +kalium +kamala +kami +kan +kanake +kaolin +kapok +kappa +karate +karbau +karite +karma +karman +kart +kava +kawa +kayak +kb +kc +kd +ke +kefir +kelvin +kendo +kentia +kephir +kepi +ketch +ketmie +kf +kg +kh +khan +khanat +khat +khmere +ki +kick +kief +kif +kiki +kil +kilo +kilt +kimono +kinase +kipper +kir +kirsch +kit +kitsch +kiwi +kj +kk +kkk +kkkk +kl +klaxon +klm +km +kn +knout +ko +koala +kobold +koine +kola +kopeck +koubba +koulak +koumis +koumys +kouros +kp +kq +kr +kraal +krach +kraft +krak +kraken +kriss +ks +ksar +ksi +ksour +kt +ku +kummel +kurde +kv +kvas +kw +kwas +kx +ky +kyrie +kyste +kz +l +label +labeur +labiee +labile +labium +labour +labre +lac +lacer +lacet +lacis +lactee +lacune +lad +ladies +ladin +ladite +ladre +lady +lagon +laguis +lagune +lai +laide +lainer +laird +lait +laitee +laiton +laitue +laize +lambda +lambel +lambic +lamer +lamie +lamier +lampe +lamper +lancer +landau +lande +langer +langue +lanice +lanier +laper +lapiaz +lapine +lapis +lapone +laps +lapsus +laptot +laque +laquee +laquer +larbin +larcin +lard +larder +lardon +large +largo +larme +larron +larve +larvee +larynx +las +lascar +laser +lasse +lasser +lassis +lasso +lastex +lat +latex +latine +latrie +latte +latter +lattis +laudes +lauree +lavabo +lavage +laver +lavis +lavoir +lavure +laxite +layer +layon +lazzi +lb +lc +ld +le +leader +lebel +lecher +ledit +legale +legat +legato +lege +legere +legion +legs +leguer +legume +lei +lemme +lemure +lendit +lente +lento +lepre +lequel +lerche +lerot +les +leser +lesion +leste +lester +let +letale +letchi +lettre +leu +leude +leur +lev +leva +levage +levain +lever +levier +levite +levre +levure +lexeme +lexie +lexis +lf +lg +lh +li +liage +liane +liard +libage +liber +libido +libre +lice +lichen +licher +licier +licite +licol +licou +lido +lied +liege +lieger +lien +lier +lierne +lierre +liesse +lieu +lieue +lieuse +lieux +lievre +lift +lifter +ligand +lige +ligie +ligne +lignee +ligner +ligot +liguer +ligule +ligure +lilas +limace +limage +liman +limbe +limbes +limer +limier +limnee +limon +limule +lin +liner +linga +lingam +linge +linger +lingot +links +lino +linon +linter +lionne +lipase +lipide +lipome +lippe +lippee +lippue +liron +lisage +lisere +lisser +listel +lister +lit +litchi +liteau +litee +liter +litham +litho +litige +litote +litre +litron +litsam +liure +live +livet +livide +living +livrer +livret +lj +lk +ll +llanos +lll +llll +lm +lmn +ln +lo +loader +lob +lobby +lobe +lober +locale +loch +locher +loden +lods +loess +lof +loft +loger +loggia +logis +logo +loi +loin +loir +loisir +lokoum +lolo +lombes +longer +longue +looch +loofa +look +lopin +loque +loquer +loquet +loran +lord +lori +loriot +loris +lors +lorsqu +lot +lote +lotier +lotion +lotir +loto +lotte +lotus +louage +loubar +louer +lougre +louis +loulou +loup +louper +lourde +lourer +loutre +louve +louver +lover +loyale +loyer +lp +lq +lr +ls +lt +lu +lubie +lucane +lucide +lucre +ludion +luette +lueur +luffa +luge +lui +lulu +lumen +lump +lunch +lundi +lune +lunee +lunule +lunure +lupin +lupus +lusin +luter +luth +lutin +lutrin +lux +luxer +luxure +luzule +lv +lw +lx +ly +lycaon +lycee +lycene +lychee +lycope +lycose +lycra +lymphe +lynx +lyre +lyric +lys +lysat +lyse +lyser +lysine +lz +m +mac +macho +macis +macler +macre +madame +madere +madone +madras +madree +maffia +mafia +mage +magie +magma +magnat +magner +magnum +magot +magret +mahous +mai +maie +maigre +mail +maille +main +mainte +maire +mairie +mais +maison +major +maki +mal +malade +malaga +malard +malart +malgre +mali +malice +malin +malle +malt +malter +malus +maman +mambo +mamie +mammy +man +mana +manade +manant +manche +mancie +mandat +mander +manege +manger +mangue +manier +manioc +manne +manoir +manse +mante +maorie +maquer +maquis +marais +marc +marche +mardi +mare +maree +marfil +margay +marge +marger +margis +mari +marial +marier +marine +mark +marli +marlou +marmot +marne +marner +marrer +marrie +mars +marte +martel +martre +maser +masser +massue +mastic +mastoc +masure +mataf +matage +match +mate +mater +math +matin +matir +matite +matoir +matou +matras +matte +mature +maure +mauser +mauve +mauvis +max +maxima +maxime +maya +maye +mayen +mazout +mb +mc +md +me +meat +mec +mecano +mecene +meche +mecher +mechta +mede +media +mediat +medina +medire +medium +medius +medoc +mefait +mefier +megere +megir +megohm +megot +mehara +mehari +meiose +melena +meleze +melia +melo +melon +membre +meme +memere +men +menade +menage +meneau +mener +menhir +menine +mense +menthe +mentir +menton +mentor +menue +menuet +menure +mer +merci +merde +mere +merise +merlan +merle +merlin +merlon +merlu +merou +mes +mesa +mess +messe +messer +messie +mestre +meta +metal +meteil +meteo +metier +metis +metope +metre +metrer +metro +meuler +meulon +meute +mezail +mezzo +mf +mg +mh +mi +miaou +miasme +mi-bas +mica +miche +micmac +micro +micron +midi +mie +miel +mienne +miette +mieux +mievre +mi-fin +mikado +mil +milan +mile +milice +milieu +milite +millas +mille +millet +milord +mi-mai +mimer +mimi +mimosa +min +minage +minbar +mince +miner +mini +minima +minime +minium +minois +minot +minou +minuit +minus +mioche +mir +mirage +mirer +miro +miroir +miser +misere +miss +missel +misses +mitage +mitan +miter +miton +mitose +mitre +mitree +mitron +mixage +mixer +mixeur +mixite +mixte +mj +mk +ml +mm +mmm +mmmm +mn +mno +mo +mobile +moblot +moche +moco +modale +mode +modem +modus +moelle +moere +moeurs +mohair +moi +moine +moins +moirer +mois +moiser +moite +moitie +moitir +moka +mol +molene +mollah +molle +mollet +mollir +mollo +moloch +moly +moment +momie +mon +monade +monde +monder +monel +moneme +mono +mont +monter +moquer +morale +morbus +mordre +more +moreau +morfil +morgue +morio +morion +morne +mornee +morose +morse +morte +morue +morula +morve +mosane +mot +motel +motet +motif +motion +moto +motte +motter +motus +mou +moue +moufle +mouise +moujik +mouler +moulin +moult +mouron +mourre +mousme +mouton +mouver +moxa +moyee +moyeu +mp +mq +mr +ms +mt +mu +muance +mucher +mucor +mucron +mucus +muer +muette +muffin +mufle +mufti +muge +muguet +muid +mule +mulet +muleta +mulon +mulot +munir +muphti +mur +murage +murale +murene +murer +muret +murex +murmel +musc +muscat +muse +museau +musee +museum +musoir +musser +must +mutage +muter +mutine +mutite +mutule +mv +mw +mx +my +mycose +mygale +myiase +myome +myope +myopie +myrrhe +myrte +mythe +mz +n +nabab +nabote +nacrer +nadir +naevus +nafe +nager +naine +naja +nana +nanan +nanar +nandou +nankin +nantir +naos +napalm +napee +napel +naphte +nappe +napper +nard +narine +narrer +narval +nasale +nase +naseau +nasse +natale +natice +nation +native +natron +natrum +natter +nature +nausee +navaja +navale +navet +navire +navrer +nazie +nb +nc +nd +ne +neant +nebka +neck +nectar +nef +nefle +negoce +negre +negus +neige +nemale +nene +nenies +nenni +neo +neon +nepete +nerf +neroli +nervi +nervin +nette +neuf +neume +neutre +neuve +neve +neveu +nez +nf +ng +nh +ni +niable +niaise +nib +nicher +nichet +nichon +nickel +nicol +nid +niece +nieme +nier +nif +nife +nille +nimber +nimbus +ninas +nippe +nipper +nique +nitrer +nivale +niveau +nixe +nizere +nj +nk +nl +nm +nn +nnn +nnnn +no +noble +noce +nocher +nocive +nodule +noeud +noire +noise +noix +nolis +nom +nomade +nome +nommer +non +nonce +none +nonidi +nonne +nop +nopal +noper +nord +noria +norme +normee +norois +nos +nostoc +noter +notice +notion +notre +notule +nouba +nouer +nougat +noulet +nounou +nous +nouure +nouvel +nover +novice +noyade +noyau +noyer +np +nq +nr +ns +nt +nu +nuage +nubile +nudite +nue +nuee +nuer +nuire +nuit +nuitee +nulle +numero +numide +nuque +nurse +nv +nw +nx +ny +nylon +nymphe +nz +o +oasien +oasis +ob +obel +obele +obese +obier +obit +objet +oblat +oblate +oblong +obole +obscur +obtus +obtuse +obus +obvers +oc +occase +ocean +ocelle +ocelot +ocre +ocreux +octane +octant +octave +octet +octidi +octroi +octuor +oculus +od +ode +odeon +odeur +odieux +odorat +oe +oedeme +oedipe +oeil +oestre +oeuf +oeuve +oeuvee +oeuvre +of +off +office +offre +offset +oflag +og +ogival +ogive +ogre +oh +ohe +ohm +oi +oie +oignon +oille +oing +oiseau +oiseux +oisif +oisive +oison +oj +ok +okapi +okoume +ol +ole +oleate +oleine +oleum +olim +olive +olle +olympe +om +omble +ombre +omega +omnium +on +onagre +once +oncial +oncle +onde +ondee +ondin +ondine +on-dit +ongle +onglee +onglet +onglon +ongule +onques +onyx +onyxis +onzain +onze +oo +oocyte +oogone +ooo +oooo +op +opale +opalin +opaque +ope +open +opera +ophite +ophrys +opimes +opium +oppida +opq +optima +option +opus +oq +or +oracle +orage +oral +orale +orange +orant +orante +orbe +orbite +orchis +ordo +ordre +ordure +oreade +oree +ores +orfroi +organe +orge +orgeat +orgie +orgue +oribus +oriel +orient +origan +orin +orle +ormaie +orme +ormeau +ormoie +orobe +oronge +orphie +orpin +orque +orteil +ortie +orvale +orvet +os +oscar +oscule +oside +osier +osmium +osmose +osque +osseux +ossu +ossue +ostiak +ot +otage +otarie +otique +otite +ou +ouais +ouate +oubli +ouche +oued +ouest +ouf +oui +oukase +oulema +ourdou +ourlet +ours +ourse +oursin +ourson +oust +ouste +out +outil +outlaw +output +ouzbek +ov +ovaire +ovale +ovate +ove +ovibos +ovides +ovin +ovine +ovni +ovule +ow +ox +oxford +oxymel +oxyton +oxyure +oy +oyat +oz +ozene +ozone +ozonee +p +pacage +pacha +pachto +pack +pacson +pacte +paddy +padou +padoue +paella +paf +page +pagel +pageot +pager +pagne +pagode +pagre +pagure +pagus +pain +paire +pairie +pairle +paix +pal +palace +palais +palan +pale +palee +palis +palmer +palot +palper +palud +palude +palus +pampa +pampre +panade +panama +panax +panca +panda +pandit +panel +paner +panic +panka +panne +panner +panser +pansue +pantin +panure +panzer +paonne +papa +papale +papaye +pape +papi +papier +papion +papule +papy +paquet +par +parage +parc +parce +par-ci +pardi +pardon +pareo +parer +parere +parfum +pari +parian +parier +parite +parka +parler +parme +parmi +paroi +parole +paroli +paros +parsec +parsie +part +parton +parure +parvis +pas +passer +passim +pastel +pastis +pat +patard +patate +patene +pater +patere +pathos +patio +patois +patrie +patte +patter +pattue +paume +paumer +pause +pauvre +pavage +paver +paveur +pavie +pavois +pavot +payer +payse +pb +pc +pd +pe +peage +pean +peau +pebroc +pecari +peche +pecnot +pecore +pecten +pecule +pedum +pegase +pegre +pehlvi +peille +peiner +pekan +pekin +pelade +pelage +pelard +peler +pelle +pellet +pelote +pelta +peltee +pelure +pelvis +penale +pendre +penil +penis +penne +pennee +pennon +penny +penon +penser +pensum +pente +pentue +peon +peotte +pep +pepe +pepere +pepie +pepin +pepite +peplum +pepon +pequin +percer +perdre +pere +peril +perle +perler +perlon +perlot +perone +perot +perron +pers +perse +persel +persil +perte +pesade +pesage +peser +peseta +peso +peson +pesse +petale +petard +petase +peter +petite +peton +petree +petrel +petrin +petrir +petun +peu +peuh +peul +peur +peyotl +peze +pezize +pf +pfft +pg +ph +phage +phanie +phare +phase +phasme +phenix +phenol +phi +philo +phlox +phobie +phone +phonie +phono +phoque +photo +photon +phrase +phylum +pi +piaf +pian +piano +pibale +pic +pica +picage +pichet +picolo +picot +picris +pidgin +pie +piece +pied +piege +pieger +pierre +piete +pieter +pietin +pietre +pieu +pieuse +pieze +pif +pifer +piffer +pige +piger +pigne +pignon +pilaf +pilage +piler +pilet +pilier +piller +pilon +pilori +pilou +pilule +pilum +piment +pin +pinard +pincer +pineau +pinede +pingre +pinne +pinot +pinson +pinte +pinter +pin-up +pinyin +piolet +pionne +pipe +pipeau +piper +pipi +pipit +piquer +piraya +pire +pirole +pis +pise +pissat +pisser +pister +pistil +piston +pistou +pite +pitie +piton +pitre +pive +pivert +pivot +pizza +pj +pk +pl +placer +plage +plaid +plaie +plaine +plan +planer +plante +plasma +plaste +plate +platee +playon +pleban +plebe +pleine +pleur +plevre +plexus +pleyon +pliage +plie +plier +plioir +plique +pliure +ploc +plomb +plot +plouc +plouf +plouk +ployer +pluie +plumer +plumet +pluton +pm +pn +pneu +pneumo +po +poche +pocher +pochon +podium +podzol +poeme +poesie +poete +pogne +pognon +pogrom +poids +poigne +poil +poiler +poilue +poing +pointe +poire +pois +poise +poison +poix +poker +polar +polder +polio +polir +polka +pollen +polo +polype +pomelo +pomme +pomper +pompon +ponant +poncer +poncho +poncif +pondre +poney +pongee +ponte +ponter +pontet +pontil +ponton +pool +pop +pope +popote +populo +poquet +porc +porche +pore +porion +porno +porque +porte +porter +porto +portor +posada +poser +poster +potage +potard +pote +poteau +potee +potin +potion +pou +pouah +pouce +pouf +poule +poulet +poulie +poulpe +pouls +poumon +poupe +poupee +poupon +pour +poutre +pp +ppp +pppp +pq +pqr +pr +praire +pralin +prame +praxis +pre +preau +precis +prefet +prelat +prele +prenom +pres +preste +presto +preuve +preux +prier +priere +primer +primo +prince +priori +priser +prisme +prison +priver +prix +pro +probe +proces +proche +prof +profes +profil +profit +proie +projet +prolan +prolo +promo +pronom +propos +propre +prose +prote +protee +proton +prou +proue +provin +provo +proyer +prude +pruine +prune +prunus +prurit +ps +psaume +pseudo +psi +psitt +psoas +psoque +pst +psyche +pt +pu +pub +pubere +pubis +public +puce +puceau +puche +pucier +pudeur +puer +puffin +puis +puiser +puits +pull +pulpe +pulque +pulsar +pulser +puma +puna +punch +punir +punk +pupe +pure +pureau +puree +purete +purger +purin +purine +purot +putain +pute +putier +putiet +putois +putsch +putti +putto +puy +puzzle +pv +pw +px +py +pygmee +pyjama +pylore +pyrale +pyrene +pyrex +pyrite +pyrrol +pythie +python +pyurie +pyxide +pz +q +qb +qc +qd +qe +qf +qg +qh +qi +qj +qk +ql +qm +qn +qo +qp +qq +qqq +qqqq +qr +qrs +qs +qt +qu +quai +quaker +quand +quant +quanta +quark +quarte +quarto +quartz +quasar +quasi +quater +quatre +que +quelle +queue +queux +qui +quiche +quidam +quiete +quille +quine +quinee +quinoa +quint +quinte +quinto +quinze +quipo +quipou +quipu +quitus +quoi +quorum +quota +qv +qw +qx +qy +qz +r +rabais +raban +rabane +rabat +rabbi +rabbin +rabiot +rabot +race +racee +racer +rachat +rachis +racket +racler +radar +radeau +rader +radian +radier +radine +radio +radis +radium +radius +radjah +radoub +rafale +raffut +rafiot +rafler +raglan +ragot +raguer +rai +raide +raider +raidir +rail +rainer +rais +raisin +raison +raja +rajah +rajout +raki +rallye +ramage +ramdam +rame +rameau +ramer +ramie +ramier +ramure +rance +ranch +ranche +rancio +rancir +rang +ranger +rani +ranz +raout +rapace +raphia +rapide +rapin +rapine +rappel +rapt +raquer +rare +rarete +rasade +rasage +rase +raser +rash +rashes +rasoir +rasta +ratage +rate +ratel +rater +ratio +ration +raton +rauque +rave +ravier +ravine +ravir +rayage +rayer +rayere +rayon +rayure +raz +razzia +rb +rc +rd +re +reac +reale +rebab +rebec +rebond +rebord +rebus +rebut +recel +reces +recez +recif +recite +recoin +record +recors +recrue +recta +recto +rectum +redan +redent +redie +redoux +reduve +reelle +ref +reflet +reflex +reflux +refuge +refus +reg +regain +regale +regard +regate +reggae +regime +region +regir +regler +reglet +reglo +regrat +regret +regule +rehaut +reine +reis +rejet +relais +relax +relent +relief +relier +rem +remake +remede +remere +remige +remiz +remora +remous +remuer +renale +rendre +renier +renne +renom +rente +renter +renvoi +repas +repic +repit +repli +report +repos +reps +repue +requin +reseau +reseda +residu +resine +ressac +ressui +rester +retard +retine +retive +retors +retour +retro +rets +reunir +reveil +revers +rf +rg +rh +rhe +rhesus +rhombe +rhum +rhumb +rhumer +ri +ria +rial +ribler +riblon +ribose +ribote +riccie +riche +ricin +rictus +ridage +rideau +rider +ridoir +ridule +riel +rien +rieuse +riffle +rififi +rifler +rift +rigide +rigolo +rikiki +rimaye +rimer +rincer +ring +ripage +riper +ripper +rire +risban +risee +rital +rite +rivage +rivale +river +rivet +rivoir +rivure +rixe +riz +rj +rk +rl +rm +rn +ro +rob +robage +rober +robert +robin +robot +roc +rocade +roche +rocher +rochet +rock +rocker +rocket +rococo +rocou +rodage +rodeo +roder +rodoir +rogner +rognon +rogue +roguee +rohart +roi +roide +roidir +roman +romane +romani +romano +rompre +ronce +ronde +rondin +rondir +rondo +ronger +ronron +roque +rosace +rosage +rosat +rosbif +rose +roseau +roser +rosir +rosser +rostre +rot +rotang +rotary +rotin +rotor +rotule +roture +rouage +rouble +rouchi +roue +rouer +rouf +rouge +rouget +rougir +rouir +rouler +roulis +roumi +round +roupie +rousse +router +roux +rowing +royale +rp +rq +rr +rrr +rrrr +rs +rst +rt +ru +ruade +ruban +rubato +rubis +ruche +rucher +rude +ruee +ruelle +ruer +rufian +rugby +ruiler +ruiner +rumba +rumen +rumeur +rumex +ruolz +rupine +rurale +ruser +rush +rushes +russe +rustre +rut +rv +rw +rx +ry +rz +s +sabbat +sabine +sabir +sabler +sablon +sabord +sabot +sabra +sabrer +sac +sachem +sachet +sacome +sacre +sacrer +sacret +sacrum +safari +safran +safre +saga +sagace +sagaie +sage +sagou +sagum +sahel +saine +sainte +saisir +saison +sajou +sake +saki +salace +salade +salage +salami +salaud +salep +saler +salete +saline +salir +salive +salle +salmis +saloir +salol +salon +saloon +salop +salsa +salse +saluer +salure +salut +salve +samare +samba +samedi +samit +sampan +sampi +sampot +sana +sandre +sang +sanie +sans +santal +sante +santon +sanve +sanza +saoule +saper +sapeur +saphir +sapide +sapin +sapine +saquer +sarde +sari +sarong +saros +sarrau +sas +sasser +satin +satire +satyre +sauce +saucee +saucer +sauf +sauge +saule +saulee +saumon +sauna +saur +saurer +saurin +saurir +saut +sauter +sauver +savane +savart +savate +saveur +savon +saxe +saxo +sayon +sb +sbire +sc +scalde +scalp +scampi +scare +scat +sceau +scene +schah +schako +scheik +schema +scheol +schleu +schupo +schuss +sciage +sciene +scier +scille +scion +scirpe +sciure +scolex +scolie +sconse +scoop +scopie +score +scorie +scotie +scoute +scribe +scull +scuta +scutum +scythe +sd +se +seance +seante +seau +sebile +sebka +sebkha +sebum +seche +secher +secte +segala +seguia +seiche +seide +seigle +seille +seime +seine +seing +seisme +seize +sejour +sel +select +self +seller +selon +seltz +selve +semer +semis +semite +semoir +semple +sen +senat +senau +sene +seneve +senile +senior +senne +sens +sensee +sentir +sep +sepale +sepia +seps +sept +septum +sequin +serac +serail +serbe +serf +serge +serie +serier +serine +sermon +serpe +serran +serrer +serte +sertir +serum +serval +servir +ses +sesame +set +setier +seton +setter +seuil +seule +seve +severe +sevrer +sevres +sexe +sexte +sexto +sexuee +sexy +sf +sg +sh +shah +shaker +sherif +sherry +shimmy +shogun +shoot +short +show +shunt +si +sial +sialis +sic +sicle +siecle +siege +sienne +sierra +sieste +sieur +sigle +sigma +signal +signer +signet +sil +silene +silex +silice +sillet +sillon +silo +silphe +silure +silves +sima +simili +simoun +simple +singe +singer +single +sinite +sinon +sinus +sioux +siphon +sirdar +sire +sirene +sirex +sirli +siroco +sirop +sisal +sistre +sitar +site +sit-in +situer +sium +six +sixain +sixte +sizain +sj +sk +skate +sketch +ski +skif +skiff +skunks +sl +slalom +slang +slave +slavon +slip +slogan +sloop +slow +sm +smala +smalt +smart +smash +smilax +smocks +smog +smolt +smurf +sn +snack +sniff +snob +snober +so +sobre +soc +socle +socque +soda +sodee +sodium +sodoku +soeur +sofa +soi +soie +soif +soin +soir +soiree +soit +soja +solder +sole +soleil +solen +solex +solide +solin +solive +solo +solute +soma +somite +sommer +sommet +son +sonar +sonate +sonder +sonner +sono +sonore +sorbe +sorbet +sore +sorgho +sort +sortir +sosie +sotch +sotie +sotte +sou +souche +souci +soudan +souder +soue +soufre +souk +soulte +soupir +souple +source +sourde +soute +soviet +soya +soyer +sp +spahi +spalax +spart +sparte +spasme +spath +spathe +speech +speiss +speos +sperme +sphere +sphex +sphinx +spider +spire +spiree +spleen +spore +sport +spot +sprat +spray +sprint +sprue +sq +squale +squame +square +squash +squat +squaw +sr +ss +sss +ssss +st +stable +stade +stadia +staff +stage +stalag +stalle +stance +stand +star +starie +stase +stator +statut +stawug +stayer +steak +stele +stem +stemm +steno +steppe +stere +stereo +sterer +sterne +sterol +sthene +stick +stipe +stiple +stock +stoker +stolon +stop +storax +store +stout +stras +strass +strate +stress +strie +strier +strige +string +strix +stroma +strume +stryge +stu +stuc +studio +stupre +style +styler +stylet +stylo +styrax +su +suage +suaire +suave +suber +subir +subite +subito +suc +succes +succin +sucer +sucrer +sucrin +sud +suede +suedee +suer +suette +sueur +suie +suif +suifer +suint +suisse +suite +suitee +suivre +sulky +sumac +summum +sunna +super +supere +supin +supra +surah +surate +surdos +sure +sureau +surf +surfil +surin +surjet +surmoi +surnom +suros +sursis +survie +survol +sushi +sutra +suture +sv +svelte +sw +swap +swing +sx +sy +sylphe +sylve +sympa +syndic +synode +syrinx +syrphe +sz +t +tabac +tabar +tabard +tabes +tablar +tablee +tabler +tabor +taboue +tac +tacca +tacet +tacher +tacite +tacon +tacot +tact +taenia +tafia +tagal +tagete +taie +tain +tajine +talc +talent +taler +taleth +talion +talmud +talon +talure +talus +talweg +tamia +tamier +tamil +tamis +tampon +tan +tancer +tanche +tandem +tandis +tango +tangon +tanin +tank +tanker +tanner +tannin +tanrec +tant +tante +taon +tapage +taper +tapin +tapir +tapon +taquer +taquet +tarage +tarama +tarare +taraud +tard +tare +tarer +taret +targe +targui +tarif +tarin +tarir +tarot +tarpan +tarpon +tarse +tartan +tarte +tartre +tarzan +tas +tasser +tata +tatami +tatane +tatare +tatou +taudis +taule +taupe +taupee +taupin +taure +taux +tauzin +taxer +taxi +taxie +taxon +tb +tc +tchao +td +te +teck +teckel +tee +tek +tele +telega +telex +tell +telle +telson +temoin +tempe +temple +tempo +temps +tenace +tender +tendon +tendre +tenia +tennis +tenon +tenor +tenrec +tenson +tenter +tenue +tenure +tenuto +teorbe +tercer +tercet +terme +terne +ternir +terrer +terril +terser +tertio +tertre +tes +tesson +test +tester +teston +tetee +teter +tetin +tetine +teton +tetra +tetras +tette +texane +texte +tf +tg +th +thaler +thalle +the +theine +theme +thenar +theque +these +thon +thora +thorax +thoron +threne +thrips +thune +thuya +thym +thymie +thymol +thymus +thyrse +ti +tian +tiare +tibia +tic +ticket +tiede +tiedir +tienne +tierce +tiers +tif +tiffe +tige +tiglon +tigrer +tigron +tilde +tillac +tiller +tilt +timide +timing +timon +tincal +tinter +tintin +tipule +tique +tir +tirade +tirage +tirer +tiroir +tisane +tiser +tison +tisser +tissu +titane +titi +titrer +tj +tk +tl +tm +tmese +tn +to +toast +toc +tocade +tocsin +toge +toi +toile +toiler +toiser +toison +toit +tokai +tokay +tolet +tolite +tolle +tolu +toluol +tomate +tombac +tome +tomer +tomme +tommy +ton +tonale +tondre +tonie +tonka +tonte +tonton +tonus +top +topaze +tophus +topo +toque +toquer +toquet +torah +torcol +tordre +torero +tories +torii +toril +toron +torque +torse +tort +tortil +tortis +tortue +torve +tory +totale +totem +toto +toton +touage +toubib +toucan +touer +toueur +touffe +toupet +toupie +touque +tour +tourbe +tourd +touret +tourie +touron +tourte +tous +toute +toutim +toutou +toux +toxine +tp +tq +tr +trabe +trabee +trac +tracas +tracer +tract +trafic +trahir +train +trajet +tram +tramer +transe +trappe +trapue +trauma +travee +trayon +trefle +treize +trema +tremie +trente +trepan +trepas +tres +tresor +tresse +treuil +tri +triade +triage +trial +tribu +tribut +tricot +tridi +trier +triere +trigle +trille +trimer +trin +trine +trio +triode +triol +trip +tripe +tripot +trique +trisme +trisoc +triste +triton +troc +troche +troene +trogne +trois +troll +trombe +tronc +trop +trope +trot +trou +trouer +troupe +truble +truc +truie +truite +trulli +trullo +trust +ts +tsar +tt +ttt +tttt +tu +tuable +tuage +tub +tubage +tuber +tudieu +tuer +tuerie +tueuse +tuf +tufeau +tuile +tuiler +tulipe +tulle +tumeur +tune +tuner +tungar +tunnel +tupaja +tupi +tuque +turban +turbe +turbeh +turbin +turbot +turco +turf +turion +turne +turnep +turque +tussah +tussor +tuthie +tutie +tutti +tutu +tuv +tuyau +tuyere +tv +tw +tweed +twist +tx +ty +tympan +typer +typha +typhon +typhus +typo +typon +tyran +tz +tzar +u +ub +ubac +uc +ucine +ud +ue +uf +ug +uh +ui +uj +uk +ukase +ul +ulcere +ulema +ultime +ultimo +ultra +ulve +um +un +unau +une +unguis +uniate +uniaxe +unieme +union +unique +unite +unitif +uo +up +upas +uq +ur +uraeus +urane +uranie +urate +urbain +ure +uree +ureide +uremie +uretre +urgent +urinal +urine +urique +urne +urubu +urus +us +usage +usagee +usager +usine +usite +usitee +usnee +usuel +usure +ut +uterin +uterus +utile +utopie +uu +uuu +uuuu +uv +uval +uvale +uvee +uveite +uvula +uvule +uvw +uw +ux +uy +uz +v +vaccin +vache +vacive +vacuum +vagin +vague +vahine +vaigre +vaine +vair +vairee +vairon +val +valet +valeur +valgus +valide +valine +valise +vallee +vallon +valser +valve +valvee +vamp +vamper +van +vanda +vanite +vanner +vanter +vape +vapeur +var +varan +varech +varice +varier +varlet +varron +varus +varve +vase +vasque +vaste +vb +vc +vd +ve +veau +veces +veiner +velar +velche +veld +velie +velin +velite +velo +veloce +velot +velte +velue +velum +venale +vendre +veneur +venger +venin +vent +vente +ventis +ventre +venus +ver +verbe +verdet +verdir +verge +vergee +verger +vergne +vergue +verin +verine +verite +verjus +verlan +vermee +vermet +vermis +verole +verrat +verre +verree +verrou +verrue +vers +verser +verset +verso +verste +versus +verte +vertex +vertu +verve +vesce +vessie +veste +veston +veto +veule +veuve +vexer +vf +vg +vh +vi +via +viable +viaduc +viande +vibord +vibrer +vice +vichy +vicier +vidage +vidame +video +vider +vidoir +vidure +vie +vieil +vierge +vieux +vigie +vigile +vigne +vignot +viking +vile +villa +ville +vin +vinage +viner +vingt +vinyle +vioc +viol +violat +violer +violon +vioque +viorne +vipere +virage +virago +virale +virer +vireur +virile +virion +virole +virose +virure +virus +visa +visage +viser +viseur +vision +vison +visser +vitae +vitale +vite +vitre +vitrer +vivace +vivat +vive +vivier +vivre +vivree +vivres +vizir +vj +vk +vl +vlan +vm +vn +vo +vocale +vodka +voeu +vogoul +voici +voiler +voire +voirie +voisin +voix +vol +volage +volcan +voler +volet +volis +volley +volt +volume +volute +volve +volvox +vomer +vomir +vorace +vortex +vos +vote +voter +votive +votre +vouer +vouge +vous +voyer +voyou +vp +vq +vr +vrac +vraie +vs +vt +vu +vulgo +vulpin +vulve +vv +vvv +vvvv +vw +vwx +vx +vy +vz +w +wading +wagage +wagon +wapiti +waters +watt +wb +wc +wd +we +weber +welche +welter +wf +wg +wh +wharf +whig +whisky +whist +wi +wigwam +wilaya +winch +wj +wk +wl +wm +wn +wo +wombat +won +woofer +wp +wq +wr +ws +wt +wu +wv +ww +www +wwww +wx +wxy +wy +wz +x +xb +xc +xd +xe +xenon +xeres +xerus +xf +xg +xh +xi +xipho +xj +xk +xl +xm +xn +xo +xp +xq +xr +xs +xt +xu +xv +xw +xx +xxx +xxxx +xy +xylene +xyste +xyz +xz +y +yacht +yack +yak +yang +yankee +yaourt +yard +yb +yc +yd +ye +yeble +yen +yeoman +yeomen +yeuse +yeux +ye-ye +yf +yg +yh +yi +yin +yj +yk +yl +ym +yn +yo +yoga +yogi +yole +yourte +youyou +yp +ypreau +yq +yr +ys +ysopet +yt +yttria +yu +yucca +yv +yw +yx +yy +yyy +yyyy +yz +z +zabre +zain +zancle +zani +zanni +zanzi +zazou +zb +zc +zd +ze +zebrer +zebu +zee +zele +zelee +zelote +zen +zenana +zend +zenith +zephyr +zero +zeste +zester +zetete +zeugma +zeugme +zf +zg +zh +zi +ziber +zig +zigoto +ziguer +zigzag +zinc +zinnia +zinzin +zipper +zircon +zizi +zj +zk +zl +zloty +zm +zn +zo +zombi +zombie +zona +zonage +zonale +zone +zoner +zonier +zonure +zoo +zoom +zou +zouave +zozo +zp +zq +zr +zs +zt +zu +zut +zv +zw +zwanze +zx +zy +zygene +zygoma +zygote +zymase +zython +zythum +zz +zzz +zzzz diff --git a/resources/public/wordlists/german-diceware-wordlist.txt b/resources/public/wordlists/german-diceware-wordlist.txt new file mode 100644 index 0000000..5016643 --- /dev/null +++ b/resources/public/wordlists/german-diceware-wordlist.txt @@ -0,0 +1,7776 @@ +abbau +abbauen +abbiegen +abbild +abbildung +abbrechen +abbruch +abdankung +abdecken +abdruck +abend +abendblatt +abendessen +abendkasse +abendmahl +abends +abenteuer +abenteurer +aber +abermals +abfahrt +abfall +abfinden +abfindung +abflug +abfolge +abfuhr +abgabe +abgang +abgeben +abgerufen +abgesehen +abgewinnen +abgrenzung +abgrund +abhalten +abhanden +abhandlung +abheben +abhilfe +abholen +abitur +abkehr +abkommen +ablauf +ablaufen +ablegen +ableger +ablehnen +ablehnend +ablehnung +ableiten +ableitung +ablenken +ablenkung +ablesen +abliefern +abnahme +abnehmen +abnehmer +abneigung +abonnenten +abordnung +aborigines +abpfiff +abrechnung +abreise +abriss +abruf +abrufbar +abrufen +abrupt +absage +absagen +absatz +abschaffen +abschied +abschlag +abschloss +abschluss +abschnitt +abschuss +absehbar +abseits +absender +absenkung +absetzen +absetzung +absichern +absicht +absolut +abspaltung +abspielt +absprache +absprechen +abstammung +abstand +abstecher +absteigen +absteiger +abstellen +abstieg +abstimmen +abstimmung +abstrakt +abstriche +absturz +absurd +abt +abtei +abteilung +abtreibung +abtreten +abwahl +abwarten +abwasser +abwegig +abwehr +abwehrchef +abwehren +abweichen +abweichung +abwenden +abwertung +abwicklung +abzeichen +abziehen +abzug +achse +acht +achten +achter +achterbahn +achtung +acker +ackerbau +action +adaption +adel +adjektiv +adler +admiral +adoption +adressaten +adresse +advent +affen +afghanen +afrikaner +after +agenda +agenten +agentur +aggression +aggressiv +agieren +ahlen +ahnen +ahnung +aids +air +airlines +akademie +akademiker +akkordeon +akribisch +akrobatik +akt +akten +akteure +aktien +aktienkurs +aktion +aktionstag +aktiv +aktiven +aktivieren +aktivisten +aktuell +akustik +akustisch +akut +akzente +akzeptabel +akzeptanz +alarm +alarmierte +alb +albaner +alben +albern +albtraum +album +algen +alias +alkohol +all +allee +allegro +allein +alleine +alleingang +allemal +allenfalls +allerdings +allergien +allerhand +allesamt +allgemein +allianz +alliierten +allseits +alltag +alm +alpen +alpha +alphabet +alpin +alpine +alsbald +also +alt +altar +altbau +altdorf +alten +altenburg +altenheim +alter +alternativ +altersheim +althaus +altlasten +altmeister +altpapier +altstadt +aluminium +amateure +ambiente +ambitionen +ambulant +ambulanz +ameisen +amerikaner +ammann +amnestie +amoklauf +ampel +amt +amtlich +amtsblatt +amtsleiter +amtssitz +amtszeit +analog +analogie +analyse +analysiert +analysis +analysten +analytiker +anarchie +anatomie +anbau +anbetracht +anbieten +anbieter +anbindung +anblick +anbrennen +anbringen +andacht +andauern +andenken +andernorts +anders +anderseits +anderswo +andrang +androhung +anekdoten +anerkennen +anfahrt +anfallen +anfang +anfangen +anfangs +anfassen +anflug +anfrage +anfreunden +angaben +angeben +angeblich +angebot +angegeben +angeht +angeklagte +angel +angeln +angemessen +angenehm +anger +angesicht +angetan +angewiesen +angler +angreifen +angreifer +angriff +angst +anhalten +anhaltend +anhang +anheben +anhebung +anhieb +anhin +animation +animieren +ankauf +anker +anklage +anklang +ankommt +ankunft +anlage +anlass +anlauf +anlegen +anleger +anlehnung +anleihen +anleitung +anliegen +anlieger +anlocken +anmelden +anmeldung +anmerken +anmerkung +anna +annahme +annalen +annehmen +anno +anonym +anordnung +anpacken +anpassen +anpassung +anpfiff +anrainer +anregen +anregungen +anreise +anreisen +anreiz +anrichten +anruf +anrufen +anrufer +ansage +ansammlung +ansatz +anschauen +anschauung +anschein +anschlag +anschluss +anschrift +ansehen +ansetzen +ansicht +ansiedeln +ansiedlung +ansinnen +ansonsten +anspannung +anspielung +ansporn +ansprache +ansprechen +anspruch +anstalt +anstand +ansteht +ansteigen +anstellen +anstellung +anstieg +anstreben +anstrich +ansturm +antarktis +anteil +antenne +antike +antlitz +antrag +antreten +antrieb +antritt +antwort +antwortete +anwalt +anweisung +anwendbar +anwenden +anwender +anwendung +anwesen +anwesend +anwesenden +anwohner +anzahl +anzeichen +anzeige +anzeigen +anzeiger +anziehen +anzug +apartheid +apfel +apostel +apotheke +apotheker +apparat +appell +appelliert +appetit +applaus +april +apropos +aquarelle +aquarium +araber +arabisch +arbeit +arbeiter +arbeitet +arbeitsamt +arbeitslos +arbeitstag +arche +architekt +archive +areal +arena +arg +arge +argument +arie +arm +armee +armenier +armut +aroma +arrogant +arroganz +arsenal +art +artikel +artillerie +artisten +arzt +asche +asiaten +aspekte +asphalt +asse +assistent +ast +asthma +aston +astrologie +astronomen +astronomie +asyl +atelier +atem +atemzug +athener +athleten +athletin +atlantik +atlas +atmet +atombombe +atome +atomkraft +atomwaffen +attacke +attentat +attila +attraktion +attraktiv +attribute +auch +audi +auditorium +aue +aufatmen +aufbau +aufbauen +aufbrechen +aufbringen +aufbruch +aufenthalt +auffahrt +auffallen +auffallend +auffassung +auffordern +aufgabe +aufgeben +aufgebot +aufgehen +aufgreifen +aufhalten +aufheben +aufhebung +aufholen +aufholjagd +aufhorchen +aufkleber +aufkommen +auflage +auflaufen +aufleben +auflistung +aufmarsch +aufmerksam +aufnahme +aufnehmen +aufpassen +aufprall +aufpreis +aufregend +aufregung +aufruf +aufrufen +aufruhr +aufsatz +aufschlag +aufschluss +aufschrei +aufschrift +aufschub +aufschwung +aufsehen +aufsicht +aufspielen +aufstand +aufstehen +aufsteigen +aufsteiger +aufstellen +aufstieg +aufstocken +aufsuchen +auftakt +auftauchen +aufteilung +auftrag +auftreten +auftrieb +auftritt +aufwand +aufwarten +aufweist +aufwendig +aufwertung +aufwind +aufzeigen +aufzug +augen +augenblick +augenmerk +august +auktion +aula +aura +aus +ausbau +ausbauen +ausbeute +ausbeutung +ausbilden +ausbilder +ausbildung +ausblick +ausbreiten +ausbruch +ausdauer +ausdehnung +ausdruck +ausfahrt +ausfall +ausfallen +ausfindig +ausflug +ausfuhren +ausgabe +ausgang +ausgeben +ausgehen +ausgehend +ausgiebig +ausgleich +aushalten +auskennt +ausklang +ausklingen +auskommen +auskunft +ausland +auslastung +auslaufen +auslegung +auslosung +ausmachen +ausmass +ausnahme +ausrede +ausreichen +ausreise +ausrichten +ausrichter +ausruhen +aussage +aussagen +ausschau +ausschied +ausschlag +ausschluss +ausschnitt +ausschuss +aussehen +aussendung +aussetzen +aussetzung +aussicht +aussiedler +ausspielen +aussprache +ausspricht +ausspruch +ausstand +aussteigen +ausstellen +aussteller +aussterben +ausstieg +aussuchen +austausch +austoben +austragen +austragung +australier +austritt +ausverkauf +auswahl +ausweg +ausweichen +ausweis +ausweisen +ausweisung +ausweiten +ausweitung +auswendig +auswertung +auswirken +auswirkung +auszahlen +auszahlung +auszeit +ausziehen +auszug +auto +autobahn +autobauer +autofahren +autofahrer +autogramme +autohaus +automaten +automobil +autonomie +autor +autorin +autostadt +autounfall +avancierte +avantgarde +ave +avenue +axt +azubis +baby +bach +bachelor +back +backen +backhaus +bad +baden +badener +badewanne +badezimmer +badminton +bagger +bahn +bahnchef +bahnhof +bahnlinie +bahnsteig +bahnt +baier +baker +bakterien +balance +bald +balken +balkon +ball +ballack +balladen +ballbesitz +ballett +ballon +bamberger +banal +bananen +band +bandbreite +bande +banden +bandleader +bangen +bank +banker +bankier +banking +banknoten +bankrott +bann +banner +bansin +baptist +bar +bargeld +bariton +barmer +barock +baron +barrel +barrieren +barrikaden +bart +basar +base +baseball +basierend +basiert +basilika +basis +basketball +basler +bass +bassist +basteln +bataillon +batterien +bau +bauamt +bauart +baubeginn +baubranche +bauch +baudenkmal +bauen +bauern +bauernhaus +bauernhof +baufirma +baugebiet +baugewerbe +bauhaus +bauherren +bauhof +baujahr +baukosten +bauland +baum +baumarkt +baumeister +baumholder +baumwolle +bauphase +bauprojekt +baurecht +baureihe +bausch +baustein +baustelle +baustopp +bauteile +bauweise +bauwerk +bauwesen +bauzeit +bayern +bayreuther +beachten +beachtlich +beachtung +beamten +beantragen +bearbeiten +beat +bebauung +beben +becher +becken +bedankte +bedarf +bedauert +bedeckt +bedenken +bedenklich +bedeutend +bedeutet +bedeutsam +bedeutung +bedienen +bedienung +bedingt +bedingung +bedrohlich +bedroht +bedrohung +bedurfte +beendete +beendigung +beerdigung +beeren +befahl +befahrbar +befassen +befehl +befindet +befragen +befragten +befragung +befreien +befreiung +befugnisse +befund +begabung +begegnen +begegnet +begegnung +begehren +begehrt +begeht +begehung +begeistern +begeistert +begibt +begierde +beginn +beginnend +beginnt +begleichen +begleiter +begleitet +begleitung +begreifen +begrenzen +begrenzt +begrenzung +begriff +behalten +behandeln +behandlung +beharrlich +beharrt +behaupten +behauptung +beheben +beherbergt +beherrscht +behilflich +behindern +behindert +behinderte +behutsam +beibringen +beifahrer +beifall +beihilfe +beilage +beileibe +beinahe +beinamen +beine +beinhaltet +beirat +beisein +beiseite +beisetzung +beisitzer +beispiel +beistand +beisteuern +beitrag +beitragen +beitreten +beitritt +bekannt +bekannten +bekanntgab +bekennt +bekenntnis +beklagt +bekleidet +bekleidung +bekommen +bekunden +belag +belagerung +belange +belassen +belasten +belastet +belastung +belaufen +beleben +belebung +belege +belegte +beleidigt +beleuchten +belgier +belgrader +belieben +beliebig +beliebt +beliefert +belohnt +belohnung +bemerkbar +bemerkte +bemerkung +benehmen +benennen +benennung +benutzen +benutzer +benutzung +benzin +benziner +beobachten +beobachter +bequem +berappen +beraten +berater +beratung +berechnen +berechnung +berechtigt +bereich +bereichern +bereit +bereitet +bereits +berg +bergab +bergauf +bergbahnen +bergbau +bergheim +bergisch +bergland +bergleute +bergung +bergwerk +bericht +berichtete +berlinale +berliner +berlinerin +berner +bertrand +beruf +berufen +beruflich +berufswahl +berufung +beruhigen +beruhigend +beruhigung +beruht +besagt +besatzung +beschaffen +bescheid +bescheiden +bescherte +bescherung +beschloss +beschluss +beschreibt +beschuss +beschwerde +beschwert +beseitigen +besen +besetzt +besetzten +besetzung +besiedlung +besiegte +besinnen +besinnung +besitz +besitzer +besitzerin +besitzt +besonderes +besonders +besorgen +besorgnis +besorgt +besprechen +besseren +besserung +bestand +bestattung +bestaunen +bestechung +bestehend +besteht +bestellen +bestellung +besten +bestens +besticht +bestimmt +bestimmung +bestmarke +bestrafen +bestrafung +bestreben +bestrebt +bestritt +bestseller +bestzeit +besuch +besucher +besuchte +beteiligen +beteiligte +beten +beteuerte +beton +betonte +betonung +betracht +betrachter +betrachtet +betrag +betreffend +betreiber +betreibt +betreuen +betreuer +betreuerin +betreuung +betrieb +betrifft +betritt +betroffene +betrug +bett +bettler +beugen +beurteilen +beute +beutel +bevorzugt +bewaffnung +bewahren +bewahrung +bewegt +bewegung +beweis +beweisen +bewerben +bewerber +bewerbung +bewertet +bewertung +bewirken +bewirtung +bewohner +bewundern +bewusst +bezahlen +bezahlung +bezeichnet +bezeugt +bezieht +beziehung +beziffert +bezirk +bezirksamt +bezug +bezwang +bezweifeln +bibel +biber +bibliothek +biedermann +bienen +biennale +bier +biergarten +bieter +bietet +bike +biker +bilanz +bild +bildband +bilden +bilderbuch +bildhauer +bildnis +bildschirm +bildung +billiger +billigte +billionen +bindeglied +binden +binder +bindung +bingen +biografie +biographie +biologe +biologie +biologisch +biomasse +biotop +birgt +birken +birnen +bischof +bisher +bislang +biss +bisschen +bistro +bistum +bisweilen +bit +bitte +bitter +blamage +blank +blase +blasmusik +blass +blatt +blatter +blau +blaulicht +blech +blei +bleibe +bleibt +bleistift +blessuren +blick +blickfang +blickfeld +blickpunkt +blickt +blind +blitz +bloch +blocher +block +blockade +blockieren +bloss +blues +blumen +blut +blutbad +blutdruck +blutig +blutprobe +blutspende +bluttat +board +bob +bobstadt +boden +bogen +bohlen +bohnen +bollwerk +bolzplatz +bombe +bomber +bon +bond +bonus +boom +boomt +boot +bord +bordeaux +bosnier +boss +botanik +botaniker +botschaft +boulevard +box +boxer +boykott +boys +brach +branche +brand +bratwurst +brauch +braucht +brauchtum +brauer +brauerei +brauhaus +braun +braunkohle +braut +brav +bravo +bravour +break +breit +breite +breitet +bremer +bremsen +brennpunkt +brennstoff +brennt +bresche +brett +bridge +brief +briefmarke +brigade +brillant +brille +bringen +brisanz +briten +broadway +brocken +brockhaus +bronze +bronzezeit +brot +browser +bruch +bruchteil +bruchweg +bruder +brunn +brunnen +brust +brustkrebs +brutal +brutto +bub +buben +buch +buchautor +buche +buchen +buchenwald +buchhandel +buchmesse +buchstaben +bucht +buchungen +buckel +budapester +buddha +buddhismus +bude +budenheim +budget +buffet +bug +bulgaren +bulle +bulletin +bund +bundesamt +bundesbahn +bundesbank +bundesheer +bundesland +bundesliga +bundesrat +bundestag +bundeswehr +bundesweit +bunker +bunt +burg +burghausen +burgruine +burschen +bus +busbahnhof +busen +busfahrer +busfahrt +business +buslinien +butler +butter +button +bytes +cabrio +cafeteria +camp +campus +cannabis +capitol +card +cash +casino +ccm +cds +cello +celsius +cembalo +cent +centers +centrum +ceo +cest +champagner +champions +chance +chancenlos +chansons +chaos +charakter +charmant +charme +charta +charts +chauffeur +chaussee +check +chef +chefarzt +chefcoach +chefin +chefsache +chemie +chemiker +chemnitzer +chinesen +chinesisch +chips +chirurg +chirurgie +chor +chorgesang +chorleiter +chorprobe +christen +christkind +christlich +christus +chronik +chronisch +chronist +circa +city +clan +clever +clown +club +clubhaus +coach +cockpit +cocktails +code +collagen +college +comeback +comedy +comics +community +computer +container +contra +cool +corps +couch +couleur +countdown +country +coup +courage +court +cousin +cousine +cover +cowboys +crash +credo +crew +cruise +cup +dach +dachboden +dachstuhl +daheim +damals +damen +damm +dampf +dank +dankbar +dankte +dann +danziger +darbietung +darf +darlegen +darlehen +darm +darsteller +darstellt +darunter +dasein +dastehen +datei +daten +datenbank +datiert +datierung +dauer +dauerhaft +dauernd +dauert +daumen +dealer +debakel +debatte +deck +decke +deckel +deckt +deckung +defekte +defekter +defensiv +defensive +definieren +definition +definitiv +defizit +deich +dekan +dekanat +dekoration +dekret +delegation +delegierte +delikte +delta +demenz +demo +demokraten +demokratie +demontage +demut +denkbar +denke +denker +denkmal +denn +dennoch +deponie +depot +depp +depression +derart +derartig +derby +dereinst +derweil +derzeit +des +desaster +design +designer +dessert +details +detektiv +deutet +deutlich +deutsch +deutschen +deutung +devise +dezember +dezent +dezernent +dezibel +dezidiert +diabetes +diabetiker +diagnose +diagnostik +diakon +diakonie +dialekt +dialektik +dialog +diamanten +diamond +dias +diavortrag +dicht +dichte +dichter +dichterin +dichtung +dick +dicke +diebe +diebesgut +diebstahl +diener +dienst +dienstag +dienstags +dienstzeit +dient +diesel +diesmal +differenz +digital +diktat +diktator +diktatur +dilemma +dimension +dinge +dinner +dino +diplom +diplomaten +diplomatie +direkt +direktion +direktor +direktorin +direktwahl +dirigent +dirigierte +disco +discounter +disk +disko +diskothek +diskrepanz +diskret +diskurs +diskussion +display +disput +distanz +distrikt +disziplin +diva +dividende +division +djs +dna +doch +doktor +dokumente +doll +dollar +dom +dominanz +dominierte +domizil +donner +donnerstag +doof +doping +doppel +doppelpack +doppelsieg +doppelt +doppelte +dorf +dorffest +dorfkirche +dorfplatz +dorn +dort +dorthin +dose +dosen +dosis +dossier +dotierten +double +download +dozent +drache +drachen +draht +drama +dramatik +dramatiker +dramatisch +drang +drastisch +dreck +dreh +drehbuch +drehmoment +dreht +drehung +drei +dreieck +dreier +dreifach +dreimal +dresdner +dressur +dringend +dringt +drinnen +drittel +drittens +dritter +drogen +droht +drohung +druck +drucken +drucker +druckerei +drucksache +dschihad +dschungel +duell +duett +duft +duisburger +dulden +duldung +dumm +dummheit +dunkel +dunkelheit +dunkeln +dunst +duo +durchaus +durchbruch +durchfahrt +durchgang +durchgehen +durchweg +durchwegs +durst +dusche +dutzend +dvd +dynamik +dynamisch +dynastie +eben +ebenda +ebene +ebenfalls +ebenso +eberswalde +ebner +echo +echt +echtheit +eck +eckball +ecke +ecker +eckpunkte +edelmann +edelmetall +eden +edition +effekt +effektiv +effizient +effizienz +egal +eggenburg +egger +ego +egoismus +ehe +ehefrau +ehegatten +eheleute +ehemals +ehemann +ehepaar +ehepartner +eher +ehre +ehrenamt +ehrengast +ehrenmal +ehrennadel +ehrfurcht +ehrgeiz +ehrgeizig +ehrlich +ehrte +ehrungen +eiche +eichel +eid +eier +eifer +eifersucht +eifrig +eigen +eigener +eigenheim +eigenregie +eigens +eigentlich +eigentor +eigentum +eigner +eignet +eignung +eile +eilig +eilt +eimer +einbau +einbauen +einbinden +einbindung +einblick +einbrecher +einbringen +einbruch +eindeutig +eindringen +eindruck +einen +einer +einerseits +einfach +einfahren +einfahrt +einfall +einfallen +einfluss +einfordern +einfuhr +eingabe +eingang +eingehen +eingehend +eingreifen +eingriff +einhalt +einhalten +einhaltung +einheit +einhellig +einholen +einig +einige +einigen +einigkeit +einigung +einkauf +einkaufen +einkehr +einklang +einkommen +einladen +einladung +einlagen +einlass +einlassen +einlegen +einleiten +einleitung +einlenken +einmal +einmalig +einmarsch +einmischen +einnahmen +einnehmen +einordnen +einordnung +einreichen +einreise +einrichten +eins +einsam +einsamkeit +einsatz +einschnitt +einsehbar +einsehen +einseitig +einsetzbar +einsetzen +einsetzung +einsicht +einsparen +einsparung +einspruch +einst +einstand +einstecken +einsteigen +einsteiger +einstellen +einstieg +einstimmig +einstmals +einstufung +einsturz +einteilung +eintracht +eintrag +eintragen +eintragung +eintreffen +eintreten +eintritt +einwand +einweihung +einwohner +einwurf +einzel +einzelfall +einzeln +einzelnen +einzelplan +einziehen +einzig +einzug +eis +eisbachtal +eisen +eisenbahn +eisenstadt +eishalle +eishockey +eiskalt +eiszeit +eitel +eitelkeit +eklat +elan +elefanten +elegant +eleganz +elektriker +elektrisch +elektronen +elektronik +elemente +elend +elf +elfer +elfmeter +elite +elster +eltern +elterngeld +elternhaus +elternteil +embryonen +emigranten +emigration +emigrierte +emir +emirate +emissionen +emotional +emotionen +empfang +empfehlung +empfiehlt +empfindet +empfindung +empfing +empire +empore +ende +endeffekt +enders +endet +endlager +endlich +endlos +endphase +endpunkt +endrunde +endspiel +endspurt +endstand +endstation +energie +energisch +eng +engadin +engagement +engagiert +enge +engel +englands +englisch +englischen +enkel +enkelin +enorm +ensemble +entdecken +entdecker +entdeckung +enteignung +enten +enterprise +entfalten +entfaltung +entfernen +entfernt +entfernung +entfielen +entgegnete +entgehen +entgelt +enthaltung +enthielt +entkommen +entlassen +entlassung +entlasten +entlastung +entlocken +entnehmen +entpuppte +entrichten +entscheid +entschied +entschloss +entschluss +entsenden +entsendung +entsetzen +entsetzt +entsorgen +entsorgung +entspannen +entspannt +entspricht +entspringt +entstammte +entstand +entstehung +entwarf +entwarnung +entwickeln +entwickler +entwurf +entziehen +entzug +episode +epoche +equipe +erachtens +erahnen +erarbeiten +erbauer +erbaut +erbe +erbgut +erblickte +erbringen +erdbeben +erdbeeren +erdboden +erde +erdgas +erdreich +ereignete +ereignisse +erfahrung +erfassen +erfassung +erfinden +erfinder +erfindung +erfolg +erfolglos +erfolgt +erfordern +erforschen +erfreuen +erfreulich +erfreut +erfuhr +ergattern +ergebnis +ergibt +erging +ergo +ergreifen +ergreifend +erhalt +erhaltung +erheben +erheblich +erhebung +erhielt +erhofft +erholen +erholung +erinnert +erinnerung +erkennbar +erkennen +erkenntnis +erklingt +erkrankung +erkunden +erkundung +erlag +erlanger +erlangte +erlass +erlauben +erlaubnis +erlebnis +erlebt +erledigen +erlernen +erlitt +ermessen +ermitteln +ermittler +ermittlung +ermordung +ernannte +ernennung +erneuern +erneuerung +erneut +ernst +ernstfall +ernsthaft +ernte +erntete +erobern +eroberung +eros +erosion +erotik +erpressung +erprobung +errang +erreger +erregte +erregung +erreichbar +erreichen +errichten +errichtung +ersatz +ersatzbank +ersatzlos +erscheint +erschweren +ersetzen +erspart +erspielte +erst +erstatten +erstaunen +erstaunt +erstellen +erstellung +ersten +erstenmal +erstens +ersticken +erstmal +erstmalig +erstmals +erstreckt +erteile +erteilung +ertrag +ertragen +erwachsene +erwacht +erwarb +erwartet +erwartung +erwecken +erweitern +erwerb +erwiderte +erwies +erwischte +erzbischof +erzbistum +erzeugen +erzeuger +erzeugung +erzgebirge +erzherzog +erziehen +erzieher +erzieherin +erziehung +erzielte +erzrivalen +erzwingen +esel +eskalation +esoterik +essays +essen +essener +etablieren +etage +etappe +etat +etc +ethik +ethnien +etikett +etwa +etwas +etymologie +eulen +euphorie +euphorisch +euro +europacup +europarat +europawahl +europaweit +eurosport +eurovision +eurozone +evaluation +evangelium +event +eventuell +evolution +ewig +ewigkeit +exakt +examen +exekutive +exempel +exemplare +exil +existenz +existieren +exklusiv +exkursion +expansion +expedition +experiment +experten +expertin +expertise +explizit +explosion +expo +exponate +export +exposition +extra +extrem +extremfall +exzellent +fabrik +facetten +fach +facharzt +fachgebiet +fachleute +fachlich +fachmann +fachmesse +fachschule +fachstelle +fachtagung +fachwelt +fachwissen +faden +fahnder +fahndung +fahne +fahrbahn +fahren +fahrer +fahrerin +fahrgast +fahrplan +fahrrad +fahrt +fahrverbot +fahrweise +fahrwerk +fahrzeit +fahrzeuge +fair +fairness +fakt +fakten +faktisch +faktoren +falken +fall +falle +fallen +falsch +falten +falter +familie +fang +fans +fantasie +farben +farbig +farblich +farce +farmer +fasching +faschismus +fasern +fashion +fasnacht +faso +fass +fassade +fassen +fassung +fast +fastenzeit +fastnacht +fasziniert +fatal +faul +fauna +faust +favoriten +favoritin +fax +fazit +februar +feder +federer +fee +feedback +fehlbetrag +fehler +fehlerfrei +fehlerhaft +fehlstart +fehlt +feier +feierabend +feierlich +feiert +feiertag +fein +feind +feinheiten +feinstaub +feinsten +feld +feldberger +feldzug +fell +fels +felsen +feminismus +fenster +ferien +ferienzeit +fernab +ferne +ferner +fernost +fernsehen +fernseher +ferrari +fersen +fertig +fertigte +fertigung +fesseln +fest +festakt +feste +festhalle +festhalten +festigen +festival +festland +festlegen +festlegung +festlich +festnahme +festnehmen +festnetz +festplatte +festplatz +festsaal +festspiele +feststeht +feststellt +festtage +festumzug +festung +festwochen +festzelt +festzug +fett +feucht +feuer +feuerte +feuerwache +feuerwehr +feuerwerk +feuilleton +fiasko +fichte +fidel +fieber +fiel +figaro +figuren +fiktion +file +filialen +film +filmmusik +filmpreis +filmtitel +filter +filz +final +finale +finalisten +finalrunde +finanzamt +finanzchef +finanzen +finanziell +finanziert +finanzlage +findet +fing +finger +finnen +finsternis +firma +firmenchef +firmensitz +first +fis +fisch +fischerei +fischler +fiskus +fit +fitness +fix +flach +flagge +flair +flammen +flandern +flanke +flasche +flash +flaute +fleck +flecken +fledermaus +fleisch +flexibel +fliegen +flieger +fliehen +fliesen +flohmarkt +flop +flora +flossen +flott +flotte +fluch +flucht +flug +flugblatt +flughafen +fluglinie +flugplatz +flugs +flugzeug +flur +fluss +flut +fokus +folge +folgejahr +folgend +folgenden +folgendes +folgezeit +folglich +folgt +folie +folk +folklore +folter +fonds +food +football +forcieren +fordert +forderung +form +formal +format +formation +formel +formell +formen +formsache +formulare +formuliert +forscher +forscht +forschung +forst +forstamt +forsthaus +fort +fortan +fortgang +fortsetzen +forum +fossilien +foto +fotografen +fotografie +fotografin +foul +foulspiels +foyer +fracht +frachter +frage +fragebogen +fraglich +fragmente +fragt +fraktion +franc +franken +franzosen +frau +frauenchor +frauenfeld +frauenhaus +frech +frechheit +frei +freibad +freien +freier +freigabe +freiheit +freiherr +freikarten +freilich +freimaurer +freiraum +freispruch +freistaat +freistil +freitag +freitags +freiwillig +freizeit +fremd +fremde +frequenz +fresken +fressen +freude +freudig +freunde +freundin +freundlich +freut +friede +frieden +friedhelm +friedhof +friedland +friedlich +fries +frisch +frische +friseur +frist +fristlos +frisur +froh +frohsinn +fromm +front +frontal +frontmann +frosch +frost +frucht +frust +fuchs +fugen +fund +fundament +fundort +fundus +fungierte +funk +funke +funken +funktion +furcht +furchtbar +furore +fusion +fuss +fussball +fussballer +futter +future +gabe +gabel +gag +gage +gala +galerie +gallen +galler +gang +gangart +gangster +gans +ganz +ganze +gar +garage +garant +garantie +garantiert +garde +garderobe +garnitur +garten +gartenbau +gas +gassen +gast +gastgeber +gasthaus +gasthof +gastiert +gastspiel +gastwirt +gate +gatten +gattin +gattung +gaumen +gebet +gebiet +gebieten +gebilde +gebirge +geboren +gebot +gebrauch +gebrauchen +gebraucht +geburt +geburtsort +geburtstag +gedanken +gedeiht +gedenken +gedenktag +gedichte +geduld +geduldig +geeignet +gefahr +gefallen +gefallenen +gefangenen +gefecht +gefolge +gegend +gegenprobe +gegensatz +gegenseite +gegenstand +gegenteil +gegentor +gegenwart +gegenwehr +gegenwind +gegenzug +gegner +gegnerin +gehalt +gehege +geheim +geheimnis +geheimtipp +gehend +gehirn +gehorsam +geht +gehweg +geige +geil +geiseln +geist +geistig +geistliche +gelang +gelangen +gelassen +gelaunt +gelbe +geld +geldbeutel +geldgeber +geldstrafe +gelehrten +geliebte +geltend +geltung +gemahlin +gemarkung +gemein +gemeinde +gemeinhin +gemeinsam +gemeinwohl +gemessen +gemisch +gemischt +gemischte +genau +genauso +gendarmen +gene +genehmigen +general +generation +generell +genesis +genesung +genetisch +genial +genie +genoss +genossen +genre +gent +gentechnik +gentleman +genug +genugtuung +genuss +geografie +geographie +geologe +geologie +geometrie +gerade +geradeaus +geradezu +gerangel +gerecht +gerede +gericht +geriet +gering +germanen +gern +gerne +geruch +gesamtbild +gesamtheit +gesamtjahr +gesamtsieg +gesamtwerk +gesamtwert +gesamtzahl +gesang +geschenk +geschichte +geschick +geschickt +geschieht +geschirr +geschlecht +geschmack +geschoss +geschosse +geschrei +geschweige +gesetz +gesetzlich +gesicht +gesinnung +gesondert +gespann +gespannt +gespenst +gestalt +gestalten +gestaltung +gestand +gestapo +gestatten +geste +gestein +gestern +gestik +gestorben +gesuch +gesund +gesundheit +getragen +getreide +getrennt +getreu +getriebe +getrost +gewagt +gewahrsam +gewalt +gewaltig +gewaltsam +gewand +gewann +gewebe +gewehr +gewerbe +gewicht +gewichtung +gewillt +gewinn +gewinner +gewinnerin +gewinnung +gewinnzone +gewiss +gewissen +gewissheit +gewitter +gewohnheit +gezielt +ghetto +gibt +giebel +gier +gift +giftig +giganten +gilt +gipfel +gips +girls +giro +gitarre +gitarrist +gitter +gladbacher +glamour +glanz +glarner +glas +glatt +glaube +glauben +glaubhaft +gleich +gleichauf +gleiche +gleichheit +gleichsam +gleicht +gleichung +gleichwohl +gleise +gletscher +glied +gliedert +gliederung +glimpflich +global +globus +glocke +gloria +gmbh +gnade +gnadenlos +goalie +gold +golden +golf +golfer +golfkrieg +golfplatz +gong +google +gott +gotteshaus +gottheit +gouverneur +grab +graben +grabmal +grabstein +grabungen +grad +grafen +graffiti +grafik +grafiker +grafschaft +gramm +grammatik +granaten +grandios +granit +gras +grasser +grat +gratis +grau +grauen +grausam +gravierend +grazer +greif +greifbar +greifswald +greift +greis +gremium +grenzen +grenzt +grenzwerte +griechen +griechisch +griff +grill +grillen +grillfest +grinst +grippe +grob +gros +groschen +gross +grossen +grossteil +grotesk +grube +grund +grundlage +grundrecht +grundriss +grundsatz +grundstein +gruppe +gucken +guerilla +guide +gulden +guldental +gunsten +gut +gutachten +gutachter +guten +guthaben +gutschein +gutshaus +gymnasium +gymnastik +haare +hab +haben +hacker +haderte +hafen +hafenstadt +hafner +haft +haftbefehl +haftet +haftstrafe +haftung +hagel +hager +hahn +haie +hain +haken +halb +halbfinal +halbfinale +halbfinals +halbieren +halbinsel +halbjahr +halbwegs +halbzeit +hall +halle +hallein +hallen +hallenbad +haller +hals +halt +haltbar +halten +haltepunkt +halter +haltung +hamas +hamburger +hammer +hand +handarbeit +handball +handballer +handbuch +handel +handelt +handgelenk +handhabung +handicap +handlung +handschlag +handschuhe +handtasche +handtuch +handvoll +handwerk +handwerker +handys +hanf +hang +hanse +hanseaten +hansestadt +hardliner +hardware +harfe +harmlos +harmonie +harmonisch +harms +hart +hartberg +hartplatz +harz +haschisch +hasen +hasler +hass +hast +hattrick +haube +hauch +hauer +haufen +hauptautor +hauptfigur +hauptgrund +hauptort +hauptplatz +hauptpreis +hauptrolle +hauptrunde +hauptsache +hauptsitz +hauptstadt +hauptteil +hauptthema +hauptwerk +hauptziel +haus +hausarrest +hausarzt +hausen +hausfrau +haushalt +hausherren +haustiere +haut +hautfarbe +hautnah +hebamme +hebel +heber +hecht +hechtsheim +heck +hecken +heer +heft +heftig +hegt +hehl +heiden +heikel +heil +heilen +heilig +heiligen +heilung +heim +heimat +heimatland +heimatort +heimfahrt +heimisch +heimischen +heimkehr +heimlich +heimrecht +heimreise +heimsieg +heimspiel +heimweg +heimweh +heirat +heiratete +heisst +heiter +heiterkeit +heizkosten +heizt +heizung +hektar +hektik +hektisch +helden +heldin +helfen +helfer +helikopter +hell +helligkeit +helm +hemd +hengst +her +heraus +herausgabe +herbst +herd +herde +herhalten +hering +herkunft +heroin +herold +herr +herrchen +herrenhaus +herrlich +herrschaft +herrscher +herrscht +herrstein +herstellen +hersteller +hervorgeht +herz +herzblut +herzlich +herzogin +herzogtum +hesse +heu +heuchelei +heuer +heut +heute +heutzutage +hexe +hier +hierarchie +hierher +high +highlight +highway +hilfe +hilflos +hilfreich +hilfswerk +hiller +himmel +himmler +hin +hinab +hinauf +hinaus +hinausgeht +hinblick +hindern +hindernis +hindurch +hinein +hing +hingabe +hingegen +hingehen +hinkt +hinnehmen +hinrunde +hinsehen +hinsicht +hinspiel +hinten +hinterher +hinterhof +hinterkopf +hinterland +hinterlegt +hintern +hinunter +hinweg +hinweise +hinweisen +hinzu +hip +hirn +hirten +his +hisbollah +historie +historiker +historisch +history +hitparade +hits +hitze +hitzfeld +hob +hobby +hoch +hochamt +hochburg +hochdruck +hochhaus +hochland +hochschule +hochsprung +hochstift +hochtief +hochtouren +hochwasser +hochzeit +hockenheim +hockey +hof +hofbauer +hofburg +hoffenheim +hoffnung +hofft +hofheimer +hofmeister +hofrat +hoheit +hohn +holding +hollande +holocaust +holte +holz +holzer +holzheim +homepage +hommage +homo +honig +honorar +hooligans +hopp +horchheim +horizont +horn +horror +hort +hosen +hospital +hospiz +hotel +hoteliers +hotellerie +hotline +hubraum +huhn +hummel +humor +humorvoll +hund +hunderte +hunger +hungrig +hurrikan +hut +hygiene +hymne +hypothese +hysterie +ideal +idealfall +idealismus +idee +identisch +ideologie +idol +idylle +igel +ignoranz +ignorieren +ihrerseits +ikone +illegal +illusion +image +imam +imbiss +imker +immens +immer +immerhin +immobilien +imperial +imperium +impfstoff +impfung +importe +impulse +imstande +inbegriff +inder +indes +indessen +index +indianer +indikator +indirekt +individuen +indiz +industrial +industrie +ineinander +infanterie +infektion +inflation +infoabend +infobox +informatik +informativ +informiert +infos +ingenieur +inhaber +inhaberin +inhalt +inhaltlich +initianten +initiative +initiator +initiierte +inland +innehatte +innen +innenhof +innenleben +innenraum +innenstadt +inneren +innerlich +innovation +innovativ +insassen +inschrift +insekten +insel +insgeheim +insgesamt +insider +insofern +insolvenz +insoweit +inspektion +inspektor +instanz +institut +instrument +inszeniert +intakt +integriert +intendant +intensiv +intention +interesse +interfax +intern +internat +internet +interview +intoleranz +intrigen +invasion +inventar +investiert +investment +investoren +inwiefern +inwieweit +inzwischen +iraker +iraner +iren +irgend +irgendwann +irgendwie +irgendwo +irlich +ironie +ironisch +irre +irrelevant +irrt +irrtum +islam +islamisten +isolation +isoliert +isolierung +israelis +ist +italiener +jacke +jackpot +jagd +jagt +jaguar +jahr +jahrbuch +jahrelang +jahresende +jahrestag +jahreszahl +jahreszeit +jahrgang +jahrmarkt +jahrzehnte +januar +japaner +jassir +javier +jazz +jeans +jedenfalls +jederzeit +jedesmal +jedoch +jeep +jeher +jemals +jenseits +jesu +jesuiten +jet +jetzt +jeweils +job +jobcenter +joint +joker +journal +journalist +jubel +jubeln +jubilar +jubilarin +juden +judentum +judo +judoka +jugend +jugendamt +jugendchor +jugendhaus +jugendheim +jugendraum +jugendstil +juli +jung +jungen +jungfrau +jungs +jungtiere +juni +junioren +junker +jurist +juristin +juristisch +juroren +jury +jusos +just +justiz +kabarett +kabel +kabine +kabinett +kader +kaffee +kahl +kai +kaiser +kaiserin +kakao +kalb +kalender +kaliber +kalk +kalorien +kalt +kaltbrunn +kamera +kameraden +kamin +kamm +kammer +kammerchor +kampagne +kampf +kampfgeist +kampflos +kanadier +kanal +kandidaten +kandidatin +kandidatur +kandidiert +kaninchen +kann +kanon +kanonen +kantate +kanten +kantersieg +kantine +kanton +kantonsrat +kantor +kantorei +kanu +kanzel +kanzlei +kanzler +kanzleramt +kanzlerin +kap +kapelle +kapital +kapitel +kaplan +kappe +kapstadt +kaputt +karate +kardinal +karfreitag +karikatur +karneval +karosserie +karren +karriere +kartellamt +karten +kartmann +kartoffeln +karton +karussell +kaschmir +kaserne +kasper +kasse +kasseler +kassen +kassenwart +kassier +kassierer +kassierte +kastell +kasten +katalog +kategorie +kater +kathedrale +katholiken +katholisch +katze +kauf +kaufen +kaufhaus +kaufhof +kaufkraft +kaufleute +kaufmann +kaufpreis +kaum +kaution +kavallerie +keeper +kegeln +kehle +kehrseite +kehrte +kehrtwende +keim +keineswegs +keller +kellner +kelten +kenner +kennt +kenntnis +kennwort +keramik +kerber +kerl +kern +kernstadt +kerzen +kessel +kette +keyboard +khan +khmer +kick +kicker +kids +kiefer +kies +kiez +killer +kilo +kilogramm +kilometer +kinder +kinderbuch +kinderchor +kinderfest +kindergeld +kinderheim +kinderlos +kindheit +kinn +kino +kinofilm +kinowelt +kiosk +kippe +kippen +kirche +kirchentag +kirchhof +kirchplatz +kirchspiel +kirchturm +kirmes +kissen +kiste +kitas +kitsch +klafft +klage +klagenfurt +klagt +klammern +klamotten +klang +klappe +klappt +klar +klaren +klarheit +klarinette +klartext +klasse +klassik +klassiker +klassisch +klausel +klausur +klavier +kleber +klebt +klee +kleider +kleidung +klein +kleinbus +kleinen +kleinkind +kleinod +kleinstadt +kleinsten +kleinwagen +klemm +klerus +kletterte +klick +klientel +klienten +klima +klinge +klingelt +klinger +klingt +klinik +klinikum +klischees +klopft +kloster +klotz +klub +klubobmann +kluft +klug +knaben +knacken +knackpunkt +knall +knaller +knapp +knast +kneipe +knien +knoblauch +knochen +knopf +knopfdruck +knoten +koalition +koblenzer +kochbuch +kochen +koffer +kofferraum +kohle +kohlhammer +kokain +kollaps +kollegen +kollegin +kollegium +kollekte +kollektion +kollektiv +koller +kollision +kolonie +kolumne +koma +kombi +kombiniert +kometen +komfort +komik +komiker +komisch +komitee +komma +kommandant +kommandeur +kommando +kommend +kommentar +kommissar +kommission +kommt +kommunen +kommunist +kompakt +kompanie +kompatibel +kompetent +kompetenz +komplett +komplex +kompliment +komplizen +komponente +komponist +kompromiss +kondition +konferenz +konfession +konflikt +kongress +konjunktur +konkret +konkurrent +konkurrenz +konkurs +konsens +konsequent +konsequenz +konsortium +konstant +konstrukt +konsul +konsum +kontakt +konter +konterte +kontext +kontinent +kontingent +konto +kontrabass +kontrakt +kontrast +kontrolle +kontrovers +konturen +konvent +konvention +konvoi +konzept +konzeption +konzern +konzert +konzession +konzil +kopf +kopfball +kopftuch +kopie +kopieren +koran +korb +korn +korps +korrekt +korrektur +korrigiere +korruption +kosmetik +kosmos +kost +kosten +kostenfrei +kostenlos +krach +krachte +kraft +kraftakt +kraftstoff +kraftvoll +kraftwerk +kragen +kram +kran +krank +kranken +krankheit +krater +kratzer +kraut +krawalle +krawatte +kreationen +kreativ +krebs +kredite +kreide +kreis +kreisebene +kreisel +kreisen +kreishaus +kreislauf +kreisliga +kreisstadt +kreistag +kreml +krems +krenz +kreuz +kreuzung +kreuzweg +kreuzzug +krieg +kriegen +kriegsende +krimi +kriminelle +kripo +krippe +krise +kriterien +kritik +kritiker +kritisch +kritisiert +kroaten +krone +kubikmeter +kuchen +kugel +kuh +kulissen +kult +kultur +kulturamt +kulturell +kulturgut +kulturhaus +kumpel +kunden +kundgebung +kundin +kundschaft +kunst +kunsthalle +kunsthaus +kunstrasen +kunststoff +kunstvoll +kunstwerke +kupfer +kuppel +kur +kurator +kuratorium +kurden +kurhaus +kurier +kurort +kurpark +kurpfalz +kurs +kurstadt +kurve +kurz +kurzarbeit +kurzem +kurzerhand +kurzfilm +kurzform +kurzum +kurzzeitig +kuss +kutsche +kutscher +label +labor +labyrinth +lachen +lachend +lacher +lachs +lacht +lack +laden +ladenburg +ladung +lady +lage +lager +lagerfeuer +lagerhalle +lagerhaus +lagern +lagerung +lahm +laien +lake +lama +lamm +lampen +land +landauer +landebahn +landeck +landesamt +landesbank +landeschef +landesliga +landesrat +landesweit +landete +landfrauen +landhaus +landjugend +landkarte +landkreis +landrat +landschaft +landsleute +landsmann +landtag +landung +landwirte +lang +lange +langeweile +langhaus +langlauf +langsam +langweilig +lanze +lapidar +larven +laser +lass +lassen +last +laster +lastet +lastwagen +latein +lateinisch +laterne +latte +laubenheim +laudatio +lauert +laufbahn +laufe +laufen +laufend +laufsteg +laufzeit +laune +lauschen +lausitz +lausitzer +laut +laute +lauter +lautet +lautstark +lawine +layout +leader +leben +lebend +lebendig +lebensjahr +lebenslang +lebenslauf +lebensraum +lebensstil +lebensweg +lebenswerk +lebenszeit +leber +lebewesen +lebhaft +lebzeiten +leck +leckereien +leder +lederer +lediglich +leer +leere +legal +legende +legion +legitim +legte +lehen +lehm +lehner +lehnt +lehramt +lehrbuch +lehre +lehrer +lehrerin +lehrgang +lehrlinge +lehrplan +lehrstelle +lehrstuhl +lehrt +leib +leiche +leichnam +leicht +leid +leider +leidet +leine +leinen +leinwand +leise +leisten +leistung +leitbild +leiter +leiterin +leitet +leitfaden +leitindex +leitlinien +leitplanke +leitstelle +leitung +leitzinsen +lektion +lenken +lenker +lenkrad +lernen +lesart +lesbar +lesben +lesen +lesenswert +leser +leserbrief +leserinnen +lesung +lettern +letzt +letzte +letztere +letztlich +letztmals +leuchten +leuchtend +leuchtet +leuchtturm +leugnen +leute +leutnant +level +lexikon +liberal +liberalen +libero +libretto +licht +lichtblick +liebe +lieber +liebevoll +liebhaber +liebling +liebt +lied +liefert +lieferung +liegend +liegt +lift +liga +lilienfeld +limburger +limes +limit +limousine +lind +lindenhof +lindern +linie +link +linke +links +linzer +lippen +lire +list +liste +listen +listet +liter +literaten +literatur +liturgie +live +livemusik +lizenz +lkw +lob +lobby +lobbyisten +lobte +loch +locker +lockerung +lockt +loge +logik +logisch +logistik +logos +lohn +lohnt +lok +lokal +lokales +lokalteil +lokomotive +look +lord +los +losgehen +lost +loswerden +lot +lotto +lotus +luft +luftfahrt +luftgewehr +luftlinie +luftraum +luftwaffe +luke +luna +lund +lunge +lupe +lust +lustig +luxus +lyrik +lyriker +machbar +machen +macher +macho +macht +machthaber +machtkampf +machtlos +madame +made +madeleine +madrider +mafia +mag +magazin +magen +mager +magie +magier +magister +magistrat +mahlzeit +mahnmal +mahnte +mahnung +mai +maifeld +mails +mainstream +mainzer +mais +maja +major +makel +makler +mal +malaria +malberg +malen +maler +malerei +malerin +malteser +mama +management +manager +manchmal +mandanten +mandat +manege +manga +mangel +mangelhaft +mangelt +mangelware +manier +manifest +manko +mann +mannen +mannheimer +mannschaft +mantel +manuell +manuskript +marathon +marburger +margen +marihuana +marine +mark +markant +marke +marketing +markgrafen +markierte +markierung +markt +markthalle +marktplatz +marktwert +marmor +marquis +mars +marsch +marschall +marshall +marxismus +maschen +maschinen +maske +mass +massaker +masse +massenhaft +massiv +massnahmen +mast +master +masterplan +match +matchball +material +materie +materiell +mathe +mathematik +matinee +matrix +matt +matte +mauer +mauerfall +mauerwerk +maul +maurer +maus +maut +maximal +maxime +maximum +mechanik +mechaniker +mechanisch +medaille +medien +medikament +meditation +medizin +mediziner +meer +meeting +megawatt +mehl +mehr +mehren +mehrfach +mehrheit +mehrkosten +mehrmals +mehrwert +mehrzahl +meiden +meilen +meiler +meint +meinung +meist +meistens +meister +meisterin +meistern +meldete +meldung +melodien +memoiren +memorial +menge +mensa +menschen +menschheit +menschlich +mental +mentor +merklich +merkmale +merkt +merkur +messe +messen +messer +messias +messungen +metall +metapher +metaphysik +meter +methode +methodik +metier +metropole +metropolen +metzger +metzgerei +metzler +mexikaner +mfs +miene +mies +miete +mieten +mieter +migranten +migration +mikrofon +milch +mild +milde +milieu +milizen +millennium +milliarden +millimeter +millionen +mimik +minder +minderheit +mindern +mindestens +mine +mineralien +mini +minimal +minimieren +minimum +minister +ministerin +minus +minuten +mischt +mischung +misere +miss +missbrauch +misserfolg +mission +missionar +misst +misstrauen +mist +mistelbach +mister +mitarbeit +mitbringen +miterleben +mitfahren +mitgehen +mitglieder +mithalten +mithelfen +mithilfe +mithin +mitleid +mitmachen +mitmischen +mitnehmen +mitnichten +mitreden +mitschuld +mitsingen +mitspielen +mitspieler +mittag +mittags +mitte +mitteilte +mitteilung +mittel +mittelfeld +mittelmeer +mitten +mittendrin +mittler +mittragen +mittwoch +mittwochs +mitunter +mitwirken +mitwirkung +mobbing +mobil +mobile +mobilfunk +mobiliar +mode +model +modell +modenschau +moderat +moderation +moderator +moderiert +modern +moderne +module +modus +mohn +moment +momentan +monarchen +monarchie +monatelang +monaten +monatlich +mond +moniert +monitor +monopol +monsieur +monster +montag +montage +montags +monument +moore +moos +moral +moralisch +moratorium +mord +mordfall +morgen +morgenpost +morgens +mosaik +moschee +moser +moskauer +moslems +most +motion +motiv +motivation +motivieren +motiviert +motor +motorhaube +motorrad +motorsport +motto +movie +multimedia +mund +mundart +mundenheim +munition +munter +muscheln +muse +museum +musical +musik +musikanten +musiker +musikerin +musikszene +musikvideo +musizieren +muskeln +muskulatur +muslimen +muss +muster +mut +mutet +mutig +mutter +muttertag +mythen +mythologie +mythos +nach +nachbarin +nachbarn +nachdenken +nachdruck +nachfahren +nachfolge +nachfolger +nachfrage +nachfragen +nachgehen +nachhaltig +nachher +nachhilfe +nachhinein +nachholen +nachkommen +nachlass +nachlesen +nachmittag +nachnamen +nachricht +nachruf +nachschub +nachsehen +nachspiel +nacht +nachteil +nachtrag +nachts +nachweis +nachweisen +nachwelt +nachwort +nachwuchs +nacken +nackt +nadel +nagel +nah +nahe +nahen +nahezu +nahost +nahrung +naht +nahtlos +nahverkehr +naiv +namen +namenstag +namentlich +napoleon +narren +nase +nass +nassauer +national +nationen +natur +natural +naturpark +navigation +nebel +nebenan +nebenbei +nebenfluss +nebenher +nebenrolle +nebensache +neffe +negativ +neger +nehmen +neid +neigt +neigung +nenner +nennt +nennung +nerven +nervt +nest +nett +netto +netz +netzer +netzwerk +neu +neuanfang +neuauflage +neubau +neubeginn +neuendorf +neuerdings +neuerlich +neuerungen +neues +neufassung +neugebauer +neugier +neugierde +neugierig +neuhausen +neuheiten +neujahr +neuland +neulich +neuling +neumarkt +neuner +neuordnung +neusiedler +neustadt +neustart +neutral +neuwagen +neuwahlen +neuzeit +neuzugang +newcomer +nibelungen +nichte +nichtig +nickel +nickenich +nickt +nicolaus +nie +niedergang +niederlage +niedriger +niemals +nieren +nimmer +nirgends +nirgendwo +nische +niveau +nobel +nobelpreis +noch +nochmal +nochmals +nominiert +nonnen +nord +norden +nordheim +nordkurier +nordost +nordosten +nordseite +nordwesten +normal +normalfall +normen +norweger +nostalgie +not +notar +notarzt +notbremse +notdienst +note +notenbank +notfall +notfalls +notiert +notierte +notizen +notlage +notruf +notstand +notwehr +notwendig +novelle +november +novum +nuancen +nudeln +nulltarif +nummer +nun +nunmal +nunmehr +nur +nutzbar +nutzen +nutzer +nutzung +oase +obdachlose +obduktion +oben +obendrein +ober +oberarzt +obergrenze +oberhand +oberhaupt +oberhaus +oberhof +oberland +oberliga +oberriet +oberschule +oberst +oberstdorf +oberstufe +oberwart +obhut +objekte +objektiv +obliegt +obmann +oboe +obrigkeit +obst +ochsen +odenwald +odyssee +ofen +offen +offenbar +offenbart +offenheit +offensiv +offensive +offerte +offiziell +offizier +oft +oftmals +ohnedies +ohnehin +ohnmacht +ohren +ohrfeige +oktober +oldies +oldtimer +olympiade +oma +omen +onkel +online +opa +oper +opera +operation +operativ +operette +operieren +opernhaus +opfer +opfern +opposition +optik +optimal +optimieren +optimismus +option +optisch +orange +oratorium +orchester +orden +ordentlich +order +ordner +ordnete +ordnung +organe +organismus +organist +orgel +orient +orientiert +original +originell +ort +ortet +ortsbeirat +ortsbild +ortschaft +ortschef +ortsgruppe +ortskern +ortslage +ortsmitte +ortsnamen +ortsrand +ortsrat +ortsteil +ortstermin +ortsverein +ortszeit +ost +osten +ostern +ostsee +ostseite +ostteil +outfit +ovationen +ozean +ozon +paar +paarung +pack +packen +packung +page +paket +pakt +palais +palast +palette +palmen +panik +pannen +panorama +panther +panzer +papa +papier +pappe +papst +parade +paradies +paradox +paragrafen +paragraph +parallel +parallelen +parameter +parat +parcours +parierte +pariser +park +parkanlage +parken +parker +parkett +parkhaus +parkplatz +parlament +parodie +parolen +paroli +part +partei +parteichef +parteilos +parteitag +partie +partikel +partitur +partner +partnerin +partout +party +parzellen +pass +passagen +passagiere +passanten +passat +passauer +passend +passieren +passion +passiv +passt +passus +pastor +pate +patent +pater +pathos +patienten +patientin +patriarch +patron +patzer +pauken +pauschal +pause +pausieren +pavillon +pazifik +pcs +pech +pechstein +pegel +peilt +peinlich +pekinger +pelz +penalty +pendant +pendelt +pendler +pension +pensionist +pentagon +perfekt +perfektion +periode +peripherie +perlen +permanent +personal +personalie +personell +personen +pest +petition +pfad +pfadfinder +pfand +pfanne +pfarramt +pfarre +pfarrei +pfarrer +pfarrerin +pfarrfest +pfarrhaus +pfarrheim +pfarrhof +pfarrsaal +pfeffer +pfeifen +pfeift +pfeil +pfeiler +pfennig +pferd +pfingsten +pflanzen +pflaster +pflege +pflegeheim +pflegen +pfleger +pflicht +pforten +pfosten +pfund +phantasie +phantom +phase +philippe +philologe +philologie +philosoph +photo +physik +physiker +physisch +pianist +pianistin +piano +piazza +pichler +picknick +pierce +pilger +pille +piloten +pilze +pinguine +pink +pinsel +pionier +pipeline +piraten +piste +pistole +pizza +pizzeria +pkw +plagen +plakate +plakette +plan +planer +planeten +plant +planung +plastik +plateau +platin +platt +platte +plattform +platz +platzeck +platzieren +platzte +plausibel +player +playoffs +pleite +plenarsaal +plenum +plural +plus +plutonium +pocht +podest +podium +poesie +poet +pointe +pokal +poker +pol +pole +polemik +police +politik +politiker +politisch +politologe +polizei +polizisten +polizistin +polnisch +polo +polster +pommern +pommes +pool +pop +popmusik +popp +popstar +population +populismus +port +portal +portfolio +portion +portland +porto +portrait +porzellan +posaune +posen +position +positiv +positives +post +postamt +postbank +posten +poster +postfach +posthum +postkarte +postulat +potential +potenzial +potsdamer +pracht +prager +praktiken +praktiker +praktikum +praktisch +prall +prallte +pranger +prangt +praxis +prediger +predigt +preis +preisgeben +preisgeld +preist +prellungen +premier +premiere +presse +prestige +priester +prima +primus +prinzen +prinzessin +prinzip +prise +privat +privatbank +privaten +privileg +pro +probanden +proben +probezeit +probieren +problem +problemlos +probt +produkte +produktion +produzent +produziert +professor +professur +profil +profis +profit +profitabel +profitiert +prognose +programm +projekt +promenade +promille +prominent +prominente +prominenz +promis +promotion +prompt +propaganda +propheten +prophezeit +prosa +prosieben +prospekt +proteine +protest +protokoll +prototyp +provinz +provoziert +prozedur +prozent +prozess +prozession +pseudonym +psyche +psychiater +psychisch +psychologe +pub +publik +publikum +publizist +puck +puderbach +pullover +puls +pult +pulver +puma +pumpen +punk +punkte +punkten +punktspiel +punktzahl +puppen +pur +putsch +putz +putzen +pyramide +quadrat +qual +qualitativ +quartal +quartett +quartier +quasi +quatsch +queen +quelle +quellen +quer +querelen +quintett +quittung +quiz +quote +rabatt +rabatte +rabbiner +rache +rad +radar +radfahren +radfahrer +radikal +radio +radius +radler +radprofi +radsport +radtour +radweg +rage +ragt +rahmen +rain +raketen +rallye +rammte +rampe +ran +randale +rande +rang +rangers +rangiert +rangliste +rap +rapid +rappen +rapper +raps +rar +rasant +rasch +rasen +raser +rasse +rassismus +rast +raste +rat +raten +ratgeber +rathaus +rating +rational +ratlos +ratsam +ratten +raub +rauch +rauchen +raucher +raum +raumfahrt +raumschiff +raupen +raus +rausch +rauschen +rauschgift +rauswurf +razzia +reagierte +reaktion +reaktor +real +realismus +realschule +rebellen +rebellion +reben +rebstein +recherchen +rechner +rechnet +rechnung +recht +rechtens +rechtlich +rechts +rechtsform +rechtslage +rechtsweg +records +recycling +redakteur +redaktion +rede +reden +redezeit +redlich +redner +rednerpult +reduktion +reduzieren +reeder +reederei +referat +referee +referendum +referent +referentin +referenzen +referiert +reflex +reflexion +reform +reformer +refrain +regal +regatta +regel +regelfall +regelrecht +regelt +regelung +regelwerk +regen +regenbogen +regenwald +reggae +regie +regieren +regierung +regime +regiment +region +regional +regisseur +register +reglement +regnet +reh +rehhagel +reich +reichsbahn +reichstag +reicht +reichtum +reichweite +reif +reife +reifen +reigen +reihe +reiht +reim +reimer +rein +reingewinn +reinheit +reinigen +reinigung +reis +reise +reisen +reisende +reiten +reiter +reiz +reizt +reizvoll +rekord +rekruten +rektor +relation +relativ +relegation +relevant +relevanz +relief +religion +remis +remix +rendite +rene +rennen +renner +rennfahrer +rennstall +rennwagen +rente +rentner +rentnerin +reparatur +reparieren +repertoire +report +reportage +reporter +repression +reptilien +republik +reputation +requiem +requisiten +reserve +residenz +resigniert +resolution +resonanz +respekt +ressort +ressourcen +rest +restaurant +restlos +resultat +resultiert +retten +retter +rettung +reue +revanche +revier +review +revision +revolte +revolution +revolver +revue +rezension +rezept +rezeption +rezession +rheineck +rheingau +rheinpfalz +rheintal +rheintaler +rheinufer +rhetorik +rhythmisch +rhythmus +richter +richterin +richtet +richtfest +richtig +richtige +richtlinie +richtung +riecht +rief +riege +riegel +riegler +riesen +riesig +rigoros +rinde +rinder +ring +ringen +ringer +ringt +rippen +risiko +riskant +riskieren +riss +risse +ritt +ritter +ritual +rivalen +robben +roboter +robust +rock +rockband +rocker +rockmusik +rohbau +rohr +rohstoffe +rolle +roller +rollstuhl +rollt +rom +roman +romanshorn +romantik +romantisch +rosa +rosen +rosig +ross +rossmann +rostocker +rot +rotation +rotstift +rotwein +rouge +route +routine +routinier +royal +rubel +rubin +rubrik +ruck +rucksack +ruder +ruderer +ruf +rufnummer +rugby +ruhe +ruhen +ruhestand +ruhig +ruhm +ruin +ruine +ruinen +rum +rummel +rumpf +rumsfeld +run +rund +runde +runden +rundfahrt +rundfunk +rundgang +rundschau +rundum +runter +russen +russin +russisch +russland +rutschte +saal +saalbau +saarlandes +saatgut +sache +sachlage +sachlich +sachsen +sack +sackgasse +saft +sagen +sager +sagte +sahne +saison +saisonende +saisonsieg +saisonziel +saiten +sakristei +salat +salon +salz +salzburger +salzgitter +salzig +samba +samen +sammeln +sammler +sammlung +samstag +samstags +sand +sandhausen +sandstein +sanft +sanieren +sanierung +sank +sanktionen +sarg +satelliten +satire +satt +sattel +sattler +satz +satzung +sau +sauber +sauberkeit +sauce +sauer +sauerland +sauerstoff +sauna +saxophon +scala +schach +schacht +schade +schaden +schafe +schaffen +schaffung +schah +schal +schale +schalke +schall +schaller +schalter +schaltete +scham +schande +schanze +schar +scharf +schatten +schatz +schau +schauen +schauer +schauplatz +schauspiel +scheck +scheibe +scheidung +schein +scheinbar +scheint +scheiterte +schema +schenkel +schenken +schenkung +scherben +schere +scherz +scherzte +scheu +scheune +scheut +schichten +schick +schicken +schicksal +schied +schief +schiefer +schieflage +schiene +schier +schiff +schiiten +schild +schildert +schilling +schimmel +schimpft +schinken +schirm +schirmer +schirmherr +schlacht +schlaf +schlafen +schlag +schlager +schlagwort +schlagzeug +schlamm +schlange +schlank +schlappe +schlau +schlauch +schlecht +schlecker +schlegel +schleicher +schleier +schleife +schleppend +schlepper +schleudern +schleuse +schlicht +schlimm +schlimmste +schlitten +schloss +schlosser +schlucht +schluck +schlucken +schlug +schluss +schmal +schmankerl +schmeckt +schmerzen +schmerzt +schmiede +schmuck +schmunzelt +schmutz +schnabel +schnappte +schnaps +schnauze +schnecken +schnee +schneefall +schneiden +schnell +schnelle +schnellen +schnitt +schnitte +schnitzel +schnitzer +schnuppern +schnur +schob +schock +schokolade +schon +schonen +schoss +schotten +schrank +schranken +schrauben +schreck +schrecken +schreckt +schrei +schreiber +schreibt +schreibung +schreit +schreitet +schriften +schriftzug +schritt +schrott +schrumpft +schub +schublade +schubladen +schuhe +schuhwerk +schulbank +schuld +schuldig +schuldigen +schuldner +schule +schuler +schulhaus +schulhof +schuljahr +schulrat +schultag +schulter +schulung +schulweg +schulzeit +schuppen +schuss +schutt +schutz +schwaben +schwach +schwachen +schwager +schwan +schwanger +schwangere +schwankt +schwanz +schwarz +schwarzen +schwebt +schweden +schweigen +schweiger +schweine +schweizer +schwelle +schwer +schwere +schweriner +schwerlich +schwert +schwester +schwierig +schwimmbad +schwimmen +schwimmer +schwindel +schwindet +schwingen +schwingt +schwitzen +schwul +schwule +schwung +sechsmal +sechster +see +seebad +seele +seelsorge +seelsorger +seenplatte +segeln +segen +segler +segment +sehenswert +sehnsucht +sehr +seide +seil +seilbahn +seiler +seinerzeit +seite +seither +seitlich +sekt +sekte +sektion +sektor +sekunden +selber +selbst +selbstmord +selektion +selig +selten +seltenheit +selters +seltsam +semester +semifinale +seminar +senat +senator +senatorin +sender +sendet +sendung +senf +senioren +seniorin +senken +senkrecht +senkung +senn +sensation +sensibel +sensoren +separat +september +serben +serie +server +service +serviert +sessel +session +set +setzt +seuche +seufzt +shopping +show +showdown +shuttle +sicher +sicherheit +sicherlich +sichern +sicherung +sicht +sichtbar +sichtlich +sichtweise +sichtweite +siedelte +siedler +siedlung +sieg +siegel +siegener +sieger +siegerin +siegeszug +siegreich +siegte +siehe +sieht +sierra +signal +signatur +silbe +silber +silvester +simpel +simulation +sinfonie +single +singstunde +singt +sinn +sinnbild +sinnlos +sinnvoll +sinti +sir +sitten +situation +sitz +sitzend +sitzt +sitzung +skala +skandal +skater +skelett +skepsis +skeptiker +skeptisch +ski +skifahren +skifahrer +skigebiet +skinheads +skizzen +sklaven +sklaverei +skulpturen +slalom +slogan +slowaken +slowenen +smart +snowboard +soccer +sockel +socken +sodann +soeben +sofa +sofort +software +sog +sogar +sogleich +sohn +sol +soldaten +solisten +solistin +soll +solo +somit +sommer +sommerfest +sommerzeit +sonate +sonde +sonderfall +sonderlich +songs +songwriter +sonnabend +sonne +sonnig +sonntag +sonntags +sonst +sonstiges +sopran +sorgen +sorgenkind +sorgerecht +sorgfalt +sorgsam +sorgte +sorten +sortierung +sortiment +soul +sounds +soundtrack +soweit +sowieso +sowjets +sozial +sozialamt +soziales +soziologe +soziologie +sozusagen +spagat +spalte +spalten +spaltet +spaltung +span +spandauer +spanier +spanisch +spanne +spannend +spannt +spannung +spannweite +sparen +sparer +spargel +sparkasse +sparkurs +sparpaket +sparsam +sparte +spass +spatzen +spazieren +specht +special +speck +speer +speicher +speichern +speis +speisen +spektakel +spektrum +spenden +spender +spengler +sperre +sperren +sperrung +spezialist +speziell +spezies +spezifisch +spiegel +spiegelt +spiel +spielchen +spieldauer +spielend +spielende +spieler +spielerin +spielfeld +spielfilm +spielplan +spielplatz +spielraum +spielt +spieltag +spielweise +spielzeit +spielzeug +spinnen +spion +spionage +spirale +spirit +spital +spitz +spitze +spitzer +spitznamen +spitzt +sponsoren +sponsoring +spontan +sporadisch +sporen +sport +sportart +sportbund +sportchef +sportclub +sportfest +sporthalle +sportheim +sportler +sportlerin +sportlich +sportliche +sportpark +sportplatz +sportwagen +spott +sprache +sprachlich +sprachlos +sprachraum +sprachrohr +sprang +sprecher +sprecherin +sprechtag +sprengen +sprengsatz +sprengung +spricht +sprichwort +spring +springer +sprint +sprinter +sprit +spritzen +spruch +sprung +sprunghaft +spuren +spurlos +square +staaten +staatlich +staatschef +staatsoper +staatsrat +stab +stabil +stadien +stadion +stadium +stadt +stadtbahn +stadtbild +stadtchef +stadtfest +stadthalle +stadthaus +stadtmauer +stadtmitte +stadtpark +stadtplan +stadtrand +stadtrat +stadtsaal +stadtteil +stadtwald +stadtwerke +staffel +stagnation +stahl +stahlen +stall +stamm +stammplatz +stammsitz +stammt +stammtisch +stand +standards +standbein +standesamt +standort +standpunkt +stange +stapel +star +starb +stark +starke +starr +start +startelf +starter +startet +startplatz +statement +station +statisten +statistik +stattfand +statue +statur +status +statuten +stau +staub +staunen +stausee +stechen +steckbrief +steckt +steg +stehend +steht +steigend +steiger +steigern +steigerung +steigung +steil +stein +steinbruch +steinebach +steinkohle +steinmeier +steinmetz +steinzeit +steirer +stelle +stellt +stellung +stemmen +stempel +stern +sternbild +sternwarte +stetig +stets +stettiner +steuerfrei +steuerfuss +steuerlich +steuern +steuersatz +steuert +steuerung +stich +stichtag +stichwahl +stichwort +stickstoff +stiefel +stieg +stiel +stier +stiess +stift +stifter +stiftete +stiftung +stil +still +stille +stillstand +stimmen +stimmt +stimmung +stinkt +stipendium +stirn +stock +stocken +stocker +stockwerk +stoff +stollen +stolz +stop +stopfen +stopp +stoppen +storch +stories +story +strafbar +strafe +strafraum +strafrecht +straftaten +strahlen +strahlend +strahlt +strahlung +strand +strandbad +strang +strapazen +strasse +strategie +strauch +streben +strebt +strecke +streich +streichen +streicher +streichung +streife +streifen +streifte +streifzug +streik +streit +streiten +streiter +streitig +streng +strenge +stress +strich +strikt +strittig +stroh +strom +stromnetz +strophe +strukturen +stube +stuck +studenten +studentin +studie +studien +studierte +studio +studium +stufe +stuhl +stumm +stumpf +stunden +stur +sturm +sturz +stute +style +subjekt +subjektiv +substanz +subvention +suche +sucht +suite +suizid +sultan +summe +summer +sumpf +sunniten +super +supermarkt +superstar +suppe +support +surfen +surfer +swing +sylvester +symbiose +symbol +symbolik +symbolisch +sympathie +symphonie +symposium +symptome +synagoge +synergien +synode +synonym +synthese +system +systematik +szenarien +szenario +szene +szenerie +tabak +tabelle +tabletten +tabu +tafel +tag +tagblatt +tageblatt +tagebuch +tagelang +tageslicht +tagesschau +tags +tagt +tagung +takt +taktik +taktisch +tal +talent +taler +talfahrt +taliban +talk +talkshow +tango +tank +tanken +tanker +tankstelle +tante +tanz +tanzen +tanzgruppe +tanzmusik +tapfer +tarife +tarifrunde +tasche +tasse +tastatur +tasten +tat +tatbestand +tatenlos +tatort +tatsache +tatzeit +tauben +taucher +taucht +taufe +taugt +tausch +tauschen +tausende +tauziehen +taxi +taxifahrer +team +teamchef +teamgeist +technik +techniker +technisch +techno +teddy +tee +teenager +tegel +teich +teig +teil +teilchen +teilhabe +teilhaben +teilnahme +teilnehmen +teilnehmer +teils +teilte +teilung +teilweise +teilzeit +tele +telefon +telefonat +telegramm +telegraph +telephon +television +teller +tempel +tempelhof +temperatur +tempo +tempolimit +tendenz +tennis +tennisclub +tenor +teppich +termin +terminal +terminus +terrain +terrasse +terror +terrorist +tessiner +test +testament +testen +testspiel +teuer +teuerung +teufel +text +textilien +thai +theater +theke +thema +thematik +thematisch +theologe +theologie +theorie +therapie +therme +these +thesen +thriller +thron +thront +thurgauer +tibeter +tickets +tief +tiefe +tiefensee +tiefgang +tiefgarage +tiefpunkt +tierarten +tierarzt +tiere +tiergarten +tierheim +tierpark +tierschutz +tierwelt +tiger +tilgung +time +tipps +tiroler +tisch +tischler +titan +titel +titelkampf +titelrolle +titelseite +titelte +tobt +tochter +tod +todesfall +todesopfer +todestag +toilette +toleranz +toll +tomaten +tombola +ton +tonfall +tonnen +topf +tor +torchancen +torerfolg +torfolge +tormann +tornados +torwart +tot +total +toten +totschlags +tour +tourismus +touristen +touristik +tournee +tower +trab +tracht +track +tradition +tragbar +tragen +tragik +tragisch +tragweite +trainer +trainerin +trainieren +training +traktor +tram +trank +transfer +transit +transport +trapp +trasse +trat +trauben +trauen +trauer +trauert +traum +trauma +traurig +trauung +treff +treffend +treffer +trefflich +treffpunkt +treibstoff +treibt +trend +trendwende +trennen +trennung +treppchen +treppe +tresen +tresor +treu +treue +triathlon +tribunal +tribune +tribut +tricks +triebe +triebwagen +triebwerk +trierer +trifft +trikot +trilogie +trinken +trio +trip +tritt +trittin +triumph +trocken +trommeln +trompete +trompeter +tropfen +trost +trotz +trotzig +trubel +trumpf +truppen +trust +tschechen +tuch +tugend +tummeln +tumor +tun +tunnel +turbine +turbo +turm +turnen +turner +turnhalle +turnier +turnverein +typ +typen +typisch +typus +ufer +uhr +uhrzeit +ukrainer +ulmen +ulmer +ultimatum +umbau +umbauen +umbringen +umbruch +umdenken +umfahrung +umfang +umfassend +umfasst +umfeld +umfrage +umgang +umgebung +umgehen +umgehend +umgehung +umgekehrt +umgibt +umkehr +umkreis +umlage +umland +umlauf +umleitung +umrahmung +umsatz +umsatzplus +umschau +umschlag +umsetzen +umsetzung +umso +umsonst +umstand +umsteigen +umstellen +umstellung +umstieg +umstritten +umwandeln +umwandlung +umweg +umwelt +umziehen +umzug +unangenehm +unbedingt +unbegrenzt +unbehagen +unbekannt +unbekannte +unbelegt +unbemerkt +unbesetzt +undenkbar +unendlich +unerkannt +unerwartet +unfair +unfall +unfallort +unfug +ungar +ungebremst +ungeduldig +ungeeignet +ungeheuer +ungemein +ungenau +ungenutzt +ungerecht +ungern +ungewiss +ungewohnt +ungewollt +ungleich +unhaltbar +unheil +unheimlich +uni +uniform +uniklinik +union +unisono +universum +unkenntnis +unklar +unkraut +unmut +unpassend +unrat +unrecht +unruhe +unruhig +unschuld +unschuldig +unsicher +unsichtbar +unsinn +unsinnig +unstrittig +unten +unterart +unterarten +unterbau +unterbrach +untergang +untergehen +untergrund +unterhalt +unterhaus +unterhielt +unterkunft +unterlag +unterlagen +unternahm +unterricht +unterseite +untersteht +untersucht +untertanen +untertitel +unterwegs +unterwelt +unterzahl +untrennbar +untreue +unverletzt +unversehrt +unweit +unwesen +unwetter +unwichtig +unwirksam +uran +urbar +urenkel +urgestein +urheber +urin +urkunde +urkundlich +urlaub +urlauber +urne +urnengang +urs +ursache +ursprung +urteil +urteilte +urwald +utopie +vage +vakuum +vampire +vandalen +variabel +variante +variation +variieren +vater +vaterland +vatikan +vegetation +vehement +vehikel +velo +venus +verachtung +veraltet +verankern +verbal +verband +verbessern +verbieten +verbindet +verbindung +verbirgt +verbleib +verblieb +verbot +verbrauch +verbrechen +verbrecher +verbreiten +verbreitet +verbrennen +verbringen +verbuchen +verbund +verbunden +verdacht +verdammt +verdanken +verdeckt +verderben +verdienen +verdienste +verdient +verdoppeln +verehrung +verein +vereinbar +vereinigen +vereint +vereinzelt +verfahren +verfall +verfasser +verfasste +verfassung +verfechter +verfehlt +verfehlte +verfiel +verfilmung +verfolgen +verfolger +verfolgung +vergabe +vergeben +vergebens +vergeblich +vergebung +vergehen +vergeltung +vergessen +vergleich +vergleicht +verhaftet +verhaftung +verhalten +verhandeln +verheerend +verhelfen +verhindern +verkauf +verkaufen +verkehr +verkehren +verkehrt +verkraften +verlag +verlagern +verlangen +verlassen +verlauf +verlautete +verlegen +verleger +verlegung +verleihen +verleihung +verletzt +verletzte +verletzung +verliebt +verlief +verlierer +verlinken +verlinkung +verlor +verlost +verlosung +verlust +vermag +vermarkten +vermehren +vermehrt +vermehrung +vermeiden +vermeidung +vermelden +vermerk +vermessung +vermieten +vermieter +vermietung +vermissen +vermisst +vermissten +vermitteln +vermittler +vermochte +vermochten +vermuten +vermutlich +vermutung +vernehmen +vernehmung +vernetzung +vernichtet +vernissage +vernunft +verordnung +verpackung +verpasste +verrat +verrichten +verriet +verringern +versagen +versammelt +versand +verschafft +verschiebt +verschluss +verschont +verschwand +verse +versehen +versenkte +versenkung +versetzen +versetzung +versichert +versinkt +version +versorgen +versorger +versorgung +verspricht +verstand +verstarb +versteck +versteckt +verstehen +versuch +versucht +versuchung +verteidigt +verteilen +verteilung +vertiefen +vertiefung +vertrag +vertrauen +vertraut +vertrauten +vertreiben +vertretbar +vertreter +vertretung +vertrieb +vertritt +verursacht +verurteilt +verwalten +verwalter +verwaltung +verwandeln +verwandt +verwandten +verweigern +verweilen +verweis +verwenden +verwendung +verwertete +verwertung +verwies +verwirrend +verwirrt +verwirrung +verwundert +verzehr +verzicht +verzichten +verzinsung +verzug +vesper +veteranen +veto +video +vieh +viel +vielerlei +vielerorts +vielfach +vielfaches +vielfalt +vielleicht +vielmehr +vielseitig +vielzahl +vier +vierbeiner +vierer +viermal +viertel +vierter +villa +violine +virtuos +virus +visier +vision +visite +visum +vita +vitamin +vitrinen +vize +vogel +vogelarten +vogelstang +vogt +volk +volksbank +volksfest +volkshaus +volksmund +volksmusik +volkswagen +voll +vollen +vollendet +vollends +vollendung +volleyball +vollgas +vollkommen +volltext +vollzieht +vollzug +volumen +vonstatten +vorab +vorabend +voran +vorarbeit +voraus +vorbehalte +vorbei +vorbeugung +vorbild +vorerst +vorfahren +vorfahrt +vorfall +vorfeld +vorfreude +vorgaben +vorgang +vorgehen +vorgesehen +vorgestern +vorgibt +vorhaben +vorhanden +vorhang +vorher +vorherige +vorhersage +vorhin +vorjahr +vorkommen +vorlage +vorlauf +vorlegen +vorlesen +vorlesung +vorliebe +vorliegen +vormals +vormarsch +vormittag +vormittags +vormonat +vorn +vornamen +vorne +vornherein +vorort +vorplatz +vorrang +vorrangig +vorrat +vorredner +vorreiter +vorrunde +vorsaison +vorsatz +vorschau +vorschein +vorschlag +vorschrift +vorsicht +vorsichtig +vorsieht +vorsitz +vorsorge +vorspiel +vorsprung +vorstadt +vorstand +vorsteher +vorstellen +vorstoss +vortag +vorteil +vortrag +vortragen +vortritt +vorurteile +vorverkauf +vorwahl +vorwand +vorweisen +vorwerfen +vorwiegend +vorwoche +vorwort +vorwurf +vorzeichen +vorzeitig +vorzug +votierten +votum +vulkan +waage +wach +wache +wachs +wachsen +wachstum +wacht +wackelt +wade +waffeln +waffen +waffenruhe +wagen +waggons +wagnis +wahl +wahlbezirk +wahlgang +wahljahr +wahlkampf +wahlkreis +wahllokale +wahlrecht +wahlsieg +wahltag +wahlweise +wahn +wahnsinn +wahnsinnig +wahr +wahren +wahrhaben +wahrhaft +wahrheit +wahrlich +wahrnehmen +wahrung +wald +waldeck +waldgebiet +waldheim +waldhof +waldsee +wale +walker +walking +wallfahrt +walliser +wallstadt +walten +walz +walzer +wand +wandel +wandelt +wanderer +wandern +wandertag +wanderung +wanderwege +wandlung +wandte +wangen +wanken +wappen +ward +waren +warentest +warm +warner +warnt +warnung +warschauer +warte +warteliste +warten +wartezeit +wartung +waschen +wasser +wasserburg +wasserfall +wasserturm +wasserwerk +watt +wattenheim +web +weber +weblink +weblinks +webseite +website +wechsel +wechselte +wecken +wecker +wedel +weg +wegfall +wegfallen +weggang +weglassen +wegnehmen +wegweiser +weh +wehen +wehmut +wehr +wehrdienst +wehrleiter +wehrmacht +wehrt +weht +weibchen +weibern +weiblich +weich +weichen +weiden +weidmann +weigerte +weigerung +weihe +weiher +weihnacht +weil +weile +weiler +weimarer +wein +weinbau +weinberg +weinen +weinfest +weingarten +weingut +weinheim +weinprobe +weise +weisheit +weiss +weist +weisung +weit +weitaus +weite +weitefeld +weiter +weitergabe +weitergeht +weiterhin +weitet +weitgehend +weithin +weitsprung +weizen +welle +weller +welt +weltall +weltbank +weltbild +weltcup +welterbe +weltklasse +weltkrieg +weltmarkt +weltraum +weltreise +weltrekord +weltspitze +weltweit +wende +wendel +wendepunkt +wendland +wendung +wenig +weniger +wenigsten +wenigstens +werben +werbung +werdegang +werfer +werft +werk +werkstatt +werktags +werkzeug +wert +wertete +wertlos +wertung +wertvoll +wesen +wesenberg +wesentlich +west +weste +westen +westens +western +westlich +westseite +wettbewerb +wette +wetter +wettkampf +wettlauf +wettstreit +whisky +wichtig +wichtigste +widder +widerlegen +widerstand +widmer +widmet +wieder +wiedergabe +wiederhole +wiederholt +wiederkehr +wiederum +wiederwahl +wiege +wiegt +wiener +wiese +wieselburg +wikinger +wild +wilden +wildnis +will +willen +willkommen +wind +winde +winkel +winkt +winter +winterkorn +winzer +wirbel +wirft +wirklich +wirksam +wirkstoff +wirkt +wirkung +wirren +wirt +wirtin +wirtschaft +wirtshaus +wissen +wissend +witterung +witwe +witz +witzig +woanders +woche +wochenende +wochenlang +wodka +wog +wogen +wohl +wohlfahrt +wohlstand +wohlwollen +wohnbau +wohngebiet +wohnhaft +wohnhaus +wohnheim +wohnort +wohnraum +wohnsitz +wohnt +wohnung +wohnwagen +wohnzimmer +wolfsberg +wolken +wolle +workshops +wort +wortlaut +wortschatz +wortwahl +wrack +wrestling +wucht +wunden +wunder +wunderbar +wunderlich +wundert +wunsch +wurf +wurm +wurst +wurzeln +wut +yacht +yen +yoga +youngster +zahl +zahlen +zahlreich +zahlung +zahn +zahnarzt +zar +zart +zauber +zauberer +zaubern +zauberwort +zaun +zeche +zehen +zehnmal +zehntel +zeichen +zeichner +zeichnet +zeichnung +zeigt +zeilen +zeit +zeitalter +zeitdruck +zeitfahren +zeitgeist +zeitgleich +zeitlebens +zeitlich +zeitnah +zeitplan +zeitpunkt +zeitraum +zeitreise +zeitspanne +zeitung +zeitweilig +zeitweise +zellen +zelt +zeltlager +zeltweg +zement +zenit +zensur +zentimeter +zentral +zentrale +zentralrat +zentrum +zepter +zeremonie +zerfall +zertifikat +zettel +zeug +zeugen +zeugin +zeugnis +zeugt +ziegen +zieht +ziel +zielgruppe +ziellinie +zielt +ziemlich +ziert +ziffer +zigaretten +zigeuner +zimmer +zink +zinsen +zinssatz +zirka +zirkel +zirkus +zitadelle +zitat +zitiert +zittern +zivilisten +zog +zoll +zone +zoo +zorn +zuber +zucht +zuchthaus +zucker +zudem +zueinander +zuerst +zufahrt +zufall +zuflucht +zufluss +zufrieden +zug +zugabe +zugang +zugeben +zugegen +zugehen +zugestehen +zugleich +zugreifen +zugriff +zugrunde +zugute +zugzwang +zuhause +zukommen +zukunft +zulassen +zulassung +zulasten +zulauf +zulegen +zuletzt +zulieferer +zumal +zumeist +zumindest +zumutbar +zumuten +zumutung +zunahme +zunehmen +zunehmend +zuneigung +zunft +zunge +zunichte +zuordnen +zuordnung +zuruf +zurufe +zurzeit +zusage +zusammen +zusatz +zuschauen +zuschauer +zuschlag +zuschuss +zusehen +zusehends +zuspiel +zuspruch +zustand +zustande +zusteht +zustimmen +zustimmung +zutaten +zuteil +zutiefst +zutreffend +zutrifft +zutritt +zuversicht +zuvor +zuwachs +zuwanderer +zuweilen +zuwendung +zuwenig +zuzug +zwang +zwanziger +zwar +zweck +zweifel +zweifellos +zweifelt +zweig +zweikampf +zweimal +zweit +zweitens +zweiter +zwerge +zwiebeln +zwillinge +zwingen +zwingend +zwist +zyklus +zylinder +zynisch +zynismus \ No newline at end of file diff --git a/resources/public/wordlists/google-10000-english-usa-no-swears-medium.txt b/resources/public/wordlists/google-10000-english-usa-no-swears-medium.txt new file mode 100644 index 0000000..df9ff08 --- /dev/null +++ b/resources/public/wordlists/google-10000-english-usa-no-swears-medium.txt @@ -0,0 +1,5460 @@ +about +search +other +which +their +there +contact +business +online +first +would +services +these +click +service +price +people +state +email +health +world +products +music +should +product +system +policy +number +please +support +message +after +software +video +where +rights +public +books +school +through +links +review +years +order +privacy +items +company +group +under +general +research +january +reviews +program +games +could +great +united +hotel +center +store +travel +comments +report +member +details +terms +before +hotels +right +because +local +those +using +results +office +national +design +posted +internet +address +within +states +phone +shipping +reserved +subject +between +forum +family +based +black +check +special +prices +website +index +being +women +today +south +project +pages +version +section +found +sports +house +related +security +county +american +photo +members +power +while +network +computer +systems +three +total +place +download +without +access +think +north +current +posts +media +control +water +history +pictures +personal +since +guide +board +location +change +white +small +rating +children +during +return +students +shopping +account +times +sites +level +digital +profile +previous +events +hours +image +title +another +shall +property +class +still +money +quality +every +listing +content +country +private +little +visit +tools +reply +customer +december +compare +movies +include +college +value +article +provide +source +author +press +learn +around +print +course +canada +process +stock +training +credit +point +science +advanced +sales +english +estate +select +windows +photos +thread +category +large +gallery +table +register +however +october +november +market +library +really +action +start +series +model +features +industry +human +provided +required +second +movie +forums +march +better +yahoo +going +medical +friend +server +study +staff +articles +feedback +again +looking +issues +april +never +users +complete +street +topic +comment +things +working +against +standard +person +below +mobile +party +payment +login +student +programs +offers +legal +above +recent +stores +problem +memory +social +august +quote +language +story +options +rates +create +young +america +field +paper +single +example +girls +password +latest +question +changes +night +texas +poker +status +browse +issue +range +building +seller +court +february +always +result +audio +light +write +offer +groups +given +files +event +release +analysis +request +china +making +picture +needs +possible +might +month +major +areas +future +space +cards +problems +london +meeting +become +interest +child +enter +share +similar +garden +schools +million +added +listed +learning +energy +delivery +popular +stories +journal +reports +welcome +central +images +notice +original +radio +until +color +council +includes +track +archive +others +format +least +society +months +safety +friends +trade +edition +messages +further +updated +having +provides +david +already +green +studies +close +common +drive +specific +several +living +called +short +display +limited +powered +means +director +daily +beach +natural +whether +period +planning +database +official +weather +average +window +france +region +island +record +direct +records +district +calendar +costs +style +front +update +parts +early +miles +sound +resource +present +either +document +works +material +written +federal +hosting +rules +final +adult +tickets +thing +centre +cheap +finance +minutes +third +gifts +europe +reading +topics +cover +usually +together +videos +percent +function +getting +global +economic +player +projects +lyrics +often +submit +germany +amount +watch +included +though +thanks +deals +various +words +linux +james +weight +heart +received +choose +archives +points +magazine +error +camera +clear +receive +domain +methods +chapter +makes +policies +beauty +manager +india +position +taken +listings +models +michael +known +cases +florida +simple +quick +wireless +license +friday +whole +annual +later +basic +shows +google +church +method +purchase +active +response +practice +hardware +figure +holiday +enough +designed +along +among +death +writing +speed +brand +discount +higher +effects +created +remember +yellow +increase +kingdom +thought +stuff +french +storage +japan +doing +loans +shoes +entry +nature +orders +africa +summary +growth +notes +agency +monday +european +activity +although +western +income +force +overall +river +package +contents +players +engine +album +regional +supplies +started +views +plans +double +build +screen +exchange +types +lines +continue +across +benefits +needed +season +apply +someone +anything +printer +believe +effect +asked +sunday +casino +volume +cross +anyone +mortgage +silver +inside +solution +mature +rather +weeks +addition +supply +nothing +certain +running +lower +union +jewelry +clothing +names +robert +homepage +skills +islands +advice +career +military +rental +decision +leave +british +teens +woman +sellers +middle +cable +taking +values +division +coming +tuesday +object +lesbian +machine +length +actually +score +client +returns +capital +follow +sample +shown +saturday +england +culture +flash +george +choice +starting +thursday +courses +consumer +airport +foreign +artist +outside +levels +channel +letter +phones +ideas +summer +allow +degree +contract +button +releases +homes +super +matter +custom +virginia +almost +located +multiple +asian +editor +cause +focus +featured +rooms +female +thomas +primary +cancer +numbers +reason +browser +spring +answer +voice +friendly +schedule +purpose +feature +comes +police +everyone +approach +cameras +brown +physical +medicine +ratings +chicago +forms +glass +happy +smith +wanted +thank +unique +survey +prior +sport +ready +animal +sources +mexico +regular +secure +simply +evidence +station +round +paypal +favorite +option +master +valley +recently +probably +rentals +built +blood +improve +larger +networks +earth +parents +nokia +impact +transfer +kitchen +strong +carolina +wedding +hospital +ground +overview +owners +disease +italy +perfect +classic +basis +command +cities +william +express +award +distance +peter +ensure +involved +extra +partners +budget +rated +guides +success +maximum +existing +quite +selected +amazon +patients +warning +horse +forward +flowers +stars +lists +owner +retail +animals +useful +directly +housing +takes +bring +catalog +searches +trying +mother +traffic +joined +input +strategy +agent +valid +modern +senior +ireland +teaching +grand +testing +trial +charge +units +instead +canadian +normal +wrote +ships +entire +leading +metal +positive +fitness +chinese +opinion +football +abstract +output +funds +greater +likely +develop +artists +guest +seems +trust +contains +session +multi +republic +vacation +century +academic +graphics +indian +expected +grade +dating +pacific +mountain +filter +mailing +vehicle +longer +consider +northern +behind +panel +floor +german +buying +match +proposed +default +require +outdoor +morning +allows +protein +plant +reported +politics +partner +authors +boards +faculty +parties +mission +string +sense +modified +released +stage +internal +goods +unless +richard +detailed +japanese +approved +target +except +ability +maybe +moving +brands +places +pretty +spain +southern +yourself +winter +battery +youth +pressure +boston +keywords +medium +break +purposes +dance +itself +defined +papers +playing +awards +studio +reader +virtual +device +answers +remote +external +apple +offered +theory +enjoy +remove +surface +minimum +visual +variety +teachers +martin +manual +block +subjects +agents +repair +civil +steel +songs +fixed +wrong +hands +finally +updates +desktop +classes +paris +sector +capacity +requires +jersey +fully +father +electric +quotes +officer +driver +respect +unknown +worth +teacher +workers +georgia +peace +campus +showing +creative +coast +benefit +progress +funding +devices +grant +agree +fiction +watches +careers +beyond +families +museum +blogs +accepted +former +complex +agencies +parent +spanish +michigan +columbia +setting +scale +stand +economy +highest +helpful +monthly +critical +frame +musical +angeles +employee +chief +gives +bottom +packages +detail +changed +heard +begin +colorado +royal +clean +switch +russian +largest +african +titles +relevant +justice +connect +bible +basket +applied +weekly +demand +suite +vegas +square +chris +advance +auction +allowed +correct +charles +nation +selling +piece +sheet +seven +older +illinois +elements +species +cells +module +resort +facility +random +pricing +minister +motion +looks +fashion +visitors +monitor +trading +forest +calls +whose +coverage +couple +giving +chance +vision +ending +clients +actions +listen +discuss +accept +naked +clinical +sciences +markets +lowest +highly +appear +lives +currency +leather +patient +actual +stone +commerce +perhaps +persons +tests +village +accounts +amateur +factors +coffee +settings +buyer +cultural +steve +easily +poster +closed +holidays +zealand +balance +graduate +replies +initial +label +thinking +scott +canon +league +waste +minute +provider +optional +sections +chair +fishing +effort +phase +fields +fantasy +letters +motor +context +install +shirt +apparel +crime +count +breast +johnson +quickly +dollars +websites +religion +claim +driving +surgery +patch +measures +kansas +chemical +doctor +reduce +brought +himself +enable +exercise +santa +leader +diamond +israel +servers +alone +meetings +seconds +jones +arizona +keyword +flight +congress +username +produced +italian +pocket +saint +freedom +argument +creating +drugs +joint +premium +fresh +attorney +upgrade +factor +growing +stream +hearing +eastern +auctions +therapy +entries +dates +signed +upper +serious +prime +samsung +limit +began +louis +steps +errors +shops +efforts +informed +thoughts +creek +worked +quantity +urban +sorted +myself +tours +platform +labor +admin +nursing +defense +machines +heavy +covered +recovery +merchant +expert +protect +solid +became +orange +vehicles +prevent +theme +campaign +marine +guitar +finding +examples +saying +spirit +claims +motorola +affairs +touch +intended +towards +goals +election +suggest +branch +charges +serve +reasons +magic +mount +smart +talking +latin +avoid +manage +corner +oregon +element +birth +virus +abuse +requests +separate +quarter +tables +define +racing +facts +column +plants +faith +chain +identify +avenue +missing +domestic +sitemap +moved +houston +reach +mental +viewed +moment +extended +sequence +attack +sorry +centers +opening +damage +reserve +recipes +gamma +plastic +produce +placed +truth +counter +failure +follows +weekend +dollar +ontario +films +bridge +native +williams +movement +printing +baseball +owned +approval +draft +chart +played +contacts +jesus +readers +clubs +jackson +equal +matching +offering +shirts +profit +leaders +posters +variable +expect +parking +compared +workshop +russia +codes +kinds +seattle +golden +teams +lighting +senate +forces +funny +brother +turned +portable +tried +returned +pattern +named +theatre +laser +earlier +sponsor +warranty +indiana +harry +objects +delete +evening +assembly +nuclear +taxes +mouse +signal +criminal +issued +brain +sexual +powerful +dream +obtained +false +flower +passed +supplied +falls +opinions +promote +stated +stats +hawaii +appears +carry +decided +covers +hello +designs +maintain +tourism +priority +adults +clips +savings +graphic +payments +binding +brief +ended +winning +eight +straight +script +served +wants +prepared +dining +alert +atlanta +dakota +queen +credits +clearly +handle +sweet +criteria +pubmed +diego +truck +behavior +enlarge +revenue +measure +changing +votes +looked +festival +ocean +flights +experts +signs +depth +whatever +logged +laptop +vintage +train +exactly +explore +maryland +concept +nearly +eligible +checkout +reality +forgot +handling +origin +gaming +feeds +billion +scotland +faster +dallas +bought +nations +route +followed +broken +frank +alaska +battle +anime +speak +protocol +query +equity +speech +rural +shared +sounds +judge +bytes +forced +fight +height +speaker +filed +obtain +offices +designer +remain +managed +failed +marriage +korea +banks +secret +kelly +leads +negative +austin +toronto +theater +springs +missouri +andrew +perform +healthy +assets +injury +joseph +ministry +drivers +lawyer +figures +married +proposal +sharing +portal +waiting +birthday +gratis +banking +brian +toward +slightly +assist +conduct +lingerie +calling +serving +profiles +miami +comics +matters +houses +postal +controls +breaking +combined +ultimate +wales +minor +finish +noted +reduced +physics +spent +extreme +samples +davis +daniel +reviewed +forecast +removed +helps +singles +cycle +amounts +contain +accuracy +sleep +pharmacy +brazil +creation +static +scene +hunter +crystal +famous +writer +chairman +violence +oklahoma +speakers +drink +academy +dynamic +gender +cleaning +concerns +vendor +intel +officers +referred +supports +regions +junior +rings +meaning +ladies +henry +ticket +guess +agreed +soccer +import +posting +presence +instant +viewing +majority +christ +aspects +austria +ahead +scheme +utility +preview +manner +matrix +devel +despite +strength +turkey +proper +degrees +delta +seeking +inches +phoenix +shares +daughter +standing +comfort +colors +cisco +ordering +alpha +appeal +cruise +bonus +bookmark +specials +disney +adobe +smoking +becomes +drives +alabama +improved +trees +achieve +dress +dealer +nearby +carried +happen +exposure +gambling +refer +miller +outdoors +clothes +caused +luxury +babes +frames +indeed +circuit +layer +printed +removal +easier +printers +adding +kentucky +mostly +taylor +prints +spend +factory +interior +revised +optical +relative +amazing +clock +identity +suites +feeling +hidden +victoria +serial +relief +revision +ratio +planet +copies +recipe +permit +seeing +proof +tennis +bedroom +empty +instance +licensed +orlando +bureau +maine +ideal +specs +recorded +pieces +finished +parks +dinner +lawyers +sydney +stress +cream +trends +discover +patterns +boxes +hills +fourth +advisor +aware +wilson +shape +irish +stations +remains +greatest +firms +operator +generic +usage +charts +mixed +census +exist +wheel +transit +compact +poetry +lights +tracking +angel +keeping +attempt +matches +width +noise +engines +forget +array +accurate +stephen +climate +alcohol +greek +managing +sister +walking +explain +smaller +newest +happened +extent +sharp +lesbians +export +managers +aircraft +modules +sweden +conflict +versions +employer +occur +knows +describe +concern +backup +citizens +heritage +holding +trouble +spread +coach +kevin +expand +audience +assigned +jordan +affect +virgin +raised +directed +dealers +sporting +helping +affected +totally +plate +expenses +indicate +blonde +anderson +organic +albums +cheats +guests +hosted +diseases +nevada +thailand +agenda +anyway +tracks +advisory +logic +template +prince +circle +grants +anywhere +atlantic +edward +investor +leaving +wildlife +cooking +speaking +sponsors +respond +sizes +plain +entered +launch +checking +costa +belgium +guidance +trail +symbol +crafts +highway +buddy +observed +setup +booking +glossary +fiscal +styles +denver +filled +channels +ericsson +appendix +notify +blues +portion +scope +supplier +cables +cotton +biology +dental +killed +border +ancient +debate +starts +causes +arkansas +leisure +learned +notebook +explorer +historic +attached +opened +husband +disabled +crazy +upcoming +britain +concert +scores +comedy +adopted +weblog +linear +bears +carrier +edited +constant +mouth +jewish +meter +linked +portland +concepts +reflect +deliver +wonder +lessons +fruit +begins +reform +alerts +treated +mysql +relating +assume +alliance +confirm +neither +lewis +howard +offline +leaves +engineer +replace +checks +reached +becoming +safari +sugar +stick +allen +relation +enabled +genre +slide +montana +tested +enhance +exact +bound +adapter +formal +hockey +storm +micro +colleges +laptops +showed +editors +threads +supreme +brothers +presents +dolls +estimate +cancel +limits +weapons +paint +delay +pilot +outlet +czech +novel +ultra +winner +idaho +episode +potter +plays +bulletin +modify +oxford +truly +epinions +painting +universe +patent +eating +planned +watching +lodge +mirror +sterling +sessions +kernel +stocks +buyers +journals +jennifer +antonio +charged +broad +taiwan +chosen +greece +swiss +sarah +clark +terminal +nights +behalf +liquid +nebraska +salary +foods +gourmet +guard +properly +orleans +saving +empire +resume +twenty +newly +raise +prepare +avatar +illegal +hundreds +lincoln +helped +premier +tomorrow +decide +consent +drama +visiting +downtown +keyboard +contest +bands +suitable +millions +lunch +audit +chamber +guinea +findings +muscle +clicking +polls +typical +tower +yours +chicken +attend +shower +sending +jason +tonight +holdem +shell +province +catholic +governor +seemed +swimming +spyware +formula +solar +catch +pakistan +reliable +doubt +finder +unable +periods +tasks +attacks +const +doors +symptoms +resorts +biggest +memorial +visitor +forth +insert +gateway +alumni +drawing +ordered +fighting +happens +romance +bruce +split +themes +powers +heaven +pregnant +twice +focused +egypt +bargain +cellular +norway +vermont +asking +blocks +normally +hunting +diabetes +shift +bodies +cutting +simon +writers +marks +flexible +loved +mapping +numerous +birds +indexed +superior +saved +paying +cartoon +shots +moore +granted +choices +carbon +spending +magnetic +registry +crisis +outlook +massive +denmark +employed +bright +treat +header +poverty +formed +piano +sheets +patrick +puerto +displays +plasma +allowing +earnings +mystery +journey +delaware +bidding +risks +banner +charter +barbara +counties +ports +dreams +blogger +stands +teach +occurred +rapid +hairy +reverse +deposit +seminar +latina +wheels +specify +dutch +formats +depends +boots +holds +router +concrete +editing +poland +folder +womens +upload +pulse +voting +courts +notices +detroit +metro +toshiba +strip +pearl +accident +resident +possibly +airline +regard +exists +smooth +strike +flashing +narrow +threat +surveys +sitting +putting +vietnam +trailer +castle +gardens +missed +malaysia +antique +labels +willing +acting +heads +stored +logos +antiques +density +hundred +strange +mention +parallel +honda +amended +operate +bills +bathroom +stable +opera +doctors +lesson +cinema +asset +drinking +reaction +blank +enhanced +entitled +severe +generate +deluxe +humor +monitors +lived +duration +pursuant +fabric +visits +tight +domains +contrast +flying +berlin +siemens +adoption +meant +capture +pounds +buffalo +plane +desire +camping +meets +welfare +caught +marked +driven +measured +medline +bottle +marshall +massage +rubber +closing +tampa +thousand +legend +grace +susan +adams +python +monster +villa +columns +hamilton +cookies +inner +tutorial +entity +cruises +holder +portugal +lawrence +roman +duties +valuable +ethics +forever +dragon +captain +imagine +brings +heating +scripts +stereo +taste +dealing +commit +airlines +liberal +livecam +trips +sides +turns +cache +jacket +oracle +matthew +lease +aviation +hobbies +proud +excess +disaster +console +commands +giant +achieved +injuries +shipped +seats +alarm +voltage +anthony +nintendo +usual +loading +stamps +appeared +franklin +angle +vinyl +mining +ongoing +worst +imaging +betting +liberty +wyoming +convert +analyst +garage +exciting +thongs +ringtone +finland +morgan +derived +pleasure +honor +oriented +eagle +desktops +pants +columbus +nurse +prayer +quiet +postage +producer +cheese +comic +crown +maker +crack +picks +semester +fetish +applies +casinos +smoke +apache +filters +craft +apart +fellow +blind +lounge +coins +gross +strongly +hilton +proteins +horror +familiar +capable +douglas +debian +epson +elected +carrying +victory +madison +editions +mainly +ethnic +actor +finds +fifth +citizen +vertical +prize +occurs +absolute +consists +anytime +soldiers +guardian +lecture +layout +classics +horses +dirty +wayne +donate +taught +worker +alive +temple +prove +wings +breaks +genetic +waters +promise +prefer +ridge +cabinet +modem +harris +bringing +evaluate +tiffany +tropical +collect +toyota +streets +vector +shaved +turning +buffer +purple +larry +mutual +pipeline +syntax +prison +skill +chairs +everyday +moves +inquiry +ethernet +checked +exhibit +throw +trend +sierra +visible +desert +oldest +rhode +mercury +steven +handbook +navigate +worse +summit +victims +spaces +burning +escape +coupons +somewhat +receiver +cialis +boats +glance +scottish +arcade +richmond +russell +tells +obvious +fiber +graph +covering +platinum +judgment +bedrooms +talks +filing +foster +modeling +passing +awarded +trials +tissue +clinton +masters +bonds +alberta +commons +fraud +spectrum +arrival +pottery +emphasis +roger +aspect +awesome +mexican +counts +priced +crash +desired +inter +closer +assumes +heights +shadow +riding +firefox +expense +grove +venture +clinic +korean +healing +princess +entering +packet +spray +studios +buttons +funded +thompson +winners +extend +roads +dublin +rolling +memories +nelson +arrived +creates +faces +tourist +mayor +murder +adequate +senator +yield +grades +cartoons +digest +lodging +hence +entirely +replaced +radar +rescue +losses +combat +reducing +stopped +lakes +closely +diary +kings +shooting +flags +baker +launched +shock +walls +abroad +ebony +drawn +arthur +visited +walker +suggests +beast +operated +targets +overseas +dodge +counsel +pizza +invited +yards +gordon +farmers +queries +ukraine +absence +nearest +cluster +vendors +whereas +serves +woods +surprise +partial +shoppers +couples +ranking +jokes +simpson +twiki +sublime +palace +verify +globe +trusted +copper +dicke +kerry +receipt +supposed +ordinary +nobody +ghost +applying +pride +knowing +reporter +keith +champion +cloudy +linda +chile +plenty +sentence +throat +ignore +maria +uniform +wealth +vacuum +dancing +brass +writes +plaza +outcomes +survival +quest +publish +trans +jonathan +whenever +lifetime +pioneer +booty +acrobat +plates +acres +venue +athletic +thermal +essays +vital +telling +fairly +coastal +config +charity +excel +modes +campbell +stupid +harbor +hungary +traveler +segment +realize +enemy +puzzle +rising +aluminum +wells +wishlist +opens +insight +secrets +lucky +latter +thick +trailers +repeat +syndrome +philips +penalty +glasses +enables +iraqi +builder +vista +jessica +chips +terry +flood +arena +pupils +stewart +outcome +expanded +casual +grown +polish +lovely +extras +centres +jerry +clause +smile +lands +troops +indoor +bulgaria +armed +broker +charger +believed +cooling +trucks +divorce +laura +shopper +tokyo +partly +nikon +candy +pills +tiger +donald +folks +sensor +exposed +telecom +angels +deputy +sealed +loaded +scenes +boost +spanking +founded +chronic +icons +moral +catering +finger +keeps +pound +locate +trained +roses +bread +tobacco +wooden +motors +tough +roberts +incident +gonna +dynamics +decrease +chest +pension +billy +revenues +emerging +worship +craig +herself +churches +damages +reserves +solve +shorts +minority +diverse +johnny +recorder +facing +nancy +tones +passion +sight +defence +patches +refund +towns +trembl +divided +emails +cyprus +insider +seminars +makers +hearts +worry +carter +legacy +pleased +danger +vitamin +widely +phrase +genuine +raising +paradise +hybrid +reads +roles +glory +bigger +billing +diesel +versus +combine +exceed +saudi +fault +babies +karen +compiled +romantic +revealed +albert +examine +jimmy +graham +bristol +margaret +compaq +slowly +rugby +portions +infant +sectors +samuel +fluid +grounds +regards +unlike +equation +baskets +wright +barry +proven +cached +warren +studied +reviewer +involves +profits +devil +grass +comply +marie +florist +cherry +deutsch +kenya +webcam +funeral +nutten +earrings +enjoyed +chapters +charlie +quebec +dennis +francis +sized +manga +noticed +socket +silent +literary +signals +theft +swing +symbols +humans +analog +facial +choosing +talent +dated +seeker +wisdom +shoot +boundary +packard +offset +payday +philip +elite +holders +believes +swedish +poems +deadline +robot +witness +collins +equipped +stages +winds +powder +broadway +acquired +assess +stones +entrance +gnome +roots +losing +attempts +gadgets +noble +glasgow +impacts +gospel +shore +loves +induced +knight +loose +linking +appeals +earned +illness +islamic +pending +parker +lebanon +kennedy +teenage +triple +cooper +vincent +secured +unusual +answered +slots +disorder +routine +toolbar +rocks +titans +wearing +sought +genes +mounted +habitat +firewall +median +scanner +herein +animated +judicial +integer +bachelor +attitude +engaged +falling +basics +montreal +carpet +struct +lenses +binary +genetics +attended +dropped +walter +besides +hosts +moments +atlas +strings +feels +torture +deleted +mitchell +ralph +warner +embedded +inkjet +wizard +corps +actors +liver +liable +brochure +morris +petition +eminem +recall +antenna +picked +assumed +belief +killing +bikini +memphis +shoulder +decor +lookup +texts +harvard +brokers +diameter +ottawa +podcast +seasons +refine +bidder +singer +evans +herald +literacy +fails +aging +plugin +diving +invite +alice +latinas +suppose +involve +moderate +terror +younger +thirty +opposite +rapidly +dealtime +intro +mercedes +clerk +mills +outline +tramadol +holland +receives +jeans +fonts +refers +favor +veterans +sigma +xhtml +occasion +victim +demands +sleeping +careful +arrive +sunset +tracked +moreover +minimal +lottery +framed +aside +licence +michelle +essay +dialogue +camps +declared +aaron +handheld +trace +disposal +florists +packs +switches +romania +consult +greatly +blogging +cycling +midnight +commonly +inform +turkish +pentium +quantum +murray +intent +largely +pleasant +announce +spoke +arrow +sampling +rough +weird +inspired +holes +weddings +blade +suddenly +oxygen +cookie +meals +canyon +meters +merely +passes +pointer +stretch +durham +permits +muslim +sleeve +netscape +cleaner +cricket +feeding +stroke +township +rankings +robin +robinson +strap +sharon +crowd +olympic +remained +entities +customs +rainbow +roulette +decline +gloves +israeli +medicare +skiing +cloud +valve +hewlett +explains +proceed +flickr +feelings +knife +jamaica +shelf +timing +liked +adopt +denied +fotos +britney +freeware +donation +outer +deaths +rivers +tales +katrina +islam +nodes +thumbs +seeds +cited +targeted +skype +realized +twelve +founder +decade +gamecube +dispute +tired +titten +adverse +excerpt +steam +drinks +voices +acute +climbing +stood +perfume +carol +honest +albany +restore +stack +somebody +curve +creator +amber +museums +coding +tracker +passage +trunk +hiking +pierre +jelsoft +headset +oakland +colombia +waves +camel +lamps +suicide +archived +arabia +juice +chase +logical +sauce +extract +panama +payable +courtesy +athens +judges +retired +remarks +detected +decades +walked +arising +nissan +bracelet +juvenile +afraid +acoustic +railway +cassette +pointed +causing +mistake +norton +locked +fusion +mineral +steering +beads +fortune +canvas +parish +claimed +screens +cemetery +planner +croatia +flows +stadium +fewer +coupon +nurses +proxy +lanka +edwards +contests +costume +tagged +berkeley +voted +killer +bikes +gates +adjusted +bishop +pulled +shaped +seasonal +farmer +counters +slave +cultures +norfolk +coaching +examined +encoding +heroes +painted +lycos +zdnet +artwork +cosmetic +resulted +portrait +ethical +carriers +mobility +floral +builders +struggle +schemes +neutral +fisher +spears +bedding +joining +heading +equally +bearing +combo +seniors +worlds +guilty +haven +tablet +charm +violent +basin +ranch +crossing +cottage +drunk +crimes +resolved +mozilla +toner +latex +branches +anymore +delhi +holdings +alien +locator +broke +nepal +zimbabwe +browsing +resolve +melissa +moscow +thesis +nylon +discs +rocky +bargains +frequent +nigeria +ceiling +pixels +ensuring +hispanic +anybody +diamonds +fleet +untitled +bunch +totals +marriott +singing +afford +starring +referral +optimal +distinct +turner +sucking +cents +reuters +spoken +omega +stayed +civic +manuals +watched +saver +thereof +grill +redeem +rogers +grain +regime +wanna +wishes +depend +differ +ranging +monica +repairs +breath +candle +hanging +colored +verified +formerly +situated +seeks +herbal +loving +strictly +routing +stanley +retailer +vitamins +elegant +gains +renewal +opposed +deemed +scoring +brooklyn +sisters +critics +spots +hacker +madrid +margin +solely +salon +norman +turbo +headed +voters +madonna +murphy +thinks +thats +soldier +phillips +aimed +justin +interval +mirrors +tricks +reset +brush +expansys +panels +repeated +assault +spare +kodak +tongue +bowling +danish +monkey +filename +skirt +florence +invest +honey +analyzes +drawings +scenario +lovers +atomic +approx +arabic +gauge +junction +faced +rachel +solving +weekends +produces +chains +kingston +sixth +engage +deviant +quoted +adapters +farms +imports +cheat +bronze +sandy +suspect +macro +sender +crucial +adjacent +tuition +spouse +exotic +viewer +signup +threats +puzzles +reaching +damaged +receptor +laugh +surgical +destroy +citation +pitch +autos +premises +perry +proved +imperial +dozen +benjamin +teeth +cloth +studying +stamp +lotus +salmon +olympus +cargo +salem +starter +upgrades +likes +butter +pepper +weapon +luggage +burden +tapes +zones +races +stylish +maple +grocery +offshore +depot +kenneth +blend +harrison +julie +emission +finest +realty +janet +apparent +phpbb +autumn +probe +toilet +ranked +jackets +routes +packed +excited +outreach +helen +mounting +recover +lopez +balanced +timely +talked +debug +delayed +chuck +explicit +villas +ebook +exclude +peeing +brooks +newton +anxiety +bingo +whilst +spatial +ceramic +prompt +precious +minds +annually +scanners +xanax +fingers +sunny +ebooks +delivers +necklace +leeds +cedar +arranged +theaters +advocacy +raleigh +threaded +qualify +blair +hopes +mason +diagram +burns +pumps +footwear +beijing +peoples +victor +mario +attach +licenses +utils +removing +advised +spider +ranges +pairs +trails +hudson +isolated +calgary +interim +assisted +divine +approve +chose +compound +abortion +dialog +venues +blast +wellness +calcium +newport +indians +shield +harvest +membrane +prague +previews +locally +pickup +mothers +nascar +iceland +candles +sailing +sacred +morocco +chrome +tommy +refused +brake +exterior +greeting +ecology +oliver +congo +botswana +delays +olive +cyber +verizon +scored +clone +dicks +velocity +lambda +relay +composed +tears +oasis +baseline +angry +silicon +compete +lover +belong +honolulu +beatles +rolls +thomson +barnes +malta +daddy +ferry +rabbit +seating +exports +omaha +electron +loads +heather +passport +motel +unions +treasury +warrant +solaris +frozen +occupied +royalty +scales +rally +observer +sunshine +strain +ceremony +somehow +arrested +yamaha +hebrew +gained +dying +laundry +stuck +solomon +placing +stops +homework +adjust +assessed +enabling +filling +imposed +silence +focuses +soviet +treaty +vocal +trainer +organ +stronger +volumes +advances +lemon +toxic +darkness +bizrate +vienna +implied +stanford +packing +statute +rejected +satisfy +shelter +chapel +gamespot +layers +guided +bahamas +powell +mixture +bench +rider +radius +logging +hampton +borders +butts +bobby +sheep +railroad +lectures +wines +nursery +harder +cheapest +travesti +stuart +salvador +salad +monroe +tender +paste +clouds +tanzania +preserve +unsigned +staying +easter +theories +praise +jeremy +venice +estonia +veteran +streams +landing +signing +executed +katie +showcase +integral +relax +namibia +synopsis +hardly +prairie +reunion +composer +sword +absent +sells +ecuador +hoping +accessed +spirits +coral +pixel +float +colin +imported +paths +bubble +acquire +contrary +tribune +vessel +acids +focusing +viruses +cheaper +admitted +dairy +admit +fancy +equality +samoa +stickers +leasing +lauren +beliefs +squad +analyze +ashley +scroll +relate +wages +suffer +forests +invalid +concerts +martial +males +retain +execute +tunnel +genres +cambodia +patents +chaos +wheat +beaver +updating +readings +kijiji +confused +compiler +eagles +bases +accused +unity +bride +defines +airports +begun +brunette +packets +anchor +socks +parade +trigger +gathered +essex +slovenia +notified +beaches +folders +dramatic +surfaces +terrible +routers +pendant +dresses +baptist +hiring +clocks +females +wallace +reflects +taxation +fever +cuisine +surely +myspace +theorem +stylus +drums +arnold +chicks +cattle +radical +rover +treasure +reload +flame +levitra +tanks +assuming +monetary +elderly +floating +bolivia +spell +hottest +stevens +kuwait +emily +alleged +compile +webster +struck +plymouth +warnings +bridal +annex +tribal +curious +freight +rebate +meetup +eclipse +sudan +shuttle +stunning +cycles +affects +detect +actively +ampland +fastest +butler +injured +payroll +cookbook +courier +uploaded +hints +collapse +americas +unlikely +techno +beverage +tribute +wired +elvis +immune +latvia +forestry +barriers +rarely +infected +martha +genesis +barrier +argue +trains +metals +bicycle +letting +arise +celtic +thereby +jamie +particle +minerals +advise +humidity +bottles +boxing +bangkok +hughes +jeffrey +chess +operates +brisbane +survive +oscar +menus +reveal +canal +amino +herbs +clinics +manitoba +missions +watson +lying +costumes +strict +saddam +drill +offense +bryan +protest +hobby +tries +nickname +inline +washing +staffing +trick +enquiry +closure +timber +intense +playlist +showers +ruling +steady +statutes +myers +drops +wider +plugins +enrolled +sensors +screw +publicly +hourly +blame +geneva +freebsd +reseller +handed +suffered +intake +informal +tucson +heavily +swingers +fifty +headers +mistakes +uncle +defining +counting +assure +devoted +jacob +sodium +randy +hormone +timothy +brick +naval +medieval +bridges +captured +thehun +decent +casting +dayton +shortly +cameron +carlos +donna +andreas +warrior +diploma +cabin +innocent +scanning +valium +copying +cordless +patricia +eddie +uganda +fired +trivia +adidas +perth +grammar +syria +disagree +klein +harvey +tires +hazard +retro +gregory +episodes +boolean +circular +anger +mainland +suits +chances +interact +bizarre +glenn +auckland +olympics +fruits +ribbon +startup +suzuki +trinidad +kissing +handy +exempt +crops +reduces +geometry +slovakia +guild +gorgeous +capitol +dishes +barbados +chrysler +nervous +refuse +extends +mcdonald +replica +plumbing +brussels +tribe +trades +superb +trinity +handled +legends +floors +exhaust +shanghai +speaks +burton +davidson +copied +scotia +farming +gibson +roller +batch +organize +alter +nicole +latino +ghana +edges +mixing +handles +skilled +fitted +harmony +asthma +twins +triangle +amend +oriental +reward +windsor +zambia +hydrogen +webshots +sprint +chick +advocate +inputs +genome +escorts +thong +medal +coaches +vessels +walks +knives +arrange +artistic +honors +booth +indie +unified +bones +breed +detector +ignored +polar +fallen +precise +sussex +msgid +invoice +gather +backed +alfred +colonial +carey +motels +forming +embassy +danny +rebecca +slight +proceeds +indirect +amongst +msgstr +arrest +adipex +horizon +deeply +toolbox +marina +prizes +bosnia +browsers +patio +surfing +lloyd +optics +pursue +overcome +attract +brighton +beans +ellis +disable +snake +succeed +leonard +lending +reminder +searched +plains +raymond +insights +sullivan +midwest +karaoke +lonely +hereby +observe +julia +berry +collar +racial +bermuda +amanda +mobiles +kelkoo +exhibits +terrace +bacteria +replied +seafood +novels +ought +safely +finite +kidney +fixes +sends +durable +mazda +allied +throws +moisture +roster +symantec +spencer +wichita +nasdaq +uruguay +timer +tablets +tuning +gotten +tyler +futures +verse +highs +wanting +custody +scratch +launches +ellen +rocket +bullet +towers +racks +nasty +latitude +tumor +deposits +beverly +mistress +trustees +watts +duncan +reprints +bernard +forty +tubes +midlands +priest +floyd +ronald +analysts +queue +trance +locale +nicholas +bundle +hammer +invasion +runner +notion +skins +mailed +fujitsu +spelling +arctic +exams +rewards +beneath +defend +medicaid +infrared +seventh +welsh +belly +quarters +stolen +soonest +haiti +naturals +lenders +fitting +fixtures +bloggers +agrees +surplus +elder +sonic +cheers +belarus +zoning +gravity +thumb +guitars +essence +flooring +ethiopia +mighty +athletes +humanity +holmes +scholars +galaxy +chester +snapshot +caring +segments +dominant +twist +itunes +stomach +buried +newbie +minimize +darwin +ranks +debut +bradley +anatomy +fraction +defects +milton +marker +clarity +sandra +adelaide +monaco +settled +folding +emirates +airfare +vaccine +belize +promised +volvo +penny +robust +bookings +minolta +porter +jungle +ivory +alpine +andale +fabulous +remix +alias +newer +spice +implies +cooler +maritime +periodic +overhead +ascii +prospect +shipment +breeding +donor +tension +trash +shapes +manor +envelope +diane +homeland +excluded +andrea +breeds +rapids +disco +bailey +endif +emotions +incoming +lexmark +cleaners +eternal +cashiers +rotation +eugene +metric +minus +bennett +hotmail +joshua +armenia +varied +grande +closest +actress +assign +tigers +aurora +slides +milan +premiere +lender +villages +shade +chorus +rhythm +digit +argued +dietary +symphony +clarke +sudden +marilyn +lions +findlaw +pools +lyric +claire +speeds +matched +carroll +rational +fighters +chambers +warming +vocals +fountain +chubby +grave +burner +finnish +gentle +deeper +muslims +footage +howto +worthy +reveals +saints +carries +devon +helena +saves +regarded +marion +lobby +egyptian +tunisia +outlined +headline +treating +punch +gotta +cowboy +bahrain +enormous +karma +consist +betty +queens +lucas +tribes +defeat +clicks +honduras +naughty +hazards +insured +harper +mardi +tenant +cabinets +tattoo +shake +algebra +shadows +holly +silly +mercy +hartford +freely +marcus +sunrise +wrapping +weblogs +timeline +belongs +readily +fence +nudist +infinite +diana +ensures +lindsay +legally +shame +civilian +fatal +remedy +realtors +briefly +genius +fighter +flesh +retreat +adapted +barely +wherever +estates +democrat +borough +failing +retained +pamela +andrews +marble +jesse +logitech +surrey +briefing +belkin +highland +modular +brandon +giants +balloon +winston +solved +hawaiian +gratuit +consoles +qatar +magnet +porsche +cayman +jaguar +sheer +posing +hopkins +urgent +infants +gothic +cylinder +witch +cohen +puppy +kathy +graphs +surround +revenge +expires +enemies +finances +accepts +enjoying +patrol +smell +italiano +carnival +roughly +sticker +promises +divide +cornell +satin +deserve +mailto +promo +worried +tunes +garbage +combines +bradford +phrases +chelsea +boring +reynolds +speeches +reaches +schema +catalogs +quizzes +prefix +lucia +savannah +barrel +typing +nerve +planets +deficit +boulder +pointing +renew +coupled +myanmar +metadata +harold +circuits +floppy +texture +handbags +somerset +incurred +antigua +thunder +caution +locks +namely +euros +pirates +aerial +rebel +origins +hired +makeup +textile +nathan +tobago +indexes +hindu +licking +markers +weights +albania +lasting +wicked +kills +roommate +webcams +pushed +slope +reggae +failures +surname +theology +nails +evident +whats +rides +rehab +saturn +allergy +twisted +merit +enzyme +zshops +planes +edmonton +tackle +disks +condo +pokemon +ambien +retrieve +vernon +worldcat +titanium +fairy +builds +shaft +leslie +casio +deutsche +postings +kitty +drain +monte +fires +algeria +blessed +cardiff +cornwall +favors +potato +panic +sticks +leone +excuse +reforms +basement +onion +strand +sandwich +lawsuit +cheque +banners +reject +circles +italic +beats +merry +scuba +passive +valued +courage +verde +gazette +hitachi +batman +hearings +coleman +anaheim +textbook +dried +luther +frontier +settle +stopping +refugees +knights +palmer +derby +peaceful +altered +pontiac +doctrine +scenic +trainers +sewing +conclude +munich +celebs +propose +lighter +advisors +pavilion +tactics +trusts +talented +annie +pillow +derek +shorter +harley +relying +finals +paraguay +steal +parcel +refined +fifteen +fears +predict +boutique +acrylic +rolled +tuner +peterson +shannon +toddler +flavor +alike +homeless +horrible +hungry +metallic +blocked +warriors +cadillac +malawi +sagem +curtis +parental +strikes +lesser +marathon +pressing +gasoline +dressed +scout +belfast +dealt +niagara +warcraft +charms +catalyst +trader +bucks +denial +thrown +prepaid +raises +electro +badge +wrist +analyzed +heath +ballot +lexus +varying +remedies +validity +trustee +weighted +angola +performs +plastics +realm +jenny +helmet +salaries +postcard +elephant +yemen +tsunami +scholar +nickel +buses +expedia +geology +coating +wallet +cleared +smilies +boating +drainage +shakira +corners +broader +rouge +yeast +clearing +coated +intend +louise +kenny +routines +hitting +yukon +beings +aquatic +reliance +habits +striking +podcasts +singh +gilbert +ferrari +brook +outputs +ensemble +insulin +assured +biblical +accent +mysimon +eleven +wives +ambient +utilize +mileage +prostate +adaptor +auburn +unlock +hyundai +pledge +vampire +angela +relates +nitrogen +xerox +merger +softball +firewire +nextel +framing +musician +blocking +rwanda +sorts +vsnet +limiting +dispatch +papua +restored +armor +riders +chargers +remark +dozens +varies +rendered +picking +guards +openings +councils +kruger +pockets +granny +viral +inquire +pipes +laden +aruba +cottages +realtor +merge +edgar +develops +chassis +dubai +pushing +fleece +pierce +allan +dressing +sperm +filme +craps +frost +sally +yacht +tracy +prefers +drilling +breach +whale +tomatoes +bedford +mustang +clusters +antibody +momentum +wiring +pastor +calvin +shark +phases +grateful +emerald +laughing +grows +cliff +tract +ballet +abraham +bumper +webpage +garlic +hostels +shine +senegal +banned +wendy +briefs +diffs +mumbai +ozone +radios +tariff +nvidia +opponent +pasta +muscles +serum +wrapped +swift +runtime +inbox +focal +distant +decimal +propecia +samba +hostel +employ +mongolia +penguin +magical +miracle +manually +reprint +centered +yearly +wound +belle +writings +hamburg +cindy +fathers +charging +marvel +lined +petite +terrain +strips +gossip +rangers +rotary +discrete +beginner +boxed +cubic +sapphire +kinase +skirts +crawford +labeled +marking +serbia +sheriff +griffin +declined +guyana +spies +neighbor +elect +highways +thinkpad +intimate +preston +deadly +bunny +chevy +rounds +longest +tions +dentists +flyer +dosage +variance +cameroon +baking +adaptive +computed +needle +baths +brakes +nirvana +invision +sticky +destiny +generous +madness +emacs +climb +blowing +heated +jackie +sparc +cardiac +dover +adrian +vatican +brutal +learners +token +seekers +yields +suited +numeric +skating +kinda +aberdeen +emperor +dylan +belts +blacks +educated +rebates +burke +proudly +inserted +pulling +basename +obesity +curves +suburban +touring +clara +vertex +tomato +andorra +expired +travels +flush +waiver +hayes +delight +survivor +garcia +cingular +moses +counted +declare +johns +valves +impaired +donors +jewel +teddy +teaches +ventures +bufing +stranger +tragedy +julian +dryer +painful +velvet +tribunal +ruled +pensions +prayers +funky +nowhere +joins +wesley +lately +scary +mattress +mpegs +brunei +likewise +banana +slovak +cakes +mixer +remind +sbjct +charming +tooth +annoying +stays +disclose +affair +drove +washer +upset +restrict +springer +beside +mines +rebound +logan +mentor +fought +baghdad +metres +pencil +freeze +titled +sphere +ratios +concord +endorsed +walnut +lance +ladder +italia +liberia +sherman +maximize +hansen +senators +workout +bleeding +colon +lanes +purse +optimize +stating +caroline +align +bless +engaging +crest +triumph +welding +deferred +alloy +condos +plots +polished +gently +tulsa +locking +casey +draws +fridge +blanket +bloom +simpsons +elliott +fraser +justify +blades +loops +surge +trauma +tahoe +advert +possess +flashers +subaru +vanilla +picnic +souls +arrivals +spank +hollow +vault +securely +fioricet +groove +pursuit +wires +mails +backing +sleeps +blake +travis +endless +figured +orbit +niger +bacon +heater +colony +cannon +circus +promoted +forbes +moldova +paxil +spine +trout +enclosed +cooked +thriller +transmit +apnic +fatty +gerald +pressed +scanned +hunger +mariah +joyce +surgeon +cement +planners +disputes +textiles +missile +intranet +closes +deborah +marco +assists +gabriel +auditor +aquarium +violin +prophet +bracket +isaac +oxide +naples +promptly +modems +harmful +prozac +sexually +dividend +newark +glucose +phantom +playback +turtle +warned +neural +fossil +hometown +badly +apollo +persian +handmade +greene +robots +grenada +scoop +earning +mailman +sanyo +nested +somalia +movers +verbal +blink +carlo +workflow +novelty +bryant +tiles +voyuer +switched +tamil +garmin +fuzzy +grams +richards +budgets +toolkit +render +carmen +hardwood +erotica +temporal +forge +dense +brave +awful +airplane +istanbul +impose +viewers +asbestos +meyer +enters +savage +willow +resumes +throwing +existed +wagon +barbie +knock +potatoes +thorough +peers +roland +optimum +quilt +creature +mounts +syracuse +refresh +webcast +michel +subtle +notre +maldives +stripes +firmware +shepherd +canberra +cradle +mambo +flour +sympathy +choir +avoiding +blond +expects +jumping +fabrics +polymer +hygiene +poultry +virtue +burst +surgeons +bouquet +promotes +mandate +wiley +corpus +johnston +fibre +shades +indices +adware +zoloft +prisoner +daisy +halifax +ultram +cursor +earliest +donated +stuffed +insects +crude +morrison +maiden +examines +viking +myrtle +bored +cleanup +bother +budapest +knitting +attacked +bhutan +mating +compute +redhead +arrives +tractor +allah +unwrap +fares +resist +hoped +safer +wagner +touched +cologne +wishing +ranger +smallest +newman +marsh +ricky +scared +theta +monsters +asylum +lightbox +robbie +stake +cocktail +outlets +arbor +poison diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index afde56f..0393870 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -159,9 +159,9 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.84" +version = "0.1.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b1244b10dcd56c92219da4e14caa97e312079e185f04ba3eea25061561dc0a0" +checksum = "3f934833b4b7233644e5848f235df3f57ed8c80f1528a26c3dfa13d2147fa056" dependencies = [ "proc-macro2", "quote", @@ -3074,7 +3074,6 @@ dependencies = [ "aes 0.7.5", "aes-gcm", "argon2-sys", - "async-trait", "base64 0.21.7", "block-modes", "botan", @@ -3735,7 +3734,7 @@ dependencies = [ "rustc-hash", "rustls", "socket2", - "thiserror 2.0.9", + "thiserror 2.0.11", "tokio", "tracing", ] @@ -3754,7 +3753,7 @@ dependencies = [ "rustls", "rustls-pki-types", "slab", - "thiserror 2.0.9", + "thiserror 2.0.11", "tinyvec", "tracing", "web-time", @@ -4278,9 +4277,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.20" +version = "0.23.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5065c3f250cbd332cd894be57c40fa52387247659b14a2d6041d121547903b1b" +checksum = "8f287924602bf649d949c63dc8ac8b235fa5387d394020705b80c4eb597ce5b8" dependencies = [ "once_cell", "ring", @@ -5255,11 +5254,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.9" +version = "2.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f072643fd0190df67a8bab670c20ef5d8737177d6ac6b2e9a236cb096206b2cc" +checksum = "d452f284b73e6d76dd36758a0c8684b1d5be31f92b89d07fd5822175732206fc" dependencies = [ - "thiserror-impl 2.0.9", + "thiserror-impl 2.0.11", ] [[package]] @@ -5275,9 +5274,9 @@ dependencies = [ [[package]] name = "thiserror-impl" -version = "2.0.9" +version = "2.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b50fa271071aae2e6ee85f842e2e28ba8cd2c5fb67f11fcb1fd70b276f9e7d4" +checksum = "26afc1baea8a989337eeb52b6e72a039780ce45c3edfcc9c5b9d112feeb173c2" dependencies = [ "proc-macro2", "quote", @@ -6635,9 +6634,9 @@ dependencies = [ [[package]] name = "xml-rs" -version = "0.8.24" +version = "0.8.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea8b391c9a790b496184c29f7f93b9ed5b16abb306c05415b68bcc16e4d06432" +checksum = "c5b940ebc25896e71dd073bad2dbaa2abfe97b0a391415e22ad1326d9c54e3c4" [[package]] name = "yoke" diff --git a/src-tauri/src/app_state.rs b/src-tauri/src/app_state.rs index c49368e..8f72291 100644 --- a/src-tauri/src/app_state.rs +++ b/src-tauri/src/app_state.rs @@ -17,15 +17,85 @@ use tauri::{ App, Env, Manager, Runtime, }; -use crate::{app_paths, file_util}; -use crate::biometric; +use crate::app_preference::{Preference, PreferenceData}; +use crate::{biometric, callback_service_provider}; use crate::constants::standard_file_names::APP_PREFERENCE_FILE; use crate::key_secure; -use crate::app_preference::{Preference, PreferenceData}; use crate::translation::current_locale_language; +use crate::{app_paths, file_util}; + +////// App startup time Init call ////////// + +pub fn init_app(app: &App) { + // An example of using Short Cut Key to use with menus and auto typing + use tauri::GlobalShortcutManager; + let _r = app + .app_handle() + .global_shortcut_manager() + .register("Alt+Shift+R", move || { + println!("⌥⇧R is pressed"); + }); + //// + + // Ensure that all app dir paths are created if required and available + app_paths::init_app_paths(); + + let state = app.state::(); + // loggings still not yet setup + state.read_preference(app); + + init_log(&app_paths::app_logs_dir()); + // Now onwards all loggings calls will be effective + + // Se the resource path for latter use + let resource_path = app_paths::app_resources_dir(app.app_handle()) + .ok() + .map(|ref p| PathBuf::from(&p)); + + state.set_resource_dir_path(resource_path); + + key_secure::init_key_main_store(); + + callback_service_provider::init_callback_service_provider(app.app_handle().clone()); + + onekeepass_core::async_service::start_runtime(); + + info!("{}", "Intit app is done"); +} + +fn init_log(log_dir: &PathBuf) { + let local_time = Local::now().format("%Y-%m-%d-%H%M%S").to_string(); + let log_file = format!("{}.log", local_time); + let log_file = log_dir.join(log_file); + + let time_format = "{d(%Y-%m-%d %H:%M:%S)} - {m}{n}"; + let stdout = ConsoleAppender::builder() + .encoder(Box::new(PatternEncoder::new(time_format))) + .build(); + let tofile = FileAppender::builder() + .encoder(Box::new(PatternEncoder::new(time_format))) + .build(log_file) + .unwrap(); + + #[cfg(not(feature = "onekeepass-dev"))] + let level = LevelFilter::Info; + + #[cfg(feature = "onekeepass-dev")] + let level = LevelFilter::Debug; + + let config = Config::builder() + .appender(Appender::builder().build("stdout", Box::new(stdout))) + .appender(Appender::builder().build("file", Box::new(tofile))) + .build(Root::builder().appenders(["stdout", "file"]).build(level)) + .unwrap(); + + log4rs::init_config(config).unwrap(); +} -// IMPORTANT: -// Need to keep all state fields behind Mutex if we need to mutuate as +//////////////////////////////////////////// + +// IMPORTANT: +// Need to keep all state fields behind Mutex if we need to mutuate as // we cann't get &mut self of 'AppState' pub struct AppState { // Here we're using an Arc to share memory among threads, @@ -33,6 +103,7 @@ pub struct AppState { pub preference: Arc>, pub backup_files: Mutex>, timers_init_completed: Mutex, + resource_dir_path: Mutex>, } impl AppState { @@ -44,9 +115,20 @@ impl AppState { // TODO: How to handle this when we want to include time info in the file name backup_files: Mutex::new(HashMap::default()), timers_init_completed: Mutex::new(false), + resource_dir_path: Mutex::new(None), } } + fn set_resource_dir_path(&self, resource_path: Option) { + let mut resource_dir_path = self.resource_dir_path.lock().unwrap(); + *resource_dir_path = resource_path; + } + + pub(crate) fn resource_dir_path(&self,) -> Option { + let resource_dir_path = self.resource_dir_path.lock().unwrap(); + resource_dir_path.clone() + } + pub fn timers_init_completed(&self) { let mut init_status = self.timers_init_completed.lock().unwrap(); *init_status = true; @@ -171,34 +253,6 @@ impl SystemInfoWithPreference { } } -pub fn init_app(app: &App) { - // An example of using Short Cut Key to use with menus and auto typing - use tauri::GlobalShortcutManager; - let _r = app - .app_handle() - .global_shortcut_manager() - .register("Alt+Shift+R", move || { - println!("⌥⇧R is pressed"); - }); - //// - - // Ensure that all app dir paths are created if required and available - app_paths::init_app_paths(); - - let state = app.state::(); - // loggings still not yet setup - state.read_preference(app); - - init_log(&app_paths::app_logs_dir()); - // Now onwards all loggings calls will be effective - - key_secure::init_key_main_store(); - - onekeepass_core::async_service::start_runtime(); - - info!("{}", "Intit app is done"); -} - // TODO Return Result> pub fn load_custom_svg_icons(app: tauri::AppHandle) -> HashMap { //IMPORTANT: @@ -233,7 +287,7 @@ pub fn load_custom_svg_icons(app: tauri::AppHandle) -> HashMap String { let Some(s) = Preference::read_language_selection(preference_file_content) else { @@ -248,35 +302,6 @@ pub fn read_preference_file() -> String { fs::read_to_string(pref_file_name).unwrap_or("".into()) } -fn init_log(log_dir: &PathBuf) { - let local_time = Local::now().format("%Y-%m-%d-%H%M%S").to_string(); - let log_file = format!("{}.log", local_time); - let log_file = log_dir.join(log_file); - - let time_format = "{d(%Y-%m-%d %H:%M:%S)} - {m}{n}"; - let stdout = ConsoleAppender::builder() - .encoder(Box::new(PatternEncoder::new(time_format))) - .build(); - let tofile = FileAppender::builder() - .encoder(Box::new(PatternEncoder::new(time_format))) - .build(log_file) - .unwrap(); - - #[cfg(not(feature = "onekeepass-dev"))] - let level = LevelFilter::Info; - - #[cfg(feature = "onekeepass-dev")] - let level = LevelFilter::Debug; - - let config = Config::builder() - .appender(Appender::builder().build("stdout", Box::new(stdout))) - .appender(Appender::builder().build("file", Box::new(tofile))) - .build(Root::builder().appenders(["stdout", "file"]).build(level)) - .unwrap(); - - log4rs::init_config(config).unwrap(); -} - #[cfg(test)] mod tests { use crate::app_state::Preference; @@ -313,13 +338,13 @@ mod tests { #[test] fn verify_serde_using_alias() { - // Json has 'menu.labels' as field name and it is mapped to - // rust's menu_labels + // Json has 'menu.labels' as field name and it is mapped to + // rust's menu_labels let input1 = r#"{ "menu.labels": {"addField": "Add field","addCategory": "Add category"} }"#; - #[derive(Debug, PartialEq,serde::Deserialize)] + #[derive(Debug, PartialEq, serde::Deserialize)] struct Translation { #[serde(alias = "menu.labels")] menu_labels: HashMap, @@ -332,6 +357,6 @@ mod tests { }; let d: Translation = serde_json::from_str(input1).unwrap(); //println!("D is {:?}, t is {:?}", d,t); - assert_eq!(t,d); + assert_eq!(t, d); } } diff --git a/src-tauri/src/callback_service_provider.rs b/src-tauri/src/callback_service_provider.rs new file mode 100644 index 0000000..83c6a06 --- /dev/null +++ b/src-tauri/src/callback_service_provider.rs @@ -0,0 +1,56 @@ +use std::sync::Arc; + +use log::debug; +use onekeepass_core::callback_service::{CallbackServiceProvider, CommonCallbackService}; +use onekeepass_core::error::{self, Result}; +use tauri::Manager; + +use crate::app_state::AppState; + +// IMPORTANT: +// Should be called during app init call so that the backend api can make a callback to the Runtime +pub(crate) fn init_callback_service_provider(app_handle: tauri::AppHandle) { + let instance = Arc::new(CommonCallbackServiceImpl::new(app_handle)); + // In case, we need to hold any reference at this module, then we need to Arc::clone and use it + CallbackServiceProvider::init(instance); + debug!("init_callback_service_provider is called and CallbackServiceProvider init is done"); +} + +//#[derive(Default)] +struct CommonCallbackServiceImpl { + // We need to hold a copy of app handle to get back the AppState and use fields from that + app_handle: tauri::AppHandle, +} + +impl CommonCallbackServiceImpl { + fn new(app_handle: tauri::AppHandle) -> Self { + Self { app_handle } + } +} + +impl CommonCallbackService for CommonCallbackServiceImpl { + fn load_wordlist(&self, wordlist_file_name: &str) -> Result { + // Though we can get the resouerce dir from 'tauri::AppHandle', we are getting + // our own AppState from this handle and use it to get the resource dir. + // In that way our app specific preferences can be accessed if required + + let app_state = self.app_handle.state::(); + let Some(rseource_path) = app_state.resource_dir_path() else { + return Err(error::Error::DataError("No app resource dir is found")); + }; + + // IMPORTANT: + // We need to add "../resources/public/wordlists" src-tauri/tauri.conf.json + // in order for the file reading. See also translation::load_language_translations and 'load_custom_svg_icons' + // for other app level resources handling + + // _up_/resources/public is the resource dir and all wordlist files are found + // in the sub dir _up_/resources/public/wordlists + + let full_path = rseource_path.join("wordlists").join(wordlist_file_name); + + debug!("Going to load the wordlist file {:?}", &full_path); + + Ok(std::fs::read_to_string(&full_path)?) + } +} diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 40ebe2a..c4634ca 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -15,6 +15,7 @@ mod key_secure; mod menu; mod translation; mod password_gen_preference; +mod callback_service_provider; use constants::event_action_names::*; use constants::event_names::*; diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 90bc1dd..e84538d 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -23,7 +23,8 @@ ], "resources": [ "../resources/public/icons", - "../resources/public/translations" + "../resources/public/translations", + "../resources/public/wordlists" ], "externalBin": [], "copyright": "", diff --git a/src/main/onekeepass/frontend/background_password.cljs b/src/main/onekeepass/frontend/background_password.cljs index 445c939..eab1c80 100644 --- a/src/main/onekeepass/frontend/background_password.cljs +++ b/src/main/onekeepass/frontend/background_password.cljs @@ -9,6 +9,7 @@ "Generates a password with the given options and returns the generated password with its analysis" [password-options dispatch-fn] + #_(println "password-options are " password-options) ;; passwordOptions should be in camelCase as it is the tauri command fn arg ;; However we use 'snake_case' to deserialize the struc 'PasswordGenerationOptions' (invoke-api "analyzed_password" @@ -23,6 +24,7 @@ (invoke-api "score_password" {:password password} dispatch-fn)) (defn generate-password-phrase [password-phrase-options dispatch-fn] + #_(println "password-phrase-options are " password-phrase-options) (invoke-api "generate_password_phrase" (clj->js {:passwordPhraseOptions (->> password-phrase-options @@ -34,7 +36,8 @@ (-> @re-frame.db/app-db keys) (def db-key (:current-db-file-name @re-frame.db/app-db)) (-> @re-frame.db/app-db (get db-key) keys) - (-> (get @re-frame.db/app-db db-key) :entry-form-data) + (def a {:word-list-source {:name "GermanDicewareWordlist"} :words 3 :separator "-" :capitalize-first {:type-name "Always"} :capitalize-words {:type-name "Never"}}) ;;{:name "EFFLarge"} - (def a {:word-list-source {:name "EFFShort2"} :words 5 :separator "-" :capitalize-first {:type-name "Always"} :capitalize-words {:type-name "Never"}}) + (-> (get @re-frame.db/app-db db-key) :entry-form-data) + (def a {:word-list-source {:name "EFFShort1"} :words 3 :separator "-" :capitalize-first {:type-name "Always"} :capitalize-words {:type-name "Never"}}) ) \ No newline at end of file diff --git a/src/main/onekeepass/frontend/common_components.cljs b/src/main/onekeepass/frontend/common_components.cljs index 2635ac9..cd4b2bd 100644 --- a/src/main/onekeepass/frontend/common_components.cljs +++ b/src/main/onekeepass/frontend/common_components.cljs @@ -1,33 +1,30 @@ (ns onekeepass.frontend.common-components - (:require [clojure.string :as str] - [onekeepass.frontend.background :as bg] - [onekeepass.frontend.constants :refer [ADD_TAG_PREFIX]] - [onekeepass.frontend.events.common :as cmn-events] - [onekeepass.frontend.mui-components :as m :refer [auto-sizer - fixed-size-list - is-light-theme? - mui-alert - mui-autocomplete - mui-box - mui-button - mui-dialog - mui-dialog-actions - mui-dialog-content - mui-dialog-content-text - mui-dialog-title - mui-icon-button - mui-icon-close-outlined - mui-icon-file-copy-outlined - mui-linear-progress - mui-snackbar - mui-stack - mui-text-field-type - mui-tooltip - mui-typography - react-use-state]] - [onekeepass.frontend.translation :refer-macros [tr-bl] :refer [lstr-sm]] - [onekeepass.frontend.utils :refer [contains-val?]] - [reagent.core :as r])) + (:require + [clojure.string :as str] + [onekeepass.frontend.background :as bg] + [onekeepass.frontend.constants :refer [ADD_TAG_PREFIX]] + [onekeepass.frontend.events.common :as cmn-events] + [onekeepass.frontend.mui-components :as m :refer [auto-sizer + fixed-size-list + is-light-theme? mui-alert + mui-autocomplete mui-box + mui-button mui-dialog + mui-dialog-actions + mui-dialog-content + mui-dialog-content-text + mui-dialog-title + mui-icon-button + mui-icon-close-outlined + mui-icon-file-copy-outlined + mui-linear-progress + mui-snackbar mui-stack + mui-text-field-type + mui-tooltip + mui-typography + react-use-state]] + [onekeepass.frontend.translation :refer-macros [tr-bl] :refer [lstr-sm]] + [onekeepass.frontend.utils :refer [contains-val? str->int]] + [reagent.core :as r])) #_(set! *warn-on-infer* true) @@ -42,28 +39,28 @@ ;; children ? #_(defn theme-text-field-read-sx [theme-mode] - {"&.MuiInput-root" - {:border 0 - :border-bottom (if (is-light-theme?) - "1px solid #eeeeee" (str "1px solid " "rgba(255, 255, 255, 0.3)")) + {"&.MuiInput-root" + {:border 0 + :border-bottom (if (is-light-theme?) + "1px solid #eeeeee" (str "1px solid " "rgba(255, 255, 255, 0.3)")) ;; :border-bottom-color "#eeeeee" ;; :border-bottom-style "solid" ;; :border-bottom-width "1px" - } + } ;; "&.Mui-focused" ;; {:border "1px solid var(--color-primary-main)" ;; :border-bottom "1px solid var(--color-primary-main)"} - }) + }) #_(defn theme-text-field-edit-sx [theme-mode] - {"&.MuiInput-root" - {:border "1px solid grey" - :outline "1px solid transparent"} + {"&.MuiInput-root" + {:border "1px solid grey" + :outline "1px solid transparent"} - "&.Mui-focused" - {:border "1px solid var(--color-primary-main)" - :outline "1px solid var(--color-primary-main)"}}) + "&.Mui-focused" + {:border "1px solid var(--color-primary-main)" + :outline "1px solid var(--color-primary-main)"}}) (defn theme-text-field-sx [edit theme] (if edit @@ -509,6 +506,37 @@ :on-click #(bg/write-to-clipboard value)} [mui-icon-file-copy-outlined]]))) +#_(defn on-change-factory + "A function factory + The arg 'handler-name' is a fn that is called with supplier arg 'field-name-kw' and + the event value + Returns a function that can be used in a on-change handler of a text field + " + [handler-name field-name-kw] + (fn [^js/Event e] + (handler-name field-name-kw (-> e .-target .-value)))) + +(defn on-change-factory + "A function factory + The arg 'handler-name' is a fn that is called + with supplied arg 'field-name-kw' and the event value + Returns a function that can be used in a on-change handler of a text field + " + ([handler-name field-name-kw int-val] + (fn [^js/Event e] + (let [val (-> e .-target .-value) + ;; Need to ensure that length is an int as expected by backend api + val (if int-val (str->int val) val)] + (handler-name field-name-kw val)))) + ([handler-name field-name-kw] + (on-change-factory handler-name field-name-kw false))) + +(defn on-check-factory + "Called in on-change handler of a check field" + [handler-name field-name-kw] + (fn [e] + (handler-name field-name-kw (-> e .-target .-checked)))) + (defn overflow-tool-tip "Tooltip is enabled only when the text has ellipsis shown This is based on tips in diff --git a/src/main/onekeepass/frontend/entry_form/dialogs.cljs b/src/main/onekeepass/frontend/entry_form/dialogs.cljs index dc5153f..ddc0cc0 100644 --- a/src/main/onekeepass/frontend/entry_form/dialogs.cljs +++ b/src/main/onekeepass/frontend/entry_form/dialogs.cljs @@ -2,12 +2,11 @@ (:require [clojure.string :as str] [onekeepass.frontend.common-components :refer [alert-dialog-factory confirm-text-dialog - enter-key-pressed-factory selection-autocomplete]] + enter-key-pressed-factory selection-autocomplete on-change-factory + on-check-factory]] [onekeepass.frontend.db-icons :as db-icons] [onekeepass.frontend.entry-form.common :as ef-cmn :refer [popper-button-sx - theme-popper-box-sx]] - [onekeepass.frontend.events.common :as ce :refer [on-change-factory - on-check-factory]] + theme-popper-box-sx]] [onekeepass.frontend.events.entry-form-dialogs :as dlg-events] [onekeepass.frontend.events.entry-form-ex :as form-events] [onekeepass.frontend.events.move-group-entry :as move-events] diff --git a/src/main/onekeepass/frontend/entry_form/fields.cljs b/src/main/onekeepass/frontend/entry_form/fields.cljs index fa8bff0..95d6b70 100644 --- a/src/main/onekeepass/frontend/entry_form/fields.cljs +++ b/src/main/onekeepass/frontend/entry_form/fields.cljs @@ -58,8 +58,8 @@ on-change-handler select-field-options]}] ;; We are using the mui-text-field directly as select component - ;; Another way also, this type of simple select list can be done using the following. - ;; The examples given in mui.com uses now this method + ;; This type of simple select list can also be done using the following components + ;; as given in the examples found mui.com which uses now this method ;; [mui-form-control [mui-input-label] [mui-select {} [mui-menu-item]] [mui-form-helper-text] ] [mui-text-field {:id key :sx {:margin-top cc/entry-cnt-field-margin-top} diff --git a/src/main/onekeepass/frontend/entry_form_ex.cljs b/src/main/onekeepass/frontend/entry_form_ex.cljs index b4252be..d5d2011 100644 --- a/src/main/onekeepass/frontend/entry_form_ex.cljs +++ b/src/main/onekeepass/frontend/entry_form_ex.cljs @@ -239,6 +239,8 @@ (swap! refs assoc key e))} [mui-stack {:direction "row" :sx {:width (if edit "92%" "100%")}} (cond + ;; select-field-options is vec of strings and gets data from + ;; field 'select_field_options' in struct KeyValueData (not (nil? select-field-options)) [simple-selection-field (assoc kv :edit edit diff --git a/src/main/onekeepass/frontend/events/common.cljs b/src/main/onekeepass/frontend/events/common.cljs index af81f2d..ab956d2 100644 --- a/src/main/onekeepass/frontend/events/common.cljs +++ b/src/main/onekeepass/frontend/events/common.cljs @@ -6,7 +6,7 @@ [onekeepass.frontend.constants :as const :refer [ADD_TAG_PREFIX DB_CHANGED]] [onekeepass.frontend.events.common-supports :as cmn-supports] - [onekeepass.frontend.translation :refer-macros [tr-dlg-title tr-dlg-text ] :refer [lstr-sm]] + [onekeepass.frontend.translation :refer-macros [tr-dlg-title tr-dlg-text] :refer [lstr-sm]] [onekeepass.frontend.utils :refer [contains-val? str->int utc-to-local-datetime-str]] [re-frame.core :refer [dispatch dispatch-sync reg-event-db @@ -41,6 +41,7 @@ ;;;;;;;;;;;;;;;;;;;;;;;; Common factory ;;;;;;;;;;;;;;;;;;;;;;;; +;; TODO: Move to common-components (defn on-change-factory "A function factory The arg 'handler-name' is a fn that is called with supplier arg 'field-name-kw' and @@ -62,7 +63,7 @@ (declare set-session-timeout) #_(defn load-language-translation-completed [] - (dispatch [:load-language-translation-complete])) + (dispatch [:load-language-translation-complete])) (defn new-db-full-file-name [app-db db-name] (let [document-dir (-> app-db :standard-dirs :document-dir) @@ -95,6 +96,9 @@ (defn os-name [] (subscribe [:os-name])) +(defn app-preference-phrase-generator-options [app-db] + (-> app-db :app-preference :password-gen-preference :phrase-generator-options)) + (reg-event-fx :init-process (fn [{:keys [_db]} [_event-id]] @@ -164,7 +168,7 @@ (reg-event-fx :clear-recent-files-done - (fn [{:keys [db]} [_event-id]] + (fn [{:keys [db]} [_event-id]] {:db (assoc-in db [:app-preference :recent-files] [])})) (reg-sub diff --git a/src/main/onekeepass/frontend/events/password_generator.cljs b/src/main/onekeepass/frontend/events/password_generator.cljs index 61ffebc..2a656c0 100644 --- a/src/main/onekeepass/frontend/events/password_generator.cljs +++ b/src/main/onekeepass/frontend/events/password_generator.cljs @@ -2,9 +2,10 @@ (:require [re-frame.core :refer [reg-event-db reg-event-fx reg-fx reg-sub dispatch subscribe]] [clojure.string :as str] - [onekeepass.frontend.translation :refer-macros [tr-m] ] + [onekeepass.frontend.translation :refer-macros [tr-m]] [onekeepass.frontend.events.common :as cmn-events :refer [check-error]] - [onekeepass.frontend.background :as bg])) + [onekeepass.frontend.background :as bg] + [onekeepass.frontend.background-password :as bg-pwd])) (defn generator-dialog-data-update [kw value] @@ -18,17 +19,27 @@ [] (dispatch [:generator-password-copied])) +(defn set-active-password-generator-panel [kw-panel-id] + (dispatch [:set-active-password-generator-panel kw-panel-id])) + +(defn pass-phrase-options-update [kw value] + (dispatch [:pass-phrase-options-update kw value])) + (defn generator-dialog-data [] (subscribe [:generator-dialog-data])) +(defn generator-panel-selected [] + (subscribe [:generator-panel-selected])) + ;;;; (def generator-dialog-init-data {:dialog-show false - :password-visible false + :password-visible true :text-copied false :callback-on-copy-fn nil - :password-options {;; All fields from struct PasswordGenerationOptions - :length 8 + :panel-shown :password + ;; All fields from struct PasswordGenerationOptions + :password-options {:length 8 :numbers true :lowercase-letters true :uppercase-letters true @@ -36,18 +47,22 @@ :spaces false :exclude-similar-characters true :strict true} - ;;; + ;; All fields from struct PassphraseGenerationOptions + :phrase-generator-options {} + ;; some fields from struct 'AnalyzedPassword' form the map in :password-result :password-result {:password nil :analyzed-password nil :is-common false - ;; value of :score is a map from enum PasswordScore - ;; note the use of #[serde(tag = "name")] in PasswordScore + ;; value of :score is a map from enum PasswordScore + ;; note the use of #[serde(tag = "name")] in PasswordScore :score {:name nil :raw-value nil :score-text nil}}}) (defn- init-dialog-data [app-db] - (assoc-in app-db [:generator :dialog-data] generator-dialog-init-data)) + (let [phrase-generator-options (cmn-events/app-preference-phrase-generator-options app-db)] + (-> app-db (assoc-in [:generator :dialog-data] generator-dialog-init-data) + (assoc-in [:generator :dialog-data :phrase-generator-options] phrase-generator-options)))) ;; Updates all top level fields of dialog-data (defn- to-generator-dialog-data [db & {:as kws}] @@ -56,10 +71,10 @@ (assoc-in db [:generator :dialog-data] data))) ;; Updates all :data fields -(defn- to-password-options-data [db & {:as kws}] - (let [data (get-in db [:generator :dialog-data :password-options]) +(defn- to-password-options-data [db kw-option-key & {:as kws}] + (let [data (get-in db [:generator :dialog-data kw-option-key #_:password-options]) data (merge data kws)] - (assoc-in db [:generator :dialog-data :password-options] data))) + (assoc-in db [:generator :dialog-data kw-option-key #_:password-options] data))) (reg-event-db :generator-dialog-data-update @@ -71,7 +86,7 @@ :password-options-update (fn [{:keys [db]} [_event-id field-name-kw value]] (let [db (-> db - (to-password-options-data field-name-kw value) + (to-password-options-data :password-options field-name-kw value) (to-generator-dialog-data :text-copied false)) {:keys [length] :as po} (get-in db [:generator :dialog-data :password-options])] (if (empty? (str/trim (str length))) @@ -90,7 +105,7 @@ {:db db :fx [[:bg-analyzed-password po]]}))) -(defn- handle-error +(defn- handle-error "Receives the error part of the api response" [error-text] (let [txt (condp = error-text @@ -114,6 +129,7 @@ (reg-event-db :password-generation-complete (fn [db [_event-id password-result]] + ;;(println ":password-generation-complete called "password-result) (-> db (assoc-in [:generator :dialog-data :password-result] password-result) (assoc-in [:generator :dialog-data :dialog-show] true)))) @@ -144,11 +160,91 @@ (fn [db [_query-id]] (get-in db [:generator :dialog-data :password-result]))) +(reg-sub + :generator-panel-selected + (fn [db [_query-id]] + (get-in db [:generator :dialog-data :panel-shown]))) + + +;;;;;;;;;;;;;;;;;;;;;;;; Pass phrase ;;;;;;;;;;;;;;;;;;;;;; +(reg-event-fx + :set-active-password-generator-panel + (fn [{:keys [db]} [_event-id kw-panel-id]] + (let [po (get-in db [:generator :dialog-data :password-options]) + ppo (get-in db [:generator :dialog-data :phrase-generator-options])] + {:db (assoc-in db [:generator :dialog-data :panel-shown] kw-panel-id) + :fx [(if (= kw-panel-id :password) + [:bg-analyzed-password po] [:bg-generate-password-phrase ppo])]}))) + +(reg-fx + :bg-generate-password-phrase + (fn [pass-phrase-options] + (bg-pwd/generate-password-phrase + pass-phrase-options + (fn [api-response] + (when-let [result (check-error api-response #(dispatch [:common/message-snackbar-error-open %]))] + (dispatch [:pass-phrase-generation-complete result])))))) + +;; map generated-pass-phrase is from struct GeneratedPassPhrase +(reg-event-fx + :pass-phrase-generation-complete + (fn [{:keys [db]} [_event-id {:keys [password] :as generated-pass-phrase}]] + ;;(println "generated-pass-phrase is " generated-pass-phrase) + {:fx [[:dispatch [:password-generation-complete generated-pass-phrase] ]]})) + +(reg-event-fx + :pass-phrase-options-update + (fn [{:keys [db]} [_event-id field-name-kw value]] + (let [db (-> db + (to-password-options-data :phrase-generator-options field-name-kw value) + (to-generator-dialog-data :text-copied false)) + {:keys [words] :as po} (get-in db [:generator :dialog-data :phrase-generator-options])] + (if (empty? (str/trim (str words))) + {:db db + :fx [[:dispatch [:common/message-snackbar-error-open "At least 1 word is required" #_(tr-m passwordGenerator above8)]]]} + {:db db + :fx [[:dispatch [:common/message-snackbar-error-close]] + [:bg-generate-password-phrase po]]})))) + +#_(reg-event-fx + :pass-phrase-generator/start + (fn [{:keys [db]} [_event-id callback-on-copy-fn]] + (let [phrase-generator-options (cmn-events/app-preference-phrase-generator-options db) + db (-> db init-dialog-data + (assoc-in [:generator :dialog-data :callback-on-copy-fn] callback-on-copy-fn)) + po (get-in db [:generator :dialog-data :password-options])] + {:db db + :fx [[:bg-analyzed-password po]]}))) + +#_(def pass-phrase-generator-dialog-init-data + {:dialog-show false + :password-visible false + :text-copied false + :callback-on-copy-fn nil + :phrase-generator-options {} + ;;; + :password-result {:password nil + :analyzed-password nil + :is-common false + ;; value of :score is a map from enum PasswordScore + ;; note the use of #[serde(tag = "name")] in PasswordScore + :score {:name nil + :raw-value nil + :score-text nil}}}) + + +#_(defn- init-pass-phrase-dialog-data [app-db] + (let [phrase-generator-options (cmn-events/app-preference-phrase-generator-options app-db) + data (assoc pass-phrase-generator-dialog-init-data :phrase-generator-options phrase-generator-options)] + (assoc-in app-db [:generator :dialog-data] data))) + + + (comment (def db-key (:current-db-file-name @re-frame.db/app-db)) (-> @re-frame.db/app-db :generator) (get-in @re-frame.db/app-db [:generator :dialog-data :password-options]) - (def a (to-password-options-data @re-frame.db/app-db :length 11)) + (def a (to-password-options-data :password-options @re-frame.db/app-db :length 11)) (-> @re-frame.db/app-db :generator :dialog-data :password-result :score)) diff --git a/src/main/onekeepass/frontend/password_generator.cljs b/src/main/onekeepass/frontend/password_generator.cljs index 6d1023a..28e1c2c 100644 --- a/src/main/onekeepass/frontend/password_generator.cljs +++ b/src/main/onekeepass/frontend/password_generator.cljs @@ -6,24 +6,11 @@ mui-dialog-actions mui-dialog-content mui-dialog-title mui-form-control-label mui-icon-button mui-icon-visibility mui-icon-visibility-off mui-input mui-input-adornment mui-slider - mui-stack mui-text-field mui-typography]] + mui-stack mui-text-field mui-typography mui-tabs mui-tab]] [onekeepass.frontend.translation :refer-macros [tr-l tr-h tr-bl tr-dlg-title] :refer [lstr-l-cv]] - [onekeepass.frontend.utils :refer [str->int]] [reagent.core :as r])) -(defn on-change-factory [handler-name field-name-kw] - [handler-name field-name-kw] - (fn [^js/Event e] - (let [val (-> e .-target .-value) - ;; Need to ensure that length is an int as expected by backend api - val (if (= :length field-name-kw) (str->int val) val)] - (handler-name field-name-kw val)))) - -(defn on-check-factory [handler-name field-name-kw] - (fn [^js/Event e] - (handler-name field-name-kw (-> e .-target .-checked)))) - -(defn end-icons [value visibile?] +(defn- end-icons [visibile?] [:<> (if visibile? [mui-icon-button @@ -42,111 +29,333 @@ ;; This call will provide an alert to the user #_(gen-events/generator-dialog-data-update :text-copied true)))]]) + +(defn- tab-panel-selection [panel-shown] + [mui-tabs {:value panel-shown + :on-change (fn [_event val] + ;; val is of string type and need to be coverted as keyword + (gen-events/set-active-password-generator-panel (keyword val)))} + [mui-tab {:label "Password" :value :password}] + [mui-tab {:label "Password Phrase" :value :pass-phrase}]]) + + +;; TODO: Move to 'common-components' and also change in 'src/main/onekeepass/frontend/entry_form/fields.cljs' +;; to use this common one +(defn simple-selection-field [{:keys [key + value + edit + error-text + helper-text + on-change-handler + select-field-options]} & {:as opts}] + ;; We are using the mui-text-field directly as select component + ;; This type of simple select list can also be done using the following components + ;; as given in the examples found mui.com which uses now this method + ;; [mui-form-control [mui-input-label] [mui-select {} [mui-menu-item]] [mui-form-helper-text] ] + [mui-text-field {:id key + :sx (merge {:margin-top cc/entry-cnt-field-margin-top} (:sx opts)) + :required false + ;;:classes {:root "entry-cnt-field"} + :select true + :label key #_(tr-entry-field-name-cv key) + :value value + :on-change on-change-handler + :error (not (nil? error-text)) + :helperText (if (nil? error-text) helper-text error-text) + :inputProps {:readOnly (not edit)} + :variant "standard" :fullWidth true} + (doall (for [y select-field-options] + ^{:key y} [m/mui-menu-item {:value y} y]))]) + +(def EFFLarge "EFFLarge") +(def EFFShort1 "EFFShort1") +(def EFFShort2 "EFFShort2") + +(def all-wl [EFFLarge EFFShort1 EFFShort2]) + +(def capitalize-word-choices ["Always" "Never" "Sometimes"]) + +(def capitalize-first-choices ["Always" "Never" "Sometimes"]) + + +(defn pass-phrase-panel [{:keys [password-visible + text-copied] + {:keys [words separator capitalize-words capitalize-first]} :phrase-generator-options + {:keys [password + score]} :password-result}] + [mui-stack {:sx {:align-items "center"}} + [mui-stack {:sx {:width "80%"}} + [mui-stack {:direction "row"} + [simple-selection-field {:key "Wordlist" :value EFFLarge :edit true :on-change-handler #() :select-field-options all-wl}]] + [mui-stack {:direction "row" :spacing 2 :sx {:margin-top "10px"}} + [mui-stack {:sx {:width "25%"}} + [mui-typography "Words" #_(tr-l "words")]] + [mui-stack {:direction "row" :sx {:width "50%"}} + [mui-slider {:value words + :size "small" + :valueLabelDisplay "auto" + :min 1 + :max 40 + :on-change (fn [_e value] + (gen-events/pass-phrase-options-update :words value))}]] + [mui-stack {:direction "row" :sx {:width "25%"}} + [mui-input {:value words + :on-change (cc/on-change-factory gen-events/pass-phrase-options-update :words true) + :on-blur (fn [] + (cond + (< words 1) + #() #_(gen-events/pass-phrase-options-update :length 8) + + (> words 40) + #() #_(gen-events/pass-phrase-options-update :length 100))) + :inputProps {:min 1 :max 40 :type "number"}}]]] + [mui-stack {:direction "row" :sx {:width "50%"}} + [m/text-field {:label "Separator" + :value separator + :variant "standard" + :on-change (cc/on-change-factory gen-events/pass-phrase-options-update :separator)}]] + [mui-stack {:direction "row"} + [mui-stack {:direction "row" :sx {:width "50%"}} + [simple-selection-field {:key "Capitalize words" :value "Always" :select-field-options capitalize-word-choices}]] + [mui-stack {:width 8}] + [mui-stack {:direction "row" :sx {:width "50%"}} + [simple-selection-field {:key "Capitalize first letter" :value "Always" :select-field-options capitalize-first-choices}]]] + + [mui-stack {:direction "row" :sx {:width "100%" :margin-top "10px"}} + [mui-text-field + {:label (tr-l password) + :value password + :sx (merge {} (cc/password-helper-text-sx (:name score))) + :helper-text (-> score :name lstr-l-cv) + :InputProps {:endAdornment (r/as-element + [mui-input-adornment {:position "end"} + [end-icons password-visible]]) + :type (if password-visible "text" "password") + :readOnly true} + :variant "standard" + :fullWidth true}]]]]) + +;; [mui-typography "Pass phrase will come here"] + +(defn password-panel [{:keys [password-visible + text-copied] + {:keys [length + lowercase-letters + uppercase-letters + numbers + symbols]} :password-options + {:keys [analyzed-password + score]} :password-result}] + [mui-stack {:sx {:align-items "center"}} + [mui-stack {:sx {:width "80%"}} + [mui-stack {:direction "row" :spacing 2 :sx {:margin-top "10px"}} + [mui-stack {:sx {:width "25%"}} + [mui-typography (tr-l length)]] + [mui-stack {:direction "row" :sx {:width "50%"}} + [mui-slider {:value length + :size "small" + :valueLabelDisplay "auto" + :min 8 + :max 100 + :on-change (fn [_e value] + (gen-events/password-options-update :length value))}]] + [mui-stack {:direction "row" :sx {:width "25%"}} + [mui-input {:value length + :on-change (cc/on-change-factory gen-events/password-options-update :length true) + :on-blur (fn [] + (cond + (< length 8) + (gen-events/password-options-update :length 8) + + (> length 100) + (gen-events/password-options-update :length 100))) + :inputProps {:min 8 :max 100 :type "number"}}]]] + + [mui-stack {:direction "row"} + [mui-stack {:sx {:width "50%"}} + [mui-form-control-label + {:control (r/as-element + [mui-checkbox + {:checked lowercase-letters + :on-change (cc/on-check-factory + gen-events/password-options-update :lowercase-letters)}]) + :label (tr-l lowerCaseAZ)}]] + [mui-stack {:sx {:width "50%"}} + [mui-form-control-label + {:control (r/as-element + [mui-checkbox + {:checked uppercase-letters + :on-change (cc/on-check-factory + gen-events/password-options-update :uppercase-letters)}]) + :label (tr-l upperCaseAZ)}]]] + + [mui-stack {:direction "row"} + [mui-stack {:sx {:width "50%"}} + [mui-form-control-label + {:control (r/as-element + [mui-checkbox + {:checked numbers + :on-change (cc/on-check-factory + gen-events/password-options-update :numbers)}]) + :label (tr-l numbers)}]] + [mui-stack {:sx {:width "50%"}} + [mui-form-control-label + {:control (r/as-element + [mui-checkbox + {:checked symbols + :on-change (cc/on-check-factory + gen-events/password-options-update :symbols)}]) + :label (tr-l symbols)}]]] + + [mui-stack {:direction "row" :sx {:width "100%"}} + [mui-text-field + {:label (tr-l password) + :value analyzed-password + :sx (merge {} (cc/password-helper-text-sx (:name score))) + :helper-text (-> score :name lstr-l-cv) + :InputProps {:endAdornment (r/as-element + [mui-input-adornment {:position "end"} + [end-icons password-visible]]) + :type (if password-visible "text" "password") + :readOnly true} + :variant "standard" + :fullWidth true}]] + + (when text-copied [mui-stack {:sx {:margin-top "5px"}} + [mui-alert {:severity "success" + :sx {"&.MuiAlert-root" {:width "100%"}}} ;; need to override the paper width 60% ;;:sx {"&.MuiAlert-root" {:width "100%"}} + [mui-alert-title (tr-l success)] (tr-h copiedToClipboard)]])]]) + (defn password-generator-dialog - [{:keys [dialog-show - password-visible - text-copied] - {:keys [length - lowercase-letters - uppercase-letters - numbers - symbols]} :password-options - {:keys [analyzed-password - score]} :password-result}] - [mui-dialog {:open dialog-show :on-click #(.stopPropagation ^js/Event %) + [{:keys [dialog-show panel-shown] :as pass-options}] + (let [current-selection @(gen-events/generator-panel-selected)] + [mui-dialog {:open dialog-show :on-click #(.stopPropagation ^js/Event %) + ;; This will set the Paper width in all child components + ;; and is equivalent to :classes {:paper "pwd-dlg-root"} + :sx {"& .MuiPaper-root" {:width "80%"}}} + + [mui-dialog-title [tab-panel-selection panel-shown]] + [mui-dialog-content {:dividers true} + (if (= panel-shown :password) + [password-panel pass-options] + [pass-phrase-panel pass-options])] + [mui-dialog-actions + [mui-button {:on-click + (fn [] + (gen-events/generator-password-copied) + (gen-events/generator-dialog-data-update :dialog-show false))} + (tr-bl copyClose)] + [mui-button {:on-click + #(gen-events/generator-dialog-data-update :dialog-show false)} + (tr-bl close)]]])) + + + +#_(defn password-generator-dialog + [{:keys [dialog-show + password-visible + text-copied] + {:keys [length + lowercase-letters + uppercase-letters + numbers + symbols]} :password-options + {:keys [analyzed-password + score]} :password-result}] + [mui-dialog {:open dialog-show :on-click #(.stopPropagation ^js/Event %) ;; This will set the Paper width in all child components ;; and is equivalent to :classes {:paper "pwd-dlg-root"} - :sx {"& .MuiPaper-root" {:width "80%"}}} - - [mui-dialog-title (tr-dlg-title passwordGenerator)] - [mui-dialog-content {:dividers true} - [mui-stack {:sx {:align-items "center"}} - [mui-stack {:sx {:width "80%"}} - [mui-stack {:direction "row" :spacing 2 :sx {:margin-top "10px"}} - [mui-stack {:sx {:width "25%"}} - [mui-typography (tr-l length)]] - [mui-stack {:direction "row" :sx {:width "50%"}} - [mui-slider {:value length - :size "small" - :valueLabelDisplay "auto" - :min 8 - :max 100 - :on-change (fn [_e value] - (gen-events/password-options-update :length value))}]] - [mui-stack {:direction "row" :sx {:width "25%"}} - [mui-input {:value length - :on-change (on-change-factory gen-events/password-options-update :length) - :on-blur (fn [] - (cond - (< length 8) - (gen-events/password-options-update :length 8) - - (> length 100) - (gen-events/password-options-update :length 100))) - :inputProps {:min 8 :max 100 :type "number"}}]]] - - [mui-stack {:direction "row"} - [mui-stack {:sx {:width "50%"}} - [mui-form-control-label - {:control (r/as-element - [mui-checkbox - {:checked lowercase-letters - :on-change (on-check-factory - gen-events/password-options-update :lowercase-letters)}]) - :label (tr-l lowerCaseAZ)}]] - [mui-stack {:sx {:width "50%"}} - [mui-form-control-label - {:control (r/as-element - [mui-checkbox - {:checked uppercase-letters - :on-change (on-check-factory - gen-events/password-options-update :uppercase-letters)}]) - :label (tr-l upperCaseAZ)}]]] - - [mui-stack {:direction "row"} - [mui-stack {:sx {:width "50%"}} - [mui-form-control-label - {:control (r/as-element - [mui-checkbox - {:checked numbers - :on-change (on-check-factory - gen-events/password-options-update :numbers)}]) - :label (tr-l numbers)}]] - [mui-stack {:sx {:width "50%"}} - [mui-form-control-label - {:control (r/as-element - [mui-checkbox - {:checked symbols - :on-change (on-check-factory - gen-events/password-options-update :symbols)}]) - :label (tr-l symbols)}]]] - - [mui-stack {:direction "row" :sx {:width "100%"}} - [mui-text-field - {:label (tr-l password) - :value analyzed-password - :sx (merge {} (cc/password-helper-text-sx (:name score))) - :helper-text (-> score :name lstr-l-cv) - :InputProps {:endAdornment (r/as-element - [mui-input-adornment {:position "end"} - [end-icons analyzed-password password-visible]]) - :type (if password-visible "text" "password") - :readOnly true} - :variant "standard" - :fullWidth true}]] - - (when text-copied [mui-stack {:sx {:margin-top "5px"}} - [mui-alert {:severity "success" - :sx {"&.MuiAlert-root" {:width "100%"}}} ;; need to override the paper width 60% ;;:sx {"&.MuiAlert-root" {:width "100%"}} - [mui-alert-title (tr-l success)] (tr-h copiedToClipboard)]])]]] - [mui-dialog-actions - [mui-button {:on-click - (fn [] - (gen-events/generator-password-copied) - (gen-events/generator-dialog-data-update :dialog-show false))} - (tr-bl copyClose)] - [mui-button {:on-click - #(gen-events/generator-dialog-data-update :dialog-show false)} - (tr-bl close)]]]) + :sx {"& .MuiPaper-root" {:width "80%"}}} + + [mui-dialog-title (tr-dlg-title passwordGenerator)] + [mui-dialog-content {:dividers true} + [mui-stack {:sx {:align-items "center"}} + [mui-stack {:sx {:width "80%"}} + [mui-stack {:direction "row" :spacing 2 :sx {:margin-top "10px"}} + [mui-stack {:sx {:width "25%"}} + [mui-typography (tr-l length)]] + [mui-stack {:direction "row" :sx {:width "50%"}} + [mui-slider {:value length + :size "small" + :valueLabelDisplay "auto" + :min 8 + :max 100 + :on-change (fn [_e value] + (gen-events/password-options-update :length value))}]] + [mui-stack {:direction "row" :sx {:width "25%"}} + [mui-input {:value length + :on-change (on-change-factory gen-events/password-options-update :length) + :on-blur (fn [] + (cond + (< length 8) + (gen-events/password-options-update :length 8) + + (> length 100) + (gen-events/password-options-update :length 100))) + :inputProps {:min 8 :max 100 :type "number"}}]]] + + [mui-stack {:direction "row"} + [mui-stack {:sx {:width "50%"}} + [mui-form-control-label + {:control (r/as-element + [mui-checkbox + {:checked lowercase-letters + :on-change (on-check-factory + gen-events/password-options-update :lowercase-letters)}]) + :label (tr-l lowerCaseAZ)}]] + [mui-stack {:sx {:width "50%"}} + [mui-form-control-label + {:control (r/as-element + [mui-checkbox + {:checked uppercase-letters + :on-change (on-check-factory + gen-events/password-options-update :uppercase-letters)}]) + :label (tr-l upperCaseAZ)}]]] + + [mui-stack {:direction "row"} + [mui-stack {:sx {:width "50%"}} + [mui-form-control-label + {:control (r/as-element + [mui-checkbox + {:checked numbers + :on-change (on-check-factory + gen-events/password-options-update :numbers)}]) + :label (tr-l numbers)}]] + [mui-stack {:sx {:width "50%"}} + [mui-form-control-label + {:control (r/as-element + [mui-checkbox + {:checked symbols + :on-change (on-check-factory + gen-events/password-options-update :symbols)}]) + :label (tr-l symbols)}]]] + + [mui-stack {:direction "row" :sx {:width "100%"}} + [mui-text-field + {:label (tr-l password) + :value analyzed-password + :sx (merge {} (cc/password-helper-text-sx (:name score))) + :helper-text (-> score :name lstr-l-cv) + :InputProps {:endAdornment (r/as-element + [mui-input-adornment {:position "end"} + [end-icons analyzed-password password-visible]]) + :type (if password-visible "text" "password") + :readOnly true} + :variant "standard" + :fullWidth true}]] + + (when text-copied [mui-stack {:sx {:margin-top "5px"}} + [mui-alert {:severity "success" + :sx {"&.MuiAlert-root" {:width "100%"}}} ;; need to override the paper width 60% ;;:sx {"&.MuiAlert-root" {:width "100%"}} + [mui-alert-title (tr-l success)] (tr-h copiedToClipboard)]])]]] + [mui-dialog-actions + [mui-button {:on-click + (fn [] + (gen-events/generator-password-copied) + (gen-events/generator-dialog-data-update :dialog-show false))} + (tr-bl copyClose)] + [mui-button {:on-click + #(gen-events/generator-dialog-data-update :dialog-show false)} + (tr-bl close)]]]) From 9cacc61e45d3c2947946c8ab79c56d494839fb8c Mon Sep 17 00:00:00 2001 From: jeyasankar Date: Tue, 14 Jan 2025 17:32:11 -0800 Subject: [PATCH 04/15] Added translation texts; Changes in pass phrase gen options persisted --- resources/public/translations/de.json | 377 ++++++++++++++++++ resources/public/translations/en.json | 43 +- resources/public/translations/es.json | 21 +- resources/public/translations/zh.json | 377 ++++++++++++++++++ src-tauri/src/app_preference.rs | 8 + src-tauri/src/password_gen_preference.rs | 37 +- .../onekeepass/frontend/events/common.cljs | 19 - .../frontend/events/password_generator.cljs | 128 +++--- .../frontend/password_generator.cljs | 245 ++++-------- 9 files changed, 973 insertions(+), 282 deletions(-) create mode 100644 resources/public/translations/de.json create mode 100644 resources/public/translations/zh.json diff --git a/resources/public/translations/de.json b/resources/public/translations/de.json new file mode 100644 index 0000000..06ee34d --- /dev/null +++ b/resources/public/translations/de.json @@ -0,0 +1,377 @@ +{ + "helperTexts": { + "cardVerificationValue/Number": "Kartenprüfwert/-nummer", + "copiedToClipboard": "In die Zwischenablage kopiert", + "customFieldAdded": "Benutzerdefiniertes Feld hinzugefügt. Sie können weitere Felder hinzufügen oder zum Schließen abbrechen", + "databaseSettingsChange": "Änderung der Datenbankeinstellungen läuft", + "dbDisplayName": "Anzeigename für Ihre Datenbank", + "entryTitle": "Titel dieses Eintrags", + "entryTypeFields": "Der Typ eines Eintrags bestimmt die verfügbaren Felder", + "groupOrCategory": "Gruppe/Kategorie eines Eintrags", + "invalidOtpUrl": "Ungültige OTP-URL. Kein Token wird generiert", + "keyFileNotUsed": "Schlüsseldatei wird im Hauptschlüssel nicht verwendet", + "keyFileWillBeChanged": "Sie ändern die Verwendung der vorhandenen Schlüsseldatei", + "keyFileWillBeRemoved": "Sie entfernen die Verwendung der Schlüsseldatei", + "keyFileWillBeUsed": "Schlüsseldatei wird im Hauptschlüssel verwendet", + "keyOrAuthurl": "Bitte geben Sie den codierten Schlüssel oder die vollständige TOTPAuth-URL ein", + "noEntrySelected": "Kein Eintragsinhalt ausgewählt. Wählen oder erstellen Sie einen neuen", + "passwordForYourDb": "Passwort für Ihre Datenbank", + "passwordIsChanged": "Passwort wurde entfernt und wird im Hauptschlüssel nicht verwendet", + "passwordNotUsed": "Passwort wurde entfernt und wird im Hauptschlüssel nicht verwendet", + "passwordWillBeChanged": "Passwort wird geändert...", + "requiresApplicationRestart": "Erfordert Neustart der Anwendung", + "selectAValidGroup": "Bitte wählen Sie eine gültige Gruppe", + "selectTag": "Wählen Sie ein Tag aus oder beginnen Sie, ein neues einzugeben und hinzufügen" + }, + "titles": { + "basicDatabaseInformation": "Grundlegende Datenbankinformationen", + "databaseCredentials": "Datenbank-Anmeldedaten", + "databaseFile": "Datenbankdatei", + "databaseLocked": "Datenbank gesperrt", + "getStarted": "Los geht's", + "entryManagement": "Eintragsverwaltung", + "openDatabase": "Datenbank öffnen", + "newEntry": "Neuer Eintrag", + "newEntryType": "Neuer benutzerdefinierter Eintragstyp", + "recent": "Kürzlich", + "start": "Start", + "security": "Sicherheit", + "selectAGroup": "Wählen Sie eine Gruppe", + "timeouts": "Zeitlimits", + "userInterface": "Benutzeroberfläche", + "unlockDatabase": "Datenbank entsperren" + }, + "labels": { + "1Year": "1 Jahr", + "3Months": "3 Monate", + "6Months": "6 Monate", + "addAdditionalProtection": "Zusätzlichen Schutz hinzufügen (optional)", + "addEntry": "Eintrag hinzufügen", + "addPassword": "Passwort hinzufügen", + "addSection": "Abschnitt hinzufügen", + "algorithm": "Algorithmus", + "allEntries": "Alle Einträge", + "appSettings": "App-Einstellungen", + "backToEntry": "Zurück zum Eintrag", + "browse": "Durchsuchen", + "cancel": "Abbrechen", + "category": "Kategorie", + "categories": "Kategorien", + "changePassword": "Passwort ändern", + "clearList": "Liste leeren", + "clipboardTimeout": "Zwischenablage-Timeout (in Sek.)", + "confirmPassword": "Passwort bestätigen", + "created": "Erstellt", + "creationTime": "Erstellungszeit", + "credentials": "Anmeldeinformationen", + "customDate": "Benutzerdefiniertes Datum", + "customSettings": "Benutzerdefinierte Einstellungen", + "dangerous": "Gefährlich", + "dark": "Dunkel", + "deleted": "Gelöscht", + "deleteType": "Typ löschen", + "description": "Beschreibung", + "done": "Fertig", + "edit": "Bearbeiten", + "encriptionAlgorithm": "Verschlüsselungsalgorithmus", + "entryGroupings": "Eintragsgruppierungen", + "entryType": "Eintragstyp", + "entryTypeName": "Eintragstypname", + "expires": "Läuft ab", + "expiryDuration": "Ablaufdauer", + "expiryDate": "Ablaufdatum", + "favorites": "Favoriten", + "fieldName": "Feldname", + "fileName": "Dateiname", + "foundHistoryEntries": "Gefundene Historieneinträge", + "good": "Gut", + "generate": "Generieren", + "general": "Allgemein", + "groupOrCategory": "Gruppe/Kategorie", + "group": "Gruppe", + "groups": "Gruppen", + "hideAdditionalProtection": "Zusätzlichen Schutz verbergen", + "icons": "Symbole", + "info": "Info", + "invulnerable": "Unverwundbar", + "keepHistories": "Verläufe behalten", + "kdf": "Schlüsselableitungsfunktion", + "keyFileName": "Schlüsseldateiname", + "language": "Sprache", + "lastModified": "Zuletzt geändert", + "lastModificationTime": "Zeit der letzten Änderung", + "length": "Länge", + "light": "Hell", + "lowerCaseAZ": "Kleinbuchstaben (a-z)", + "memoryUsage": "Speichernutzung", + "modifySectionName": "Abschnittsnamen ändern", + "name": "Name", + "newDatabase": "Neue Datenbank", + "newTitle": "Neuer Titel", + "noExpiry": "Kein Ablauf", + "next": "Weiter", + "newsectionName": "Neuer Abschnittsname", + "notes": "Notizen", + "numbers": "Zahlen", + "openDatabase": "Datenbank öffnen", + "oneTimePasswordTotp": "Einmal-Passwort (TOTP)", + "parallelism": "Parallelität", + "password": "Passwort", + "period": "Zeitraum (Sek.)", + "protected": "Geschützt", + "previous": "Vorherige", + "previousVersions": "Vorherige Versionen", + "remove": "Entfernen", + "saveAs": "Speichern unter", + "searchTerm": "Suchbegriff", + "security": "Sicherheit", + "sessionTimeout": "Sitzungs-Timeout (in Min.)", + "setUpOneTimePassword": "Einmal-Passwort einrichten", + "secretOrTotpAuthUrl": "Geheimnis oder TOTPAuth-URL", + "sectionName": "Abschnittsname", + "strong": "Stark", + "success": "Erfolg", + "symbols": "Symbole", + "tags": "Tags", + "theme": "Design", + "transformRounds": "Transformationsrunden", + "tokenlength": "Tokenlänge", + "types": "Typen", + "upperCaseAZ": "Großbuchstaben (A-Z)", + "uuid": "UUID", + "veryDangerous": "Sehr gefährlich", + "veryStrong": "Sehr stark", + "veryWeak": "Sehr schwach", + "weak": "Schwach" + }, + "dialog": { + "titles": { + "applicationSettings": "Anwendungseinstellungen", + "cloneEntry": "Eintrag klonen", + "confirmDiscard": "Verwerfen bestätigen", + "confirmOverwrite": "Überschreiben bestätigen", + "conflictOnSave": "Inhaltskonflikte erkannt", + "databaseChanged": "Datenbank geändert", + "databaseSettings": "Datenbankeinstellungen", + "deleteAllHistories": "Alle Historieneinträge löschen", + "deleteAttachment": "Anhang löschen", + "deleteField": "Feld löschen", + "deleteHistory": "Historieneintrag löschen", + "deleteSectionAndField": "Abschnitt löschen", + "emptyRecycleBin": "Papierkorb leeren", + "entryDeletePermanent": "Eintrag dauerhaft löschen", + "groupDeletePermanent": "Gruppe dauerhaft löschen", + "groupDetails": "Gruppendetails", + "icons": "Symbole", + "otpDelete": "Einmal-Passwort löschen", + "otpSetup": "TOTP-Einrichtung", + "passwordGenerator": "Passwortgenerator", + "putBack": "Zurücklegen", + "restoreEntry": "Eintrag wiederherstellen", + "search": "Suche", + "sectionField1": "Feld hinzufügen in {{sectionName}}", + "sectionField2": "Feld bearbeiten in {{sectionName}}", + "unsavedChanges": "Ungespeicherte Änderungen" + }, + "texts": { + "confirmDiscard": "Möchten Sie Ihre Änderungen verwerfen und die Datenbank schließen?", + "confirmOverwrite": "Möchten Sie die extern geänderte Datenbank mit Ihren Änderungen überschreiben?", + "conflictOnSaveTxt1": "Der Datenbankinhalt der Datei hat sich seit dem letzten Öffnen geändert. Bitte führen Sie eine der folgenden Aktionen aus:", + "conflictOnSaveTxt2": "Sie können Ihre Änderungen in einer neuen Datenbank speichern und manuell zusammenführen (Automatische Zusammenführung wird in einer zukünftigen Version hinzugefügt)", + "conflictOnSaveTxt3": "Sie können die Datenbank mit Ihren Änderungen überschreiben", + "conflictOnSaveTxt4": "Sie können Ihre Änderungen verwerfen und die Datenbank schließen", + "databaseChangedTxt1": "Der Datenbankinhalt der Datei hat sich seit dem letzten Öffnen geändert.", + "databaseChangedTxt2": "Bitte speichern Sie, um verfügbare Optionen zur Lösung zu sehen", + "deleteAllHistories": "Alle Historieneinträge für diesen Eintrag werden dauerhaft gelöscht", + "deleteAttachment": "Sind Sie sicher, dass Sie diesen Anhang löschen möchten?", + "deleteField": "Sind Sie sicher, dass Sie diesen Abschnitt und alle seine Felder dauerhaft löschen möchten?", + "deleteHistory": "Diese Version des Verlaufs wird dauerhaft gelöscht", + "deleteSectionAndField": "Sind Sie sicher, dass Sie diesen Abschnitt und alle seine Felder dauerhaft löschen möchten?", + "emptyRecycleBin": "Sind Sie sicher, dass Sie den Papierkorb dauerhaft leeren möchten?", + "entryDeletePermanent": "Sind Sie sicher, dass Sie diesen Eintrag dauerhaft löschen möchten?", + "groupDeletePermanent": "Sind Sie sicher, dass Sie diese Gruppe und ihre Untergruppen dauerhaft löschen möchten?", + "otpDelete": "Sind Sie sicher, dass Sie dieses TOTP-Feld löschen möchten?", + "restoreEntry": "Der vorhandene Eintrag wird durch diesen Historieneintrag ersetzt", + "unsavedChangesTxt1": "Es gibt noch ungespeicherte Änderungen. Bitte speichern Sie, bevor Sie die Datenbank sperren", + "unsavedChangesTxt2": "Es gibt noch ungespeicherte Änderungen. Möchten Sie speichern und dann beenden?", + "unsavedChangesTxt3": "Es gibt noch ungespeicherte Änderungen. Möchten Sie speichern, bevor Sie die Datenbank schließen?" + } + }, + "entryTypeTitles": { + "bankAccount": "Bankkonto", + "credit/DebitCard": "Kredit-/Debitkarte", + "login": "Anmeldung", + "wirelessRouter": "WLAN-Router" + }, + "entryFieldNames": { + "accountHolder": "Kontoinhaber", + "accountNumber": "Kontonummer", + "accountType": "Kontoart", + "additionalUrLs": "Weitere URLs", + "addressLine1": "Adresszeile 1", + "addressLine2": "Adresszeile 2", + "bankCode/RoutingNumber": "Bankleitzahl", + "baseStationNameOrSsid": "Name der Basisstation oder SSID", + "brand": "Marke", + "cardholderName": "Karteninhabername", + "city": "Stadt", + "contactEmail": "Kontakt-E-Mail", + "contactNumber": "Kontaktnummer", + "country": "Land", + "creditLimit": "Kreditlimit", + "cvc": "CVC", + "expirationMonth": "Ablaufmonat", + "expirationYear": "Ablaufjahr", + "expiryDuration": "Ablaufdauer", + "issuingBank": "Ausstellende Bank", + "notes": "Notizen", + "number": "Nummer", + "otp": "OTP", + "phoneNumber": "Telefonnummer", + "password": "Passwort", + "pin": "PIN", + "state": "Bundesland", + "swift": "SWIFT", + "tags": "Tags", + "title": "Titel", + "url": "URL", + "userName": "Benutzername", + "zipCode": "Postleitzahl" + }, + "entrySectionNames": { + "accountDetails": "Kontodetails", + "additionalDetails": "Weitere Details", + "additionalOneTimePasswords": "Weitere Einmal-Passwörter", + "attachments": "Anhänge", + "bankAddress": "Bankadresse", + "billingAddress": "Rechnungsadresse", + "cardDetails": "Kartendetails", + "notes": "Notizen", + "loginDetails": "Anmeldedaten" + }, + "buttonLabels": { + "addEntry": "Eintrag hinzufügen", + "addKeyFile": "Schlüsseldatei hinzufügen", + "addPassword": "Passwort hinzufügen", + "apply": "Anwenden", + "browse": "Durchsuchen", + "cancel": "Abbrechen", + "changeKeyFile": "Schlüsseldatei ändern", + "changePassword": "Passwort ändern", + "copyClose": "Kopieren & Schließen", + "close": "Schließen", + "delete": "Löschen", + "deleteAll": "Alles löschen", + "discard": "Verwerfen", + "discardClose": "Verwerfen & Datenbank schließen", + "doNotSave": "Nicht speichern", + "done": "Fertig", + "edit": "Bearbeiten", + "generate": "Generieren", + "generateNewKeyFile": "Neue Schlüsseldatei generieren", + "next": "Weiter", + "no": "Nein", + "ok": "Ok", + "overwrite": "Überschreiben", + "quit": "Beenden", + "quickUnlock": "Schnell entsperren", + "removeKeyFile": "Schlüsseldatei entfernen", + "removePassword": "Passwort entfernen", + "restore": "Wiederherstellen", + "saveAs": "Speichern unter", + "save": "Speichern", + "yes": "Ja", + "yesOverwrite": "Ja, überschreiben" + }, + "menuLabels": { + "addField": "Feld hinzufügen", + "addCategory": "Kategorie hinzufügen", + "addGroup": "Gruppe hinzufügen", + "clone": "Klonen", + "createdTime": "Erstellungszeit", + "delete": "Löschen", + "deletePermanent": "Dauerhaft löschen", + "deleteType": "Typ löschen", + "edit": "Bearbeiten", + "editAutoType": "AutoType bearbeiten", + "favorites": "Favoriten", + "history": "Verlauf", + "info": "Info", + "modifiedTime": "Änderungszeit", + "performAutoType": "AutoType ausführen", + "putBack": "Zurücklegen", + "setUpTOPT": "TOTP einrichten", + "sortAtoZ": "Sortieren A-Z", + "sortZtoA": "Sortieren Z-A", + "title": "Titel" + }, + "messages": { + "appSettings": { + "sessionValidVal": "Gültige Werte sollten im Bereich von 1 Minute bis 1440 Minuten liegen", + "clipboardValidVal": "Gültige Werte sollten im Bereich von 10 Sek. bis 300 Sek. liegen" + }, + "databaseSettings": { + "databaseName": "Ein gültiger Datenbankname ist erforderlich", + "iterations": "Gültige Werte sollten im Bereich von 5 - 100 liegen", + "memory": "Gültige Werte sollten im Bereich von 1 - 1000 liegen", + "noCredentialSet": "Die Datenbank muss mit einem Hauptschlüssel geschützt werden, der aus einem Passwort oder einer Schlüsseldatei oder beidem besteht", + "parallelism": "Gültige Werte sollten im Bereich von 1 - 100 liegen", + "passwordConfirm": "Passwort und Passwort bestätigen stimmen nicht überein" + }, + "entryForm": { + "groupSelection": "Bitte wählen Sie eine Gruppe", + "cloneEntryTitleName": "Bitte geben Sie einen gültigen Titel ein", + "titleName": "Bitte geben Sie einen Titel für dieses Formular ein" + }, + "newDbPage": { + "txt1": "Sie können eine beliebige zufällige Datei auswählen, die sich nicht ändert. Ein Hash des Dateiinhalts wird als zusätzliches Passwort verwendet.", + "txt2": "Alternativ kann OneKeePass eine Schlüsseldatei mit einem zufälligen Schlüssel generieren, um sie als zusätzlichen Schlüssel zu verwenden", + "txt3": "Datenbankerstellung läuft", + "txt4": "Datenbankdatei existiert bereits und wird durch diese neue ersetzt" + }, + "openDbPage": { + "txt1": "Bitte geben Sie ein gültiges Passwort oder eine Schlüsseldatei oder beides ein", + "txt2": "Datenbanköffnung läuft" + }, + "passwordGenerator": { + "oneKindCharaterRequired": "Sie müssen mindestens eine Art von Zeichen aktivieren.", + "length0": "Die Länge von Passwörtern kann nicht 0 sein.", + "above8": "Eine gültige Länge ist erforderlich und sollte 8 oder höher sein" + } + }, + "snackbarMessages": { + "dbBackupCompleted": "Datenbanksicherung abgeschlossen", + "dbClosed": "Datenbank {{- dbFileName}} geschlossen", + "entryCloned": "Eintrag wurde geklont", + "entryCreated": "Neuer Eintrag wurde erstellt", + "entryUpdated": "Eintrag wurde aktualisiert", + "dbOpened": "Datenbank {{- dbFileName}} geöffnet" + }, + "systemMenus": { + "main": { + "Database": "Datenbank", + "Edit": "Bearbeiten", + "Entries": "Einträge", + "File": "Datei", + "Groups": "Gruppen", + "Tools": "Werkzeuge" + }, + "subMenus": { + "CloseDatabase": "Datenbank schließen", + "EditEntry": "Eintrag bearbeiten", + "EditGroup": "Gruppe bearbeiten", + "LockAllDatabases": "Alle Datenbanken sperren", + "LockDatabase": "Datenbank sperren", + "NewDatabase": "Neue Datenbank", + "NewEntry": "Neuer Eintrag", + "NewGroup": "Neue Gruppe", + "OpenDatabase": "Datenbank öffnen", + "PasswordGenerator": "Passwortgenerator", + "Quit": "OneKeePass beenden", + "SaveDatabase": "Datenbank speichern", + "SaveDatabaseAs": "Datenbank speichern unter", + "SaveDatabaseBackup": "Datenbanksicherung speichern", + "AppSettings": "Einstellungen..." + } + } +} diff --git a/resources/public/translations/en.json b/resources/public/translations/en.json index d1ec5a4..8186541 100644 --- a/resources/public/translations/en.json +++ b/resources/public/translations/en.json @@ -31,7 +31,7 @@ "getStarted": "Get Started", "entryManagement": "Entry Management", "openDatabase": "Open Database", - "newEntry":"New Entry", + "newEntry": "New Entry", "newEntryType": "New Custom Entry Type", "recent": "Recent", "start": "Start", @@ -51,10 +51,13 @@ "addSection": "Add Section", "algorithm": "Algorithm", "allEntries": "AllEntries", + "always": "Always", "appSettings": "App Settings", "backToEntry": "Back to Entry", "browse": "Browse", "cancel": "Cancel", + "capitalizeFirstLetter": "Capitalize first letter", + "capitalizeWords": "Capitalize words", "category": "Category", "categories": "Categories", "changePassword": "Change password", @@ -94,7 +97,7 @@ "icons": "Icons", "info": "Info", "invulnerable": "Invulnerable", - "keepHistories":"Keep Histories", + "keepHistories": "Keep Histories", "kdf": "Key Derivation Function", "keyFileName": "Key File Name", "language": "Language", @@ -107,28 +110,32 @@ "modifySectionName": "Modify section name", "name": "Name", "newDatabase": "New Database", - "newTitle":"New Title", + "newTitle": "New Title", "noExpiry": "No Expiry", "next": "Next", "newsectionName": "New section name", + "never": "Never", "notes": "Notes", "numbers": "Numbers", "openDatabase": "Open Database", "oneTimePasswordTotp": "One-Time Password(TOTP)", "parallelism": "Parallelism", "password": "Password", + "passwordPhrase": "Password Phrase", "period": "Period(sec)", "protected": "Protected", "previous": "Previous", "previousVersions": "Previous Versions", "remove": "Remove", "saveAs": "Save As", - "searchTerm":"Search term", + "searchTerm": "Search term", "security": "Security", "sessionTimeout": "Session Timeout(in min)", "setUpOneTimePassword": "Set up One-Time Password", "secretOrTotpAuthUrl": "Secret or TOTPAuth URL", "sectionName": "Section Name", + "separator": "Separator", + "sometimes": "Sometimes", "strong": "Strong", "success": "Success", "symbols": "Symbols", @@ -142,12 +149,14 @@ "veryDangerous": "Very Dangerous", "veryStrong": "Very Strong", "veryWeak": "Very Weak", - "weak": "Weak" + "weak": "Weak", + "wordList": "Word List", + "words": "Words" }, "dialog": { "titles": { "applicationSettings": "Application Settings", - "cloneEntry":"Clone entry", + "cloneEntry": "Clone entry", "confirmDiscard": "Confirm Discard", "confirmOverwrite": "Confirm Overwrite", "conflictOnSave": "Content conflicts detected", @@ -168,7 +177,7 @@ "passwordGenerator": "Password Generator", "putBack": "Put back", "restoreEntry": "Restore entry", - "search":"Search", + "search": "Search", "sectionField1": "Add field in {{sectionName}}", "sectionField2": "Modify field in {{sectionName}}", "unsavedChanges": "Unsaved Changes" @@ -287,7 +296,7 @@ "addField": "Add field", "addCategory": "Add category", "addGroup": "Add Group", - "clone":"Clone", + "clone": "Clone", "createdTime": "Created Time", "delete": "Delete", "deletePermanent": "Delete Permanent", @@ -336,18 +345,18 @@ "passwordGenerator": { "oneKindCharaterRequired": "You need to enable at least one kind of characters.", "length0": "The length of passwords cannot be 0.", - "above8": "A valid length number is required and it should be 8 or above" + "above8": "A valid length number is required and it should be 8 or above", + "atLeastOneWord": "At least 1 word is required" } }, - "snackbarMessages":{ - "dbBackupCompleted":"Database backup saving is completed", - "dbClosed":"Closed database {{- dbFileName}}", - "entryCloned":"Entry is cloned", - "entryCreated":"New entry is created", - "entryUpdated":"Entry is updated", - "dbOpened":"Opened database {{- dbFileName}}" + "snackbarMessages": { + "dbBackupCompleted": "Database backup saving is completed", + "dbClosed": "Closed database {{- dbFileName}}", + "entryCloned": "Entry is cloned", + "entryCreated": "New entry is created", + "entryUpdated": "Entry is updated", + "dbOpened": "Opened database {{- dbFileName}}" }, - "systemMenus": { "main": { "Database": "Database", diff --git a/resources/public/translations/es.json b/resources/public/translations/es.json index fc58683..75df526 100644 --- a/resources/public/translations/es.json +++ b/resources/public/translations/es.json @@ -31,7 +31,7 @@ "getStarted": "Empezar", "entryManagement": "Gestión de entradas", "openDatabase": "Base de datos abierta", - "newEntry":"Nueva entrada", + "newEntry": "Nueva entrada", "newEntryType": "Nuevo tipo de entrada personalizada", "recent": "Recientes", "start": "Inicio", @@ -100,7 +100,7 @@ "lastModified": "Última modificación", "lastModificationTime": "Hora de la última modificación", "length": "Longitud", - "light": "Ligero", + "light": "Claro", "lowerCaseAZ": "Minúsculas (a-z)", "memoryUsage": "Uso de la memoria", "modifySectionName": "Modificar el nombre de la sección", @@ -121,7 +121,7 @@ "previousVersions": "Versiones anteriores", "remove": "Eliminar", "saveAs": "Guardar como", - "searchTerm":"Término de búsqueda", + "searchTerm": "Término de búsqueda", "security": "Seguridad", "sessionTimeout": "Tiempo de espera de la sesión (en minutos)", "setUpOneTimePassword": "Configurar contraseña de un solo uso", @@ -165,7 +165,7 @@ "passwordGenerator": "Generador de contraseñas", "putBack": "Poner de nuevo", "restoreEntry": "Restablecer entrada", - "search":"Buscar", + "search": "Buscar", "sectionField1": "Añadir campo en {{sección Nombre}}", "sectionField2": "Modificar campo en {{sección Nombre }}", "unsavedChanges": "Cambios no guardados" @@ -328,13 +328,12 @@ "above8": "Se requiere un número de longitud válido y debe ser 8 o superior" } }, - "snackbarMessages":{ - "dbBackupCompleted":"Se ha guardado la copia de seguridad de la base de datos", - "dbClosed":"Base de datos cerrada {{- dbFileName}}", - "entryCreated":"Se crea una nueva entrada", - "entryUpdated":"Entrada actualizada", - "dbOpened":"Base de datos abierta {{- dbFileName}}" - + "snackbarMessages": { + "dbBackupCompleted": "Se ha guardado la copia de seguridad de la base de datos", + "dbClosed": "Base de datos cerrada {{- dbFileName}}", + "entryCreated": "Se crea una nueva entrada", + "entryUpdated": "Entrada actualizada", + "dbOpened": "Base de datos abierta {{- dbFileName}}" }, "systemMenus": { "main": { diff --git a/resources/public/translations/zh.json b/resources/public/translations/zh.json new file mode 100644 index 0000000..cd1f340 --- /dev/null +++ b/resources/public/translations/zh.json @@ -0,0 +1,377 @@ +{ + "helperTexts": { + "cardVerificationValue/Number": "卡片验证值", + "copiedToClipboard": "复制到剪切板", + "customFieldAdded": "自定义字段已添加。您可以添加更多字段或取消以关闭", + "databaseSettingsChange": "正在处理数据库更改", + "dbDisplayName": "数据库的展示名称", + "entryTitle": "条目的标题", + "entryTypeFields": "由条目类型控制的字段", + "groupOrCategory": "条目的组", + "invalidOtpUrl": "无效的OTP URL,没有生成的token", + "keyFileNotUsed": "主密钥中未使用密钥文件", + "keyFileWillBeChanged": "你正在改变密钥文件", + "keyFileWillBeRemoved": "你正在删除密钥文件", + "keyFileWillBeUsed": "密钥文件将会用来增强主密钥", + "keyOrAuthurl": "输入TOTP密钥或者TOTP URL,通常通过扫描QR码获得", + "noEntrySelected": "未选择条目内容。请选择或创建一个新的", + "passwordForYourDb": "数据库的密码", + "passwordIsChanged": "密码已经移除且不在,不在用于主密钥", + "passwordNotUsed": "密码已经移除且不在,不在用于主密钥", + "passwordWillBeChanged": "密码将会被改变", + "requiresApplicationRestart": "应用需要重启", + "selectAValidGroup": "请选择有效的组", + "selectTag": "选择一个标签或者添加一个新的标签" + }, + "titles": { + "basicDatabaseInformation": "数据库信息", + "databaseCredentials": "数据库凭证", + "databaseFile": "数据库文件", + "databaseLocked": "数据库已锁定", + "getStarted": "开始", + "entryManagement": "密码项管理", + "openDatabase": "打开数据库", + "newEntry": "新建密码项", + "newEntryType": "新建自定义密码项类型", + "recent": "最近", + "start": "开始", + "security": "安全", + "selectAGroup": "选择一个组", + "timeouts": "超时设置", + "userInterface": "用户界面", + "unlockDatabase": "解锁数据库" + }, + "labels": { + "1Year": "1年", + "3Months": "3个月", + "6Months": "6个月", + "addAdditionalProtection": "添加额外的保护(可选)", + "addEntry": "添加密码项", + "addPassword": "添加密码", + "addSection": "添加部分", + "algorithm": "算法", + "allEntries": "所有密码项", + "appSettings": "APP 设置", + "backToEntry": "返回到条目", + "browse": "浏览", + "cancel": "取消", + "category": "目录", + "categories": "目录", + "changePassword": "修改密码", + "clearList": "清理列表", + "clipboardTimeout": "剪切板时间超时", + "confirmPassword": "确认密码", + "created": "创建", + "creationTime": "创建时间", + "credentials": "凭证", + "customDate": "自定义日期", + "customSettings": "自定义设置", + "dangerous": "危险", + "dark": "深色", + "deleted": "已删除", + "deleteType": "删除类型", + "description": "描述", + "done": "完成", + "edit": "编辑", + "encriptionAlgorithm": "加密算法", + "entryGroupings": "密码项组", + "entryType": "密码项类型", + "entryTypeName": "密码项类型名称", + "expires": "过期", + "expiryDuration": "过期时间", + "expiryDate": "过期日期", + "favorites": "收藏", + "fieldName": "字段名称", + "fileName": "文件名", + "foundHistoryEntries": "找到历史木马项", + "good": "良好", + "generate": "生成", + "general": "常规", + "groupOrCategory": "组/类别", + "group": "组", + "groups": "组", + "hideAdditionalProtection": "隐藏额外保护", + "icons": "图标", + "info": "信息", + "invulnerable": "不易损坏的", + "keepHistories": "保留历史记录", + "kdf": "密钥派生函数", + "keyFileName": "密钥文件名", + "language": "语言", + "lastModified": "最后修改", + "lastModificationTime": "最后修改时间", + "length": "长度", + "light": "浅色", + "lowerCaseAZ": "小写字母", + "memoryUsage": "内存时间", + "modifySectionName": "修改部分名称", + "name": "名称", + "newDatabase": "新建数据库", + "newTitle": "新建标题", + "noExpiry": "永不过期", + "next": "下一步", + "newsectionName": "新建部分名称", + "notes": "备注", + "numbers": "数字", + "openDatabase": "打开数据库", + "oneTimePasswordTotp": "一次性密码", + "parallelism": "并行度", + "password": "密码", + "period": "周期(秒)", + "protected": "受保护", + "previous": "上一步", + "previousVersions": "以前的版本", + "remove": "移除", + "saveAs": "另存为", + "searchTerm": "搜索词", + "security": "安全", + "sessionTimeout": "会话超时(分钟)", + "setUpOneTimePassword": "设置一次性密码", + "secretOrTotpAuthUrl": "密钥 或 OTP URL", + "sectionName": "部分名称", + "strong": "强", + "success": "成功", + "symbols": "符号", + "tags": "标签", + "theme": "主题", + "transformRounds": "转换轮数", + "tokenlength": "令牌长度", + "types": "类型", + "upperCaseAZ": "大写", + "uuid": "UUID", + "veryDangerous": "非常危险", + "veryStrong": "非常强", + "veryWeak": "非常弱", + "weak": "弱" + }, + "dialog": { + "titles": { + "applicationSettings": "应用设置", + "cloneEntry": "复制密码项", + "confirmDiscard": "确认丢弃", + "confirmOverwrite": "确认重写", + "conflictOnSave": "检测到内容冲突", + "databaseChanged": "数据库改变", + "databaseSettings": "数据库设置", + "deleteAllHistories": "删除所有历史密码项", + "deleteAttachment": "删除附件", + "deleteField": "删除字段", + "deleteHistory": "删除历史条目", + "deleteSectionAndField": "删除section", + "emptyRecycleBin": "清空回收站", + "entryDeletePermanent": "密码项永久删除", + "groupDeletePermanent": "组永久删除", + "groupDetails": "组细节", + "icons": "图标", + "otpDelete": "删除一次性密钥", + "otpSetup": "一次性密钥设置", + "passwordGenerator": "生成密码", + "putBack": "从回收站恢复", + "restoreEntry": "恢复密码项", + "search": "搜索", + "sectionField1": "Add field in {{sectionName}}", + "sectionField2": "Modify field in {{sectionName}}", + "unsavedChanges": "为保存的改变" + }, + "texts": { + "confirmDiscard": "你想丢弃所有修改并关闭数据库么?", + "confirmOverwrite": "你想修改你的数据库么?", + "conflictOnSaveTxt1": "文件自从上次打开有所变更,请采取以下的方式", + "conflictOnSaveTxt2": "你可以保存你的修改到数据库中,然后手动合并。(自动合并将会添加到未来的版本)", + "conflictOnSaveTxt3": "你可以保存你的修改", + "conflictOnSaveTxt4": "你可以丢弃你的更改并关闭数据库", + "databaseChangedTxt1": "从上次打开后,数据库发生变化", + "databaseChangedTxt2": "请保存以查看可用的解决选项。", + "deleteAllHistories": "删除所有历史密码项", + "deleteAttachment": "你确定要删除这个附件?", + "deleteField": "你确定要删除这个部分和它的字段?", + "deleteHistory": "历史版本将被删除", + "deleteSectionAndField": "你确定要删除section和它的相关字段?", + "emptyRecycleBin": "你确定要清空回收站?", + "entryDeletePermanent": "你确定要删除密码项?", + "groupDeletePermanent": "你确定要删除组和它的子组?", + "otpDelete": "你却要删除OTP字段", + "restoreEntry": "现有的密码项将被历史密码项替代", + "unsavedChangesTxt1": "这些修改还未保存。请在锁定数据库之前进行保存", + "unsavedChangesTxt2": "这些修改还未保存。你想保存并退出么?", + "unsavedChangesTxt3": "这些修改还未保存. 你想在关闭数据库之前保存么?" + } + }, + "entryTypeTitles": { + "bankAccount": "银行账号", + "credit/DebitCard": "银行卡", + "login": "登陆", + "wirelessRouter": "无线路由" + }, + "entryFieldNames": { + "accountHolder": "账号持有者", + "accountNumber": "账号", + "accountType": "账号类型", + "additionalUrLs": "额外的URLs", + "addressLine1": "地址 Line1", + "addressLine2": "地址 Line2", + "bankCode/RoutingNumber": "银行代码", + "baseStationNameOrSsid": "基站名称", + "brand": "品牌", + "cardholderName": "卡片持有人姓名", + "city": "城市", + "contactEmail": "联系邮箱", + "contactNumber": "联系电话", + "country": "国家", + "creditLimit": "信用卡额度", + "cvc": "卡片验证码", + "expirationMonth": "到期月份", + "expirationYear": "到期年份", + "expiryDuration": "有效期", + "issuingBank": "发行银行", + "notes": "备注", + "number": "数字", + "otp": "一次性密码", + "phoneNumber": "电话号码", + "password": "密码", + "pin": "PIN", + "state": "州", + "swift": "SWIFT代码", + "tags": "标签", + "title": "标题", + "url": "URL", + "userName": "用户名", + "zipCode": "邮编" + }, + "entrySectionNames": { + "accountDetails": "账户信息", + "additionalDetails": "额外信息", + "additionalOneTimePasswords": "额外的一次性密钥", + "attachments": "附件", + "bankAddress": "银行地址", + "billingAddress": "账单地址", + "cardDetails": "银行卡信息", + "notes": "备注", + "loginDetails": "登陆信息" + }, + "buttonLabels": { + "addEntry": "添加密码项", + "addKeyFile": "添加密钥文件", + "addPassword": "添加密码", + "apply": "应用", + "browse": "浏览", + "cancel": "取消", + "changeKeyFile": "修改密钥文件", + "changePassword": "修改密码", + "copyClose": "复制并关闭", + "close": "关闭", + "delete": "删除", + "deleteAll": "删除所有", + "discard": "丢弃", + "discardClose": "丢弃并关闭数据库", + "doNotSave": "不保存", + "done": "完成", + "edit": "编辑", + "generate": "生成", + "generateNewKeyFile": "生成新的密钥文件", + "next": "下一步", + "no": "否", + "ok": "Ok", + "overwrite": "重写", + "quit": "退出", + "quickUnlock": "快速解锁", + "removeKeyFile": "移除密钥文件", + "removePassword": "移除密码", + "restore": "恢复", + "saveAs": "另存为", + "save": "保存", + "yes": "是", + "yesOverwrite": "是,重写" + }, + "menuLabels": { + "addField": "添加字段", + "addCategory": "添加目录", + "addGroup": "添加组", + "clone": "克隆", + "createdTime": "创建时间", + "delete": "删除", + "deletePermanent": "永久删除", + "deleteType": "删除类型", + "edit": "编辑", + "editAutoType": "编辑自动类型", + "favorites": "收藏", + "history": "历史", + "info": "信息", + "modifiedTime": "修改时间", + "performAutoType": "执行自动类型", + "putBack": "放回", + "setUpTOPT": "设置TOTP", + "sortAtoZ": "排序A-Z", + "sortZtoA": "排序Z-A", + "title": "标题" + }, + "messages": { + "appSettings": { + "sessionValidVal": "有效值应在1分钟到1440分钟之间", + "clipboardValidVal": "有效值应在10秒到300秒之间" + }, + "databaseSettings": { + "databaseName": "需要一个有效的数据库名称", + "iterations": "有效值应在5到100之间", + "memory": "有效值应在1到1000之间", + "noCredentialSet": "数据库需要使用密码或密钥文件或两者来保护主密钥", + "parallelism": "有效值应在1到100之间", + "passwordConfirm": "密码和确认密码不匹配" + }, + "entryForm": { + "groupSelection": "请选择一个组", + "cloneEntryTitleName": "请输入一个有效的标题", + "titleName": "请输入一个标题" + }, + "newDbPage": { + "txt1": "你可以选择一个不改变的文件。文件的内容的哈希值将作为额外的密码。", + "txt2": "或者,OneKeePass可以生成一个具有随机密钥的密钥文件,用作额外的密钥", + "txt3": "数据库创建中", + "txt4": "数据库文件已经存在,将被新文件替换" + }, + "openDbPage": { + "txt1": "请提供一个有效的密码或密钥文件或两者", + "txt2": "数据库打开中" + }, + "passwordGenerator": { + "oneKindCharaterRequired": "你最少启用一种字符类型", + "length0": "密码的长度不能为0", + "above8": "需要一个有效的长度数字,并且它应该是8或以上" + } + }, + "snackbarMessages": { + "dbBackupCompleted": "数据库备份完成", + "dbClosed": "已关闭数据库 {{- dbFileName}}", + "entryCloned": "条目已克隆", + "entryCreated": "新条目已创建", + "entryUpdated": "条目已更新", + "dbOpened": "已打开数据库 {{- dbFileName}}" + }, + "systemMenus": { + "main": { + "Database": "数据库信息", + "Edit": "编辑", + "Entries": "条目", + "File": "文件", + "Groups": "组", + "Tools": "工具" + }, + "subMenus": { + "CloseDatabase": "关闭数据库", + "EditEntry": "编辑密码项", + "EditGroup": "编辑组", + "LockAllDatabases": "锁定所有数据库", + "LockDatabase": "锁定数据库", + "NewDatabase": "新建数据库", + "NewEntry": "新建密码项", + "NewGroup": "新建组", + "OpenDatabase": "打开数据库", + "PasswordGenerator": "生成密码", + "Quit": "退出 OneKeePass", + "SaveDatabase": "保存数据库", + "SaveDatabaseAs": "另存为", + "SaveDatabaseBackup": "保存数据库备份", + "AppSettings": "设置..." + } + } +} \ No newline at end of file diff --git a/src-tauri/src/app_preference.rs b/src-tauri/src/app_preference.rs index 4d87df3..ed26471 100644 --- a/src-tauri/src/app_preference.rs +++ b/src-tauri/src/app_preference.rs @@ -6,6 +6,7 @@ use crate::{ app_paths::app_backup_dir, constants::{standard_file_names::APP_PREFERENCE_FILE, themes::LIGHT}, password_gen_preference::PasswordGeneratorPreference, translation }; +use onekeepass_core::db_service as kp_service; use crate::app_paths::app_home_dir; #[derive(Clone, Serialize, Deserialize, Debug)] @@ -30,6 +31,7 @@ pub struct PreferenceData { pub default_entry_category_groupings: Option, pub theme: Option, pub language: Option, + pub pass_phrase_options:Option, } // Old preference used before introduction of fields clipboard_timeout,theme ,language // Leaving it here for documentation purpose only @@ -225,6 +227,7 @@ impl Preference { // Update the preference with any non null values pub fn update(&mut self, preference_data: PreferenceData) { + // TODO: Need to have a 'macro' for this let mut updated = false; if let Some(v) = preference_data.language { self.language = v; @@ -251,6 +254,11 @@ impl Preference { updated = true; } + if let Some(v) = preference_data.pass_phrase_options { + self.password_gen_preference.update_pass_phrase_options(v); + updated = true; + } + if updated { self.write_toml(); } diff --git a/src-tauri/src/password_gen_preference.rs b/src-tauri/src/password_gen_preference.rs index bc0e426..79f6dbc 100644 --- a/src-tauri/src/password_gen_preference.rs +++ b/src-tauri/src/password_gen_preference.rs @@ -1,28 +1,37 @@ use std::{ - fs, io, - path::{Path, PathBuf}, - }; - - use log::debug; - use onekeepass_core::db_service as kp_service; + fs, io, + path::{Path, PathBuf}, +}; + +use log::debug; +use onekeepass_core::db_service as kp_service; use serde::{Deserialize, Serialize}; - - use crate::app_paths; +use crate::app_paths; - #[derive(Clone, Serialize, Deserialize, Debug)] +#[derive(Clone, Serialize, Deserialize, Debug)] pub(crate) struct PasswordGeneratorPreference { - phrase_generator_options: kp_service::PassphraseGenerationOptions, + phrase_generator_options: kp_service::PassphraseGenerationOptions, } impl Default for PasswordGeneratorPreference { - fn default() -> Self { - Self { phrase_generator_options: Default::default() } + fn default() -> Self { + Self { + phrase_generator_options: Default::default(), } + } } impl PasswordGeneratorPreference { + pub(crate) fn update_pass_phrase_options( + &mut self, + phrase_generator_options: kp_service::PassphraseGenerationOptions, + ) { + self.phrase_generator_options = phrase_generator_options; + } + // Copies the words list file to app's internal dir for later use + #[allow(dead_code)] pub(crate) fn copy_wordlist_file>( picked_full_file_path: P, ) -> kp_service::Result { @@ -45,12 +54,14 @@ impl PasswordGeneratorPreference { Ok(target) } + #[allow(dead_code)] pub(crate) fn remove_word_list_file>(full_file_path: P) { let _ = fs::remove_file(full_file_path); } + #[allow(dead_code)] pub(crate) fn word_list_deleted(file_name: &str) { let p = app_paths::wordlists_dir().join(file_name); Self::remove_word_list_file(&p); } -} \ No newline at end of file +} diff --git a/src/main/onekeepass/frontend/events/common.cljs b/src/main/onekeepass/frontend/events/common.cljs index ab956d2..6de7cba 100644 --- a/src/main/onekeepass/frontend/events/common.cljs +++ b/src/main/onekeepass/frontend/events/common.cljs @@ -39,25 +39,6 @@ (let [file-name (check-error api-response)] (dispatch [kw-dispatch-name file-name]))))) -;;;;;;;;;;;;;;;;;;;;;;;; Common factory ;;;;;;;;;;;;;;;;;;;;;;;; - -;; TODO: Move to common-components -(defn on-change-factory - "A function factory - The arg 'handler-name' is a fn that is called with supplier arg 'field-name-kw' and - the event value - Returns a function that can be used in a on-change handler of a text field - " - [handler-name field-name-kw] - (fn [^js/Event e] - (handler-name field-name-kw (-> e .-target .-value)))) - -(defn on-check-factory - "Called in on-change handler of a check field" - [handler-name field-name-kw] - (fn [e] - (handler-name field-name-kw (-> e .-target .-checked)))) - ;;;;;;;;;;;;;;;;;;;;;;;; System Info and Preference ;;;;;;;;;;;;;;;;;;;; (declare set-session-timeout) diff --git a/src/main/onekeepass/frontend/events/password_generator.cljs b/src/main/onekeepass/frontend/events/password_generator.cljs index 2a656c0..c08e4d1 100644 --- a/src/main/onekeepass/frontend/events/password_generator.cljs +++ b/src/main/onekeepass/frontend/events/password_generator.cljs @@ -1,11 +1,13 @@ (ns onekeepass.frontend.events.password-generator (:require - [re-frame.core :refer [reg-event-db reg-event-fx reg-fx reg-sub dispatch subscribe]] [clojure.string :as str] - [onekeepass.frontend.translation :refer-macros [tr-m]] - [onekeepass.frontend.events.common :as cmn-events :refer [check-error]] [onekeepass.frontend.background :as bg] - [onekeepass.frontend.background-password :as bg-pwd])) + [onekeepass.frontend.background-password :as bg-pwd] + [onekeepass.frontend.events.common :as cmn-events :refer [check-error + on-error]] + [onekeepass.frontend.translation :refer-macros [tr-m]] + [re-frame.core :refer [dispatch reg-event-db reg-event-fx reg-fx reg-sub + subscribe]])) (defn generator-dialog-data-update [kw value] @@ -22,13 +24,20 @@ (defn set-active-password-generator-panel [kw-panel-id] (dispatch [:set-active-password-generator-panel kw-panel-id])) -(defn pass-phrase-options-update [kw value] +(defn pass-phrase-options-update + "Called to update pass phrase option fields that are not enum fields" + [kw value] (dispatch [:pass-phrase-options-update kw value])) +(defn pass-phrase-options-select-field-update + "Called to update pass phrase option fields that are formed from enums WordListSource and ProbabilityOption " + [field-name-kw value] + (dispatch [:pass-phrase-options-select-field-update field-name-kw value])) + (defn generator-dialog-data [] (subscribe [:generator-dialog-data])) -(defn generator-panel-selected [] +#_(defn generator-panel-selected [] (subscribe [:generator-panel-selected])) ;;;; @@ -155,12 +164,12 @@ (fn [db [_query-id]] (get-in db [:generator :dialog-data]))) -(reg-sub +#_(reg-sub :generator-password-result (fn [db [_query-id]] (get-in db [:generator :dialog-data :password-result]))) -(reg-sub +#_(reg-sub :generator-panel-selected (fn [db [_query-id]] (get-in db [:generator :dialog-data :panel-shown]))) @@ -169,29 +178,13 @@ ;;;;;;;;;;;;;;;;;;;;;;;; Pass phrase ;;;;;;;;;;;;;;;;;;;;;; (reg-event-fx :set-active-password-generator-panel - (fn [{:keys [db]} [_event-id kw-panel-id]] + (fn [{:keys [db]} [_event-id kw-panel-id]] (let [po (get-in db [:generator :dialog-data :password-options]) ppo (get-in db [:generator :dialog-data :phrase-generator-options])] {:db (assoc-in db [:generator :dialog-data :panel-shown] kw-panel-id) :fx [(if (= kw-panel-id :password) [:bg-analyzed-password po] [:bg-generate-password-phrase ppo])]}))) -(reg-fx - :bg-generate-password-phrase - (fn [pass-phrase-options] - (bg-pwd/generate-password-phrase - pass-phrase-options - (fn [api-response] - (when-let [result (check-error api-response #(dispatch [:common/message-snackbar-error-open %]))] - (dispatch [:pass-phrase-generation-complete result])))))) - -;; map generated-pass-phrase is from struct GeneratedPassPhrase -(reg-event-fx - :pass-phrase-generation-complete - (fn [{:keys [db]} [_event-id {:keys [password] :as generated-pass-phrase}]] - ;;(println "generated-pass-phrase is " generated-pass-phrase) - {:fx [[:dispatch [:password-generation-complete generated-pass-phrase] ]]})) - (reg-event-fx :pass-phrase-options-update (fn [{:keys [db]} [_event-id field-name-kw value]] @@ -201,44 +194,65 @@ {:keys [words] :as po} (get-in db [:generator :dialog-data :phrase-generator-options])] (if (empty? (str/trim (str words))) {:db db - :fx [[:dispatch [:common/message-snackbar-error-open "At least 1 word is required" #_(tr-m passwordGenerator above8)]]]} + :fx [[:dispatch [:common/message-snackbar-error-open (tr-m passwordGenerator "atLeastOneWord")]]]} {:db db :fx [[:dispatch [:common/message-snackbar-error-close]] [:bg-generate-password-phrase po]]})))) -#_(reg-event-fx - :pass-phrase-generator/start - (fn [{:keys [db]} [_event-id callback-on-copy-fn]] - (let [phrase-generator-options (cmn-events/app-preference-phrase-generator-options db) - db (-> db init-dialog-data - (assoc-in [:generator :dialog-data :callback-on-copy-fn] callback-on-copy-fn)) - po (get-in db [:generator :dialog-data :password-options])] - {:db db - :fx [[:bg-analyzed-password po]]}))) - -#_(def pass-phrase-generator-dialog-init-data - {:dialog-show false - :password-visible false - :text-copied false - :callback-on-copy-fn nil - :phrase-generator-options {} - ;;; - :password-result {:password nil - :analyzed-password nil - :is-common false - ;; value of :score is a map from enum PasswordScore - ;; note the use of #[serde(tag = "name")] in PasswordScore - :score {:name nil - :raw-value nil - :score-text nil}}}) - - -#_(defn- init-pass-phrase-dialog-data [app-db] - (let [phrase-generator-options (cmn-events/app-preference-phrase-generator-options app-db) - data (assoc pass-phrase-generator-dialog-init-data :phrase-generator-options phrase-generator-options)] - (assoc-in app-db [:generator :dialog-data] data))) +(reg-event-fx + :pass-phrase-options-select-field-update + (fn [{:keys [db]} [_event-id field-name-kw value]] + (let [db (-> db (assoc-in [:generator :dialog-data :phrase-generator-options field-name-kw :type-name] value) + (to-generator-dialog-data :text-copied false)) + ;; For now, we set probability value of 50% as content. That is half the time + db (if (or (= field-name-kw :capitalize-first) (= field-name-kw :capitalize-words)) + (if (= value "Sometimes") + (assoc-in db [:generator :dialog-data :phrase-generator-options field-name-kw :content] 0.5) + (assoc-in db [:generator :dialog-data :phrase-generator-options field-name-kw :content] nil)) + db) + + po (get-in db [:generator :dialog-data :phrase-generator-options])] + {:db db + :fx [[:bg-generate-password-phrase po]]}))) + +(reg-fx + :bg-generate-password-phrase + (fn [pass-phrase-options] + (bg-pwd/generate-password-phrase + pass-phrase-options + (fn [api-response] + (when-let [result (check-error api-response #(dispatch [:common/message-snackbar-error-open %]))] + (dispatch [:pass-phrase-generation-complete result])))))) + +;; map generated-pass-phrase-m is from struct GeneratedPassPhrase +(reg-event-fx + :pass-phrase-generation-complete + (fn [{:keys [db]} [_event-id generated-pass-phrase-m]] + ;; We check whether the user changed any pass pgrase generation option and we call + ;; the preference update accordingly + (let [pref-data (cmn-events/app-preference-phrase-generator-options db) + pp-data (get-in db [:generator :dialog-data :phrase-generator-options]) + modified (not= pref-data pp-data) #_(and (seq pref-data) (not= pref-data pp-data))] + + {:fx [[:dispatch [:password-generation-complete generated-pass-phrase-m]] + (when modified + [:bg-update-pass-gen-preference {:pass-phrase-options pp-data}])]}))) + + +;; This is similar to the app preference update call in +;; src/main/onekeepass/frontend/events/app_settings.cljs +;; Here we are using 'bg/update-preference' to update the PasswordGeneratorPreference only +(reg-fx + :bg-update-pass-gen-preference + (fn [preference-data] + (bg/update-preference preference-data + (fn [api-reponse] + (when-not (on-error api-reponse) + ;; Reloads the whole app preference + ;; This ensures the pass phrase option in preference data is the updated one + (dispatch [:common/load-app-preference])))))) (comment diff --git a/src/main/onekeepass/frontend/password_generator.cljs b/src/main/onekeepass/frontend/password_generator.cljs index 28e1c2c..6f39803 100644 --- a/src/main/onekeepass/frontend/password_generator.cljs +++ b/src/main/onekeepass/frontend/password_generator.cljs @@ -1,14 +1,17 @@ (ns onekeepass.frontend.password-generator - (:require [onekeepass.frontend.common-components :as cc] - [onekeepass.frontend.events.password-generator :as gen-events] - [onekeepass.frontend.mui-components :as m - :refer [mui-alert mui-alert-title mui-button mui-checkbox mui-dialog - mui-dialog-actions mui-dialog-content mui-dialog-title - mui-form-control-label mui-icon-button mui-icon-visibility - mui-icon-visibility-off mui-input mui-input-adornment mui-slider - mui-stack mui-text-field mui-typography mui-tabs mui-tab]] - [onekeepass.frontend.translation :refer-macros [tr-l tr-h tr-bl tr-dlg-title] :refer [lstr-l-cv]] - [reagent.core :as r])) + (:require + [onekeepass.frontend.common-components :as cc] + [onekeepass.frontend.events.password-generator :as gen-events] + [onekeepass.frontend.mui-components :as m + :refer [mui-alert mui-alert-title mui-button mui-checkbox + mui-dialog mui-dialog-actions mui-dialog-content + mui-dialog-title mui-form-control-label mui-icon-button + mui-icon-visibility mui-icon-visibility-off mui-input + mui-input-adornment mui-slider mui-stack mui-tab mui-tabs + mui-text-field mui-typography]] + [onekeepass.frontend.translation :refer-macros [tr-l tr-h tr-bl tr-dlg-title] :refer [lstr-l + lstr-l-cv]] + [reagent.core :as r])) (defn- end-icons [visibile?] [:<> @@ -35,13 +38,14 @@ :on-change (fn [_event val] ;; val is of string type and need to be coverted as keyword (gen-events/set-active-password-generator-panel (keyword val)))} - [mui-tab {:label "Password" :value :password}] - [mui-tab {:label "Password Phrase" :value :pass-phrase}]]) + [mui-tab {:label (lstr-l 'password) :value :password}] + [mui-tab {:label (lstr-l 'passwordPhrase) :value :pass-phrase}]]) ;; TODO: Move to 'common-components' and also change in 'src/main/onekeepass/frontend/entry_form/fields.cljs' ;; to use this common one -(defn simple-selection-field [{:keys [key +(defn simple-selection-field [{:keys [id + field-name value edit error-text @@ -52,12 +56,11 @@ ;; This type of simple select list can also be done using the following components ;; as given in the examples found mui.com which uses now this method ;; [mui-form-control [mui-input-label] [mui-select {} [mui-menu-item]] [mui-form-helper-text] ] - [mui-text-field {:id key + [mui-text-field {:id (if (nil? id) field-name id) :sx (merge {:margin-top cc/entry-cnt-field-margin-top} (:sx opts)) :required false - ;;:classes {:root "entry-cnt-field"} :select true - :label key #_(tr-entry-field-name-cv key) + :label field-name #_(tr-entry-field-name-cv key) :value value :on-change on-change-handler :error (not (nil? error-text)) @@ -65,31 +68,41 @@ :inputProps {:readOnly (not edit)} :variant "standard" :fullWidth true} (doall (for [y select-field-options] - ^{:key y} [m/mui-menu-item {:value y} y]))]) + (let [{:keys [value label]} (if (string? y) {:value y :label y} y)] + ^{:key y} [m/mui-menu-item {:value value} label])))]) -(def EFFLarge "EFFLarge") -(def EFFShort1 "EFFShort1") -(def EFFShort2 "EFFShort2") +;; values should match enum WordListSource +(def all-wl [{:value "EFFLarge" :label "EFF Large List"} + {:value "EFFShort1" :label "EFF Short List 1"} + {:value "EFFShort2" :label "EFF Short List 2"} + {:value "Google10000UsaEnglishNoSwearsMedium" :label "Google (U.S English,No Swears words)"} + {:value "FrenchDicewareWordlist" :label "French Word List"} + {:value "GermanDicewareWordlist" :label "German Word List"}]) -(def all-wl [EFFLarge EFFShort1 EFFShort2]) - -(def capitalize-word-choices ["Always" "Never" "Sometimes"]) - -(def capitalize-first-choices ["Always" "Never" "Sometimes"]) +;; values should match enum ProbabilityOption +(def capitalize-word-choices [{:value "Always" :label (lstr-l 'always)} + {:value "Never" :label (lstr-l 'never)} + {:value "Sometimes" :label (lstr-l 'sometimes)}]) +;; values should match enum ProbabilityOption +(def capitalize-first-choices capitalize-word-choices) (defn pass-phrase-panel [{:keys [password-visible text-copied] - {:keys [words separator capitalize-words capitalize-first]} :phrase-generator-options + {:keys [word-list-source words separator capitalize-words capitalize-first]} :phrase-generator-options {:keys [password score]} :password-result}] [mui-stack {:sx {:align-items "center"}} [mui-stack {:sx {:width "80%"}} [mui-stack {:direction "row"} - [simple-selection-field {:key "Wordlist" :value EFFLarge :edit true :on-change-handler #() :select-field-options all-wl}]] + [simple-selection-field {:field-name (lstr-l 'wordList) + :value (:type-name word-list-source) + :edit true + :on-change-handler (cc/on-change-factory gen-events/pass-phrase-options-select-field-update :word-list-source) + :select-field-options all-wl}]] [mui-stack {:direction "row" :spacing 2 :sx {:margin-top "10px"}} [mui-stack {:sx {:width "25%"}} - [mui-typography "Words" #_(tr-l "words")]] + [mui-typography (lstr-l 'words) #_(tr-l "words")]] [mui-stack {:direction "row" :sx {:width "50%"}} [mui-slider {:value words :size "small" @@ -104,22 +117,30 @@ :on-blur (fn [] (cond (< words 1) - #() #_(gen-events/pass-phrase-options-update :length 8) + (gen-events/pass-phrase-options-update :words 1) (> words 40) - #() #_(gen-events/pass-phrase-options-update :length 100))) + (gen-events/pass-phrase-options-update :words 40))) :inputProps {:min 1 :max 40 :type "number"}}]]] [mui-stack {:direction "row" :sx {:width "50%"}} - [m/text-field {:label "Separator" + [m/text-field {:label (lstr-l 'separator) :value separator :variant "standard" - :on-change (cc/on-change-factory gen-events/pass-phrase-options-update :separator)}]] + :on-change (cc/on-change-factory gen-events/pass-phrase-options-update :separator)}]] [mui-stack {:direction "row"} [mui-stack {:direction "row" :sx {:width "50%"}} - [simple-selection-field {:key "Capitalize words" :value "Always" :select-field-options capitalize-word-choices}]] + [simple-selection-field {:field-name (lstr-l "capitalizeWords") + :value (:type-name capitalize-words) + :edit true + :on-change-handler (cc/on-change-factory gen-events/pass-phrase-options-select-field-update :capitalize-words) + :select-field-options capitalize-word-choices}]] [mui-stack {:width 8}] [mui-stack {:direction "row" :sx {:width "50%"}} - [simple-selection-field {:key "Capitalize first letter" :value "Always" :select-field-options capitalize-first-choices}]]] + [simple-selection-field {:field-name (lstr-l 'capitalizeFirstLetter) + :value (:type-name capitalize-first) + :edit true + :on-change-handler (cc/on-change-factory gen-events/pass-phrase-options-select-field-update :capitalize-first) + :select-field-options capitalize-first-choices}]]] [mui-stack {:direction "row" :sx {:width "100%" :margin-top "10px"}} [mui-text-field @@ -133,9 +154,12 @@ :type (if password-visible "text" "password") :readOnly true} :variant "standard" - :fullWidth true}]]]]) + :fullWidth true}]] -;; [mui-typography "Pass phrase will come here"] + (when text-copied [mui-stack {:sx {:margin-top "5px"}} + [mui-alert {:severity "success" + :sx {"&.MuiAlert-root" {:width "100%"}}} ;; need to override the paper width 60% ;;:sx {"&.MuiAlert-root" {:width "100%"}} + [mui-alert-title (tr-l success)] (tr-h copiedToClipboard)]])]]) (defn password-panel [{:keys [password-visible text-copied] @@ -228,134 +252,25 @@ (defn password-generator-dialog [{:keys [dialog-show panel-shown] :as pass-options}] - (let [current-selection @(gen-events/generator-panel-selected)] - [mui-dialog {:open dialog-show :on-click #(.stopPropagation ^js/Event %) - ;; This will set the Paper width in all child components - ;; and is equivalent to :classes {:paper "pwd-dlg-root"} - :sx {"& .MuiPaper-root" {:width "80%"}}} - - [mui-dialog-title [tab-panel-selection panel-shown]] - [mui-dialog-content {:dividers true} - (if (= panel-shown :password) - [password-panel pass-options] - [pass-phrase-panel pass-options])] - [mui-dialog-actions - [mui-button {:on-click - (fn [] - (gen-events/generator-password-copied) - (gen-events/generator-dialog-data-update :dialog-show false))} - (tr-bl copyClose)] - [mui-button {:on-click - #(gen-events/generator-dialog-data-update :dialog-show false)} - (tr-bl close)]]])) - - - -#_(defn password-generator-dialog - [{:keys [dialog-show - password-visible - text-copied] - {:keys [length - lowercase-letters - uppercase-letters - numbers - symbols]} :password-options - {:keys [analyzed-password - score]} :password-result}] - [mui-dialog {:open dialog-show :on-click #(.stopPropagation ^js/Event %) - ;; This will set the Paper width in all child components - ;; and is equivalent to :classes {:paper "pwd-dlg-root"} - :sx {"& .MuiPaper-root" {:width "80%"}}} - - [mui-dialog-title (tr-dlg-title passwordGenerator)] - [mui-dialog-content {:dividers true} - [mui-stack {:sx {:align-items "center"}} - [mui-stack {:sx {:width "80%"}} - [mui-stack {:direction "row" :spacing 2 :sx {:margin-top "10px"}} - [mui-stack {:sx {:width "25%"}} - [mui-typography (tr-l length)]] - [mui-stack {:direction "row" :sx {:width "50%"}} - [mui-slider {:value length - :size "small" - :valueLabelDisplay "auto" - :min 8 - :max 100 - :on-change (fn [_e value] - (gen-events/password-options-update :length value))}]] - [mui-stack {:direction "row" :sx {:width "25%"}} - [mui-input {:value length - :on-change (on-change-factory gen-events/password-options-update :length) - :on-blur (fn [] - (cond - (< length 8) - (gen-events/password-options-update :length 8) - - (> length 100) - (gen-events/password-options-update :length 100))) - :inputProps {:min 8 :max 100 :type "number"}}]]] - - [mui-stack {:direction "row"} - [mui-stack {:sx {:width "50%"}} - [mui-form-control-label - {:control (r/as-element - [mui-checkbox - {:checked lowercase-letters - :on-change (on-check-factory - gen-events/password-options-update :lowercase-letters)}]) - :label (tr-l lowerCaseAZ)}]] - [mui-stack {:sx {:width "50%"}} - [mui-form-control-label - {:control (r/as-element - [mui-checkbox - {:checked uppercase-letters - :on-change (on-check-factory - gen-events/password-options-update :uppercase-letters)}]) - :label (tr-l upperCaseAZ)}]]] - - [mui-stack {:direction "row"} - [mui-stack {:sx {:width "50%"}} - [mui-form-control-label - {:control (r/as-element - [mui-checkbox - {:checked numbers - :on-change (on-check-factory - gen-events/password-options-update :numbers)}]) - :label (tr-l numbers)}]] - [mui-stack {:sx {:width "50%"}} - [mui-form-control-label - {:control (r/as-element - [mui-checkbox - {:checked symbols - :on-change (on-check-factory - gen-events/password-options-update :symbols)}]) - :label (tr-l symbols)}]]] - - [mui-stack {:direction "row" :sx {:width "100%"}} - [mui-text-field - {:label (tr-l password) - :value analyzed-password - :sx (merge {} (cc/password-helper-text-sx (:name score))) - :helper-text (-> score :name lstr-l-cv) - :InputProps {:endAdornment (r/as-element - [mui-input-adornment {:position "end"} - [end-icons analyzed-password password-visible]]) - :type (if password-visible "text" "password") - :readOnly true} - :variant "standard" - :fullWidth true}]] - - (when text-copied [mui-stack {:sx {:margin-top "5px"}} - [mui-alert {:severity "success" - :sx {"&.MuiAlert-root" {:width "100%"}}} ;; need to override the paper width 60% ;;:sx {"&.MuiAlert-root" {:width "100%"}} - [mui-alert-title (tr-l success)] (tr-h copiedToClipboard)]])]]] - [mui-dialog-actions - [mui-button {:on-click - (fn [] - (gen-events/generator-password-copied) - (gen-events/generator-dialog-data-update :dialog-show false))} - (tr-bl copyClose)] - [mui-button {:on-click - #(gen-events/generator-dialog-data-update :dialog-show false)} - (tr-bl close)]]]) + [mui-dialog {:open dialog-show :on-click #(.stopPropagation ^js/Event %) + ;; This will set the Paper width in all child components + ;; and is equivalent to :classes {:paper "pwd-dlg-root"} + :sx {"& .MuiPaper-root" {:width "80%"}}} + + [mui-dialog-title [tab-panel-selection panel-shown]] + [mui-dialog-content {:dividers true} + (if (= panel-shown :password) + [password-panel pass-options] + [pass-phrase-panel pass-options])] + [mui-dialog-actions + [mui-button {:on-click + (fn [] + (gen-events/generator-password-copied) + (gen-events/generator-dialog-data-update :dialog-show false))} + (tr-bl copyClose)] + [mui-button {:on-click + #(gen-events/generator-dialog-data-update :dialog-show false)} + (tr-bl close)]]] + #_(let [current-selection @(gen-events/generator-panel-selected)])) From 618261d0d5566f99964b3605ad760d5fefd986b8 Mon Sep 17 00:00:00 2001 From: jeyasankar Date: Thu, 16 Jan 2025 10:03:41 -0800 Subject: [PATCH 05/15] Added events to open a db with credentials --- .clj-kondo/config.edn | 21 +++-- src-tauri/src/auto_type/parsing.rs | 26 +++--- src/main/onekeepass/frontend/core.cljs | 4 +- .../onekeepass/frontend/events/common.cljs | 26 ++++-- .../frontend/events/entry_form_ex.cljs | 68 ++++++++------- .../frontend/events/open_db_form.cljs | 82 +++++++++++++++---- .../onekeepass/frontend/mui_components.cljs | 6 +- .../onekeepass/frontend/open_db_form.cljs | 15 ++-- 8 files changed, 155 insertions(+), 93 deletions(-) diff --git a/.clj-kondo/config.edn b/.clj-kondo/config.edn index fc0df17..062bbc3 100644 --- a/.clj-kondo/config.edn +++ b/.clj-kondo/config.edn @@ -93,6 +93,7 @@ FavoriteBorder FeedOutlined FlightTakeoffOutlined + Launch LoginOutlined LockOpenOutlined LockOutlined @@ -121,14 +122,14 @@ ;; Dialogs related clone-entry-options-dialog - data + data on-ok show - show-with-state + show-with-state state-m ;; Translations related - entryForm + entryForm cloneEntryTitleName discard confirmDiscard @@ -281,14 +282,12 @@ txt4 txt5]} - :unresolved-var {:exclude [onekeepass.frontend.mui-components - onekeepass.frontend.background/go - ]} - - + :unresolved-var {:exclude [onekeepass.frontend.mui-components + onekeepass.frontend.background/go]} + + ;;Following is not working ;; :unused-import {:exclude [camel-snake-kebab.core]} } - - :skip-comments true - } \ No newline at end of file + + :skip-comments true} \ No newline at end of file diff --git a/src-tauri/src/auto_type/parsing.rs b/src-tauri/src/auto_type/parsing.rs index be16571..1f44e3d 100644 --- a/src-tauri/src/auto_type/parsing.rs +++ b/src-tauri/src/auto_type/parsing.rs @@ -31,7 +31,7 @@ fn key_names() -> &'static HashSet<&'static str> { } #[derive(Debug, PartialEq, Eq)] -pub enum PlaceHolder<'a> { +enum PlaceHolder<'a> { Attribute(&'a str), KeyName(&'a str, i32), //include optional repeat field Delay(i32), @@ -49,9 +49,9 @@ fn fenced_name<'a>() -> impl FnMut(&'a str) -> IResult<&'a str, &'a str> { ) } -// Extracts the modifiers if any with the an optional single letter at the end -// parser verify ensures we have only one charater at the end -fn modifier_parser<'a>() -> impl FnMut(&'a str) -> IResult<&'a str, PlaceHolder> { +// Extracts the modifiers if any with the an optional single letter at the end. +// The parser 'verify' ensures that we have only one charater at the end +fn modifier_parser<'a>() -> impl FnMut(&'a str) -> IResult<&'a str, PlaceHolder<'a>> { map( tuple(( multispace0, @@ -64,7 +64,7 @@ fn modifier_parser<'a>() -> impl FnMut(&'a str) -> IResult<&'a str, PlaceHolder> } // Extracts the attribute name and verifies that the name is accepted one -fn standard_field_parser<'a>() -> impl FnMut(&'a str) -> IResult<&'a str, PlaceHolder> { +fn standard_field_parser<'a>() -> impl FnMut(&'a str) -> IResult<&'a str, PlaceHolder<'a>> { map( verify( map( @@ -75,7 +75,7 @@ fn standard_field_parser<'a>() -> impl FnMut(&'a str) -> IResult<&'a str, PlaceH tag("}"), multispace0, )), - // x is a tuple and map call returns the actual extracted value from third member ( indx 2) of tuple + // x is a tuple and map call returns the actual extracted value from third member ( index 2 - take_until output) of tuple |x| x.2, ), // Verifies that the map call returned value @@ -89,7 +89,7 @@ fn standard_field_parser<'a>() -> impl FnMut(&'a str) -> IResult<&'a str, PlaceH // Extracts the attribute name and verifies that the name is accepted one fn custom_field_parser<'a>( entry_fields: &'a HashMap, -) -> impl FnMut(&'a str) -> IResult<&'a str, PlaceHolder> { +) -> impl FnMut(&'a str) -> IResult<&'a str, PlaceHolder<'a>> { map( verify( map( @@ -102,7 +102,7 @@ fn custom_field_parser<'a>( tag("}"), multispace0, )), - // x is a tuple and map call returns the actual extracted value from fifth member ( indx 5) of tuple + // x is a tuple and map call returns the actual extracted value from fifth member ( index 5) of tuple |x| x.4, ), // Verifies that the map call returned key value that is found in 'entry_fields' @@ -125,7 +125,7 @@ fn to_num<'a>(default_val: i32) -> impl FnMut(&'a str) -> IResult<&'a str, i32> // Gets any key name with any optional repeat value // Repeat a key x times (e.g., {SPACE 5} inserts five spaces) -fn key_name_opt_repeat_parser<'a>() -> impl FnMut(&'a str) -> IResult<&'a str, PlaceHolder> { +fn key_name_opt_repeat_parser<'a>() -> impl FnMut(&'a str) -> IResult<&'a str, PlaceHolder<'a>> { map_parser( fenced_name(), map( @@ -156,7 +156,7 @@ fn key_name_opt_repeat_parser<'a>() -> impl FnMut(&'a str) -> IResult<&'a str, P ) } -fn delay_parser<'a>() -> impl FnMut(&'a str) -> IResult<&'a str, PlaceHolder> { +fn delay_parser<'a>() -> impl FnMut(&'a str) -> IResult<&'a str, PlaceHolder<'a>> { map_parser( fenced_name(), map( @@ -181,7 +181,7 @@ fn delay_parser<'a>() -> impl FnMut(&'a str) -> IResult<&'a str, PlaceHolder> { ) } -fn key_delay_parser<'a>() -> impl FnMut(&'a str) -> IResult<&'a str, PlaceHolder> { +fn key_delay_parser<'a>() -> impl FnMut(&'a str) -> IResult<&'a str, PlaceHolder<'a>> { map_parser( fenced_name(), map( @@ -209,7 +209,7 @@ fn key_delay_parser<'a>() -> impl FnMut(&'a str) -> IResult<&'a str, PlaceHolder } #[derive(Debug)] -pub struct PlaceHolderParser<'a> { +struct PlaceHolderParser<'a> { input: &'a str, entry_fields: &'a HashMap, } @@ -290,7 +290,7 @@ impl<'a> From> for ParsedPlaceHolderVal { pub fn parse_auto_type_sequence( // This is the string that needs to be parsed sequence: &str, - // This maps the filed names to its values. + // This maps the field names to its values. // The parsed field names will be replaced with the actual value entry_fields: &HashMap, ) -> Result, String> { diff --git a/src/main/onekeepass/frontend/core.cljs b/src/main/onekeepass/frontend/core.cljs index d0850df..6447bef 100644 --- a/src/main/onekeepass/frontend/core.cljs +++ b/src/main/onekeepass/frontend/core.cljs @@ -111,8 +111,10 @@ [db-list] [mui-box [mui-box - [mui-tabs {:value @(cmn-events/active-db-key) + [mui-tabs {;; This determines which tab's content shown + :value @(cmn-events/active-db-key) ;; Sets the active db so that group-entry-content can show selected db data + ;; 'val' is from :value prop of 'mui-tab' below :on-change (fn [_event val] (cmn-events/set-active-db-key val))} (doall (for [{:keys [db-key database-name]} db-list] diff --git a/src/main/onekeepass/frontend/events/common.cljs b/src/main/onekeepass/frontend/events/common.cljs index 6de7cba..bd5710e 100644 --- a/src/main/onekeepass/frontend/events/common.cljs +++ b/src/main/onekeepass/frontend/events/common.cljs @@ -230,9 +230,16 @@ (defn set-active-db-key "Sets the new current active db" - [db-key] - #_(dispatch [:set-active-db-key db-key]) - (dispatch [:change-active-db-complete db-key])) + [db-key] + (dispatch [:common/change-active-db-complete db-key])) + +(defn set-active-db-key-direct + "Called to set the current db to the given db-key and thus making it active + It is assumed that the 'db-key' is already available in the opened db list + Returns the updated app-db map + " + [app-db db-key] + (assoc app-db :current-db-file-name db-key)) (defn opened-db-list "Gets an atom to get all opened db summary list if app-db is not passed" @@ -449,8 +456,13 @@ (defn locked? ([] (subscribe [:common/current-db-locked])) - ([app-db] - (boolean (get-in-key-db app-db [:locked])))) + ;; Following two fns access the app-db directly + ([app-db] + ;; Current db key is used + (boolean (get-in-key-db app-db [:locked]))) + ([app-db db-key] + ;; Finds out whether the db that has the db-key is locked or not + (boolean (get-in app-db [db-key :locked])))) (defn unlock-current-db "Unlocks the database using biometric option if available" @@ -478,7 +490,7 @@ ;; Dispatched from a open-db-form event (reg-event-fx :common/kdbx-database-unlocked - (fn [{:keys [db]} [_event-id _kdbx-loaded]] + (fn [{:keys [db]} [_event-id _kdbx-loaded]] {:db (assoc-in-key-db db [:locked] false) :fx [;; TODO: Combine these reset calls with 'common/kdbx-database-loading-complete' [:dispatch [:load-all-tags]] @@ -707,7 +719,7 @@ {:opened-db-list []})) (reg-event-fx - :change-active-db-complete + :common/change-active-db-complete (fn [{:keys [db]} [_event-id db-key]] (let [db (assoc db :current-db-file-name db-key)] {:db db}))) diff --git a/src/main/onekeepass/frontend/events/entry_form_ex.cljs b/src/main/onekeepass/frontend/events/entry_form_ex.cljs index fda39cf..c3e99a1 100644 --- a/src/main/onekeepass/frontend/events/entry_form_ex.cljs +++ b/src/main/onekeepass/frontend/events/entry_form_ex.cljs @@ -1,25 +1,23 @@ (ns onekeepass.frontend.events.entry-form-ex - (:require ;; Need to be called here so that events are registered - ;; Should it be moved to core.cljs ? - [clojure.string :as str] - [onekeepass.frontend.background :as bg] ;; Need to be called here so that events are registered - [onekeepass.frontend.constants :as const :refer [PASSWORD]] - [onekeepass.frontend.events.common :as cmn-events :refer [active-db-key - assoc-in-key-db - check-error - fix-tags-selection-prefix - get-in-key-db - on-error]] - [onekeepass.frontend.events.entry-form-common :refer [add-section-field - entry-form-key - extract-form-otp-fields - is-field-exist - merge-section-key-value]] ;; Need to be called here so that events are registered - [onekeepass.frontend.events.entry-form-otp :as ef-otp-events] - [onekeepass.frontend.translation :refer [lstr-sm]] - [onekeepass.frontend.utils :as u :refer [contains-val?]] - [re-frame.core :refer [dispatch reg-event-db reg-event-fx reg-fx - reg-sub subscribe]])) + (:require + [clojure.string :as str] + [onekeepass.frontend.background :as bg] + [onekeepass.frontend.constants :as const :refer [PASSWORD]] + [onekeepass.frontend.events.common :as cmn-events :refer [active-db-key + assoc-in-key-db + check-error + fix-tags-selection-prefix + get-in-key-db + on-error]] + [onekeepass.frontend.events.entry-form-common :refer [add-section-field + entry-form-key + extract-form-otp-fields + is-field-exist + merge-section-key-value]] ;; Need to be called here so that events are registered + [onekeepass.frontend.translation :refer [lstr-sm]] + [onekeepass.frontend.utils :as u :refer [contains-val?]] + [re-frame.core :refer [dispatch reg-event-db reg-event-fx reg-fx + reg-sub subscribe]])) (def Favorites "Favorites") @@ -75,7 +73,7 @@ [_e tags] (dispatch [:entry-form-tags-selected-ex (fix-tags-selection-prefix tags)])) -(defn section-date-field-on-change-factory +#_(defn section-date-field-on-change-factory "Creates an event handler to handle an event when the date is changed in the date picker" [section key] (fn [date-val kb] @@ -196,7 +194,7 @@ ;;Delegates to a subcriber in group tree event (subscribe [:group-tree-content/groups-listing])) -(defn is-entry-parent-group-deleted +(defn is-entry-parent-group-deleted [group-uuid] (subscribe [:group-tree-content/group-in-recycle-bin group-uuid])) @@ -448,18 +446,18 @@ #_(reg-event-db - :cancel-entry-edit-ex - (fn [db [_event-id]] - (let [undo-data (get-in-key-db db [entry-form-key :undo-data]) - data (get-in-key-db db [entry-form-key :data])] - (if (and (seq undo-data) (not= undo-data data)) - (-> db (assoc-in-key-db [entry-form-key :data] undo-data) - (assoc-in-key-db [entry-form-key :undo-data] {}) - (assoc-in-key-db [entry-form-key :edit] false) - (assoc-in-key-db [entry-form-key :error-fields] {})) - (-> db (assoc-in-key-db [entry-form-key :edit] false) - (assoc-in-key-db [entry-form-key :undo-data] {}) - (assoc-in-key-db [entry-form-key :error-fields] {})))))) + :cancel-entry-edit-ex + (fn [db [_event-id]] + (let [undo-data (get-in-key-db db [entry-form-key :undo-data]) + data (get-in-key-db db [entry-form-key :data])] + (if (and (seq undo-data) (not= undo-data data)) + (-> db (assoc-in-key-db [entry-form-key :data] undo-data) + (assoc-in-key-db [entry-form-key :undo-data] {}) + (assoc-in-key-db [entry-form-key :edit] false) + (assoc-in-key-db [entry-form-key :error-fields] {})) + (-> db (assoc-in-key-db [entry-form-key :edit] false) + (assoc-in-key-db [entry-form-key :undo-data] {}) + (assoc-in-key-db [entry-form-key :error-fields] {})))))) (defn- update-entry [db dispatch-fn] (let [form-data (get-in-key-db db [entry-form-key :data])] diff --git a/src/main/onekeepass/frontend/events/open_db_form.cljs b/src/main/onekeepass/frontend/events/open_db_form.cljs index 9312018..0c7e6a0 100644 --- a/src/main/onekeepass/frontend/events/open_db_form.cljs +++ b/src/main/onekeepass/frontend/events/open_db_form.cljs @@ -39,7 +39,11 @@ (dispatch [:open-db-error "Database is already opened"]) (dispatch [:open-db-login-credential-entered file-name pwd key-file-name]))) -(defn unlock-ok-on-click [pwd key-file-name] +(defn unlock-ok-on-click + "Called when user enters the credential instead of using TouchID in mac. + In Unix and Windows, user needs to enter credentials even for unlocking + " + [pwd key-file-name] (dispatch [:open-db-login-credential-entered nil pwd key-file-name])) (defn password-visible-change [^boolean t] @@ -139,6 +143,8 @@ (fn [db [_event-id]] (init-open-db-vals db))) +(declare on-file-loading) + (reg-event-fx :open-db-login-credential-entered (fn [{:keys [db]} [_event-id file-name pwd key-file-name]] @@ -147,8 +153,8 @@ (assoc-in [:open-db :error-fields] {}) (assoc-in [:open-db :status] :in-progress)) :fx [(if unlock-request - [:unlock-kdbx-file [(active-db-key db) pwd key-file-name]] - [:load-kdbx-file [file-name pwd key-file-name]])]}))) + [ :bg-unlock-kdbx-file [(active-db-key db) pwd key-file-name]] + [ :bg-load-kdbx-file [file-name pwd key-file-name on-file-loading]])]}))) (reg-event-db :open-db-error @@ -170,26 +176,27 @@ ;;IMPORTANT reg-fx handler fn takes single argument. So we need to use vec [file-name pwd] (reg-fx - :load-kdbx-file - (fn [[file-name pwd key-file-name]] + :bg-load-kdbx-file + (fn [[file-name pwd key-file-name on-file-loading]] (bg/load-kdbx file-name pwd key-file-name on-file-loading))) -;;common/kdbx-database-unlocked (reg-event-fx :unlock-db-file-loading-done (fn [{:keys [db]} [_event-id kdbx-loaded]] {:db (-> db init-open-db-vals) ;; will hide dialog :fx [[:dispatch [:common/kdbx-database-unlocked kdbx-loaded]]]})) +#_(defn- unlock-response-handler [api-response] + (when-let [kdbx-loaded (check-error + api-response + #(dispatch [:open-db-error %]))] + (dispatch [:unlock-db-file-loading-done kdbx-loaded]))) + (reg-fx - :unlock-kdbx-file - (fn [[db-key pwd key-file-name]] - (bg/unlock-kdbx db-key pwd key-file-name - (fn [api-response] - (when-let [kdbx-loaded (check-error - api-response - #(dispatch [:open-db-error %]))] - (dispatch [:unlock-db-file-loading-done kdbx-loaded])))))) + :bg-unlock-kdbx-file + (fn [[db-key pwd key-file-name dispatch-fn]] + (println "bg-unlock-kdbx-file is called") + (bg/unlock-kdbx db-key pwd key-file-name dispatch-fn))) (reg-event-fx :open-db-form/authenticate-with-biometric @@ -234,7 +241,7 @@ (reg-event-fx :open-db-biometric-login-fail - (fn [{:keys [_db]} [_event-id]] + (fn [{:keys [_db]} [_event-id]] {:fx [[:dispatch [:common/message-snackbar-error-open "Biometric authentication is not successful"]] [:dispatch [:open-db-form/dialog-show-on-current-db-unlock-request]]]})) @@ -244,8 +251,51 @@ (-> db :open-db))) +;;;;;;;;;;;;;;;;;;;; auto db open ;;;;;;;;;;;;;;;;;;; + + +(defn open-db-with-auto-open-credentials [db-file-full-path pwd key-file-name] + (dispatch [:open-db-with-auto-open-credentials db-file-full-path pwd key-file-name])) + +(defn- handle-auto-open-response [api-response] + (when-let [kdbx-loaded (check-error api-response)] + (dispatch [:open-db-file-loading-done kdbx-loaded]))) + +(defn- handle-auto-open-unlock-response [api-response] + (when-let [kdbx-loaded (check-error + api-response + #(dispatch [:open-db-error %]))] + (dispatch [:auto-open-unlock-db-file-loading-done kdbx-loaded]))) + +(reg-event-fx + :open-db-with-auto-open-credentials + (fn [{:keys [db]} [_event-id db-file-full-path pwd key-file-name]] + (let [db-list (cmn-events/opened-db-list db) + already_opened (cmn-events/is-in-opend-db-list db-file-full-path db-list) + db-locked (cmn-events/locked? db db-file-full-path)] + #_(println " opened locked " opened locked) + (cond + db-locked + {:fx [[:bg-unlock-kdbx-file [db-file-full-path pwd key-file-name handle-auto-open-unlock-response]]]} + + already_opened + {:fx [[:dispatch [:common/change-active-db-complete db-file-full-path]]]} + + :else + {:fx [[:bg-load-kdbx-file [db-file-full-path pwd key-file-name handle-auto-open-response]]]})))) + +(reg-event-fx + :auto-open-unlock-db-file-loading-done + (fn [{:keys [db]} [_event-id {:keys [db-key] :as kdbx-loaded}]] + ;; Need to make this db-key as current active db by + ;; making this direct call. This ensures that this db-key as active db-key as expected + ;; by the event handler in ':common/kdbx-database-unlocked' where the lcoked status + ;; set to false + {:db (cmn-events/set-active-db-key-direct db db-key) + :fx [[:dispatch [:common/kdbx-database-unlocked kdbx-loaded]]]})) + (comment (keys @re-frame.db/app-db) - +;; /Users/jeyasankar/Documents/OneKeePass/Test14.kdbx (def db-key (:current-db-file-name @re-frame.db/app-db)) (-> @re-frame.db/app-db (get db-key) keys)) diff --git a/src/main/onekeepass/frontend/mui_components.cljs b/src/main/onekeepass/frontend/mui_components.cljs index 909d8f8..1a4eb8a 100644 --- a/src/main/onekeepass/frontend/mui_components.cljs +++ b/src/main/onekeepass/frontend/mui_components.cljs @@ -174,8 +174,9 @@ ;; Default primary #1976d2, secondary #9c27b0 (https://mui.com/material-ui/customization/palette/) -;; https://mui.com/customization/default-theme/ -;; Here we can all props of the theme object are shown for MUI's organization branding theme +;; https://mui.com/customization/default-theme/ +;; https://v5.mui.com/material-ui/customization/default-theme/ ( The new url for v5 as the other one is meant for the latest mui) +;; Here we can see all the props of the theme object that are shown for MUI's organization branding theme ;; From this link: ;; If you want to learn more about how the theme is assembled, ;; take a look at material-ui/style/createTheme.js, and the related imports which createTheme uses. @@ -450,6 +451,7 @@ FavoriteBorder FeedOutlined FlightTakeoffOutlined + Launch LoginOutlined LockOpenOutlined LockOutlined diff --git a/src/main/onekeepass/frontend/open_db_form.cljs b/src/main/onekeepass/frontend/open_db_form.cljs index 9f2a020..b4e3970 100644 --- a/src/main/onekeepass/frontend/open_db_form.cljs +++ b/src/main/onekeepass/frontend/open_db_form.cljs @@ -53,8 +53,8 @@ {:edge "end" :sx {:mr "-8px"} :onClick od-events/open-file-explorer-on-click} [mui-icon-folder-outlined]]]))}}] - - [mui-stack {:sx { :margin-bottom "20px"} }] + + [mui-stack {:sx {:margin-bottom "20px"}}] [m/text-field {:label (tr-l password) :value password @@ -95,10 +95,9 @@ :onClick od-events/open-key-file-explorer-on-click} [mui-icon-folder-outlined]]])} :type (if key-file-visibility-on "text" "password")}] - - [mui-stack {:sx {:margin-top "10px" :margin-bottom "5px"}} - [mui-typography {:variant "caption"} (tr-m openDbPage txt1)]] - ] + + [mui-stack {:sx {:margin-top "10px" :margin-bottom "5px"}} + [mui-typography {:variant "caption"} (tr-m openDbPage txt1)]]] [mui-stack (tr-m openDbPage txt2)]) (cond (= status :in-progress) @@ -118,12 +117,12 @@ [mui-dialog-actions [mui-button {:color "secondary" :disabled in-progress? - :on-click od-events/cancel-on-click} + :on-click od-events/cancel-on-click} (tr-bl cancel)] [mui-button {:color "secondary" :disabled in-progress? :on-click - ok-action} + ok-action} (tr-bl ok)]]])) (defn open-db-dialog-main [] From 8d819aaa1964a908704f1265f83de8a8c9aaaeb0 Mon Sep 17 00:00:00 2001 From: jeyasankar Date: Thu, 23 Jan 2025 17:12:59 -0800 Subject: [PATCH 06/15] Auto database open events added; UI changes done to show kdbx url and other labels; backend parsing of path done --- src-tauri/Cargo.lock | 13 +- src-tauri/Cargo.toml | 1 + src-tauri/src/auto_open.rs | 384 ++++++++++++++++++ src-tauri/src/commands.rs | 8 + src-tauri/src/main.rs | 2 + src/main/onekeepass/frontend/background.cljs | 40 +- .../frontend/background_common.cljs | 42 +- src/main/onekeepass/frontend/constants.cljs | 18 +- .../frontend/entry_form/fields.cljs | 116 +++--- .../onekeepass/frontend/entry_form_ex.cljs | 85 ++-- .../frontend/events/common_supports.cljs | 2 + .../frontend/events/entry_form_auto_open.cljs | 115 ++++++ .../frontend/events/entry_form_common.cljs | 83 +++- .../frontend/events/entry_form_ex.cljs | 360 ++++++++-------- .../frontend/events/entry_form_otp.cljs | 5 +- .../frontend/events/open_db_form.cljs | 32 +- .../frontend/password_generator.cljs | 31 +- 17 files changed, 1034 insertions(+), 303 deletions(-) create mode 100644 src-tauri/src/auto_open.rs create mode 100644 src/main/onekeepass/frontend/events/entry_form_auto_open.cljs diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 0393870..af2325b 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -1681,6 +1681,16 @@ dependencies = [ "windows-targets 0.48.5", ] +[[package]] +name = "gethostname" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc3655aa6818d65bc620d6911f05aa7b6aeb596291e1e9f79e52df85583d1e30" +dependencies = [ + "rustix", + "windows-targets 0.52.6", +] + [[package]] name = "getrandom" version = "0.1.16" @@ -3121,6 +3131,7 @@ version = "0.0.0" dependencies = [ "cfg-if", "chrono", + "gethostname 0.5.0", "hex", "log", "log4rs", @@ -6610,7 +6621,7 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d91ffca73ee7f68ce055750bf9f6eca0780b8c85eff9bc046a3b0da41755e12" dependencies = [ - "gethostname", + "gethostname 0.4.3", "rustix", "x11rb-protocol", ] diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index b483b2e..c8bfefc 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -27,6 +27,7 @@ cfg-if = "1.0" nom = "7.1.3" os_info = "3" sys-locale = "0.3.1" +gethostname = "0.5.0" #tokio = { version = "1", features = [ "rt", "rt-multi-thread", "sync", "fs", "io-util" ] } tokio = { version = "1", features = [ "time" ] } diff --git a/src-tauri/src/auto_open.rs b/src-tauri/src/auto_open.rs new file mode 100644 index 0000000..c3d6cca --- /dev/null +++ b/src-tauri/src/auto_open.rs @@ -0,0 +1,384 @@ +use nom::bytes::complete::tag; +use nom::combinator::rest; +use nom::sequence::preceded; +use nom::{branch::alt, IResult}; +use onekeepass_core::error::{self, Error, Result}; +use serde::{Deserialize, Serialize}; +use std::path::Path; + +#[derive(Default, Debug, Deserialize)] +pub(crate) struct AutoOpenProperties { + source_db_key: String, + url_field_value: Option, + key_file_path: Option, + device_if_val: Option, +} + +#[derive(Default, Debug, Serialize)] +pub(crate) struct AutoOpenPropertiesResolved { + url_field_value: Option, + key_file_path: Option, + can_open: bool, +} + +impl AutoOpenProperties { + pub(crate) fn resolve(&self) -> Result { + let mut out = AutoOpenPropertiesResolved::default(); + + self.apply_if_device_condition(&mut out); + // Early return if this device is excluded from auto open launch + if !out.can_open { + return Ok(out); + } + + let db_dir_path = Path::new(&self.source_db_key); + + // Ensure that the db file (the db that has the auto open entry) is correct + // Will this fail any time? + if !db_dir_path.exists() { + let er = format!( + "Invalid db_key {}. The db file is not found", + &self.source_db_key + ); + return Err(Error::UnexpectedError(er)); + } + + // We should be able to find the parent dir from the auto open master db's path + let Some(parent_dir_path) = db_dir_path.parent() else { + return Err(Error::UnexpectedError("Parent dir is not found".into())); + }; + + // The child database path is parsed only if it is not an empty string + if let Some(ref db_v) = self.url_field_value.as_ref().map(|v| v.trim().to_string()) { + if !db_v.is_empty() { + out.url_field_value = Some(resolved_path(parent_dir_path, db_v)?); + } + } + + // The child database key file path is parsed only if it is not an empty string + if let Some(ref kf_v) = self.key_file_path.as_ref().map(|v| v.trim().to_string()) { + if !kf_v.is_empty() { + out.key_file_path = Some(resolved_path(parent_dir_path, kf_v)?); + } + } + + Ok(out) + } + + fn apply_if_device_condition(&self, out: &mut AutoOpenPropertiesResolved) { + if let Some(val) = &self.device_if_val { + let computer = gethostname::gethostname() + .to_string_lossy() + .to_string() + .to_lowercase(); + + let devices: Vec = val.split(",").map(|s| s.trim().to_lowercase()).collect(); + + let mut exclude = false; + + for device_id in &devices { + if device_id.starts_with("!") { + let exclude_matched = device_id + .strip_prefix("!") + .is_some_and(|s| s.trim() == &computer); + + if exclude_matched { + // The device is explicitly excluded and opening is skipped + exclude = true; + break; + } + } else { + if device_id == &computer { + // The device is explicitly listed and we can open the db + exclude = false; + break; + } + } + } + // The database can be opened when the final 'not exclude' is true + out.can_open = !exclude; + } else { + // User has not set any devices in the field 'IfDevice' + out.can_open = true; + } + } +} + +fn resolved_path(parent_dir_path: &Path, in_path: &String) -> Result { + let (remaining, parsed) = parse_field_value(in_path) + .map_err(|e| error::Error::UnexpectedError(format!("Parsing failed with error {}", e)))?; + + if !remaining.is_empty() { + return Err(Error::UnexpectedError("Url parsing is not complete".into())); + } + + let mut p = parent_dir_path.join(&parsed.full_path_part); + + // If the canonicalize path is not found, then this will return an error + p = p + .canonicalize() + .map_err(|e| Error::UnexpectedError(format!("Error: Path {:?} : {}", &p,e)))?; + + Ok(p.to_string_lossy().to_string()) +} + +#[derive(Debug)] +struct ParsedVal<'a> { + full_path_part: &'a str, +} + +fn parse_field_value(field_value: &str) -> IResult<&str, ParsedVal<'_>> { + let r = alt(( + preceded(tag("kdbx://{DB_DIR}/"), rest), + preceded(tag("kdbx://"), rest), + rest, + ))(field_value)?; + + Ok(( + r.0, + ParsedVal { + full_path_part: r.1, + }, + )) +} + +#[cfg(test)] +mod tests { + + use super::AutoOpenProperties; + + #[test] + fn verify_path_resolve() { + let source_db_key = "/Users/jeyasankar/Documents/OneKeePass/TestAutoOpenXC.kdbx"; + let k_url = "./f1//mytestkey2.keyx"; + let db_url = "kdbx://{DB_DIR}/f1/PasswordsUsesKeyFile2.kdbx"; + + let my_computer = gethostname::gethostname().to_string_lossy().to_string(); + // my_computer is excluded + let devices = format!( + "Computer-one, Computer-Two, ! Computer-Six, !Computer-nine, !{}", + &my_computer + ); + + let mut input = AutoOpenProperties { + source_db_key: source_db_key.to_string(), + url_field_value: Some(db_url.into()), + key_file_path: Some(k_url.into()), + device_if_val: Some(devices), + }; + + let resolved = input.resolve().unwrap(); + + println!("resolved is {:?}", resolved); + + assert_eq!(resolved.can_open, false, "Expected false"); + assert_eq!(resolved.url_field_value, None); + assert_eq!(resolved.key_file_path, None); + + ////// + + // my_computer is included + let devices = format!( + "Computer-one, Computer-Two, ! Computer-Six, !Computer-nine, {}", + &my_computer + ); + + input.device_if_val = Some(devices); + + let resolved = input.resolve().unwrap(); + + assert_eq!(resolved.can_open, true, "Expected true"); + assert_eq!( + resolved.url_field_value, + Some("/Users/jeyasankar/Documents/OneKeePass/f1/PasswordsUsesKeyFile2.kdbx".into()) + ); + } + + #[test] + fn verify2() { + let cv = "Jeyasankars-MacBook-Pro16-M1.local".to_lowercase(); + let s = "Computer-one, Computer-Two, ! Computer-Six, !Computer-nine,!Jeyasankars-MacBook-Pro16-M1.local"; + let v: Vec = s.split(",").map(|s| s.trim().to_lowercase()).collect(); + println!("v is {:?}", &v); + + let mut exclude = false; + for c in &v { + if c.starts_with("!") { + let v1 = c.strip_prefix("!"); + let v2 = c.strip_prefix("!").is_some_and(|s| s.trim() == &cv); + println!("no ! {:?},{}", &v1, v2); + if v2 { + exclude = true; + break; + } + } else { + if c == &cv { + exclude = false; + break; + } + } + } + + println!("Exclude is {}", &exclude); + } + + #[test] + fn verify1() { + //println!("Host name is {:?}", hostname::get()); + + //println!("Host name 2 is {:?}", gethostname::gethostname().to_string_lossy().to_string()); + + println!( + "Result {:?} ", + super::parse_field_value("kdbx://{DB_DIR}/../Test14.kdbx") + ); + + println!("Result {:?} ", super::parse_field_value("./Test14.kdbx")); + + println!( + "Result {:?} ", + super::parse_field_value("kdbx://../Test14.kdbx") + ); + + // let b = "/Users/jeyasankar/Documents/OneKeePass"; + // let mut p = PathBuf::from(&b); + // p.push("/f1/PasswordsUsesKeyFile2.kdbx"); + // //let s = p.push("f1/PasswordsUsesKeyFile2.kdbx"); + + // println!("s is {:?}", &p); + } +} + +/* + +fn parse_field_value(field_value: &str) -> IResult<&str, &str> { + let r = alt(( + preceded(tag("kdbx://{DB_DIR}/"), rest), + preceded(tag("kdbx://"), rest), + rest, + ))(field_value)?; + + Ok(r) +} + +pub(crate) fn resolve_auto_open_paths( + auto_open_path_input: &AutoOpenPathInput, +) -> Result { + println!("Incoming data {:?}", auto_open_path_input); + + let mut out = AutoOpenPathResolved::default(); + + let db_dir_path = Path::new(&auto_open_path_input.source_db_key); + + if !db_dir_path.exists() { + let er = format!("Invalid db_key {}", &auto_open_path_input.source_db_key); + return Err(Error::UnexpectedError(er)); + } + + let Some(parent_dir_path) = db_dir_path.parent() else { + return Err(Error::UnexpectedError("Parent dir is not found".into())); + }; + + if let Some(db_v) = auto_open_path_input.url_field_value.as_ref() { + out.url_field_value = Some(resolved_path(parent_dir_path, db_v)?); + } + + if let Some(kf_v) = auto_open_path_input.key_file_path.as_ref() { + out.key_file_path = Some(resolved_path(parent_dir_path, kf_v)?); + } + + Ok(out) +} + +const PREFIX1: &str = "kdbx://{DB_DIR}"; + +const PREFIX2: &str = "./"; + +fn resolve_auto_open_url(auto_open_source_db_key: &str, url_field_value: &str) -> Result { + let db_dir_path = Path::new(auto_open_source_db_key); + + if !db_dir_path.exists() { + let er = format!("Invalid db_key {}", &auto_open_source_db_key); + return Err(Error::UnexpectedError(er)); + } + + if let Some(parent_path) = db_dir_path.parent() { + let v = if url_field_value.starts_with(PREFIX1) { + url_field_value + .split_once(PREFIX1) + .map(|v| parent_path.join(v.1)) + } else { + Some(parent_path.join(url_field_value)) + }; + + return v + .map(|p| p.to_string_lossy().to_string()) + .ok_or(Error::UnexpectedError("Conversion error".into())); + } else { + return Err(Error::UnexpectedError(format!( + "Could not find parent dir from {:?}", + &db_dir_path + ))); + } +} + +pub(crate) fn resolve_auto_open_url( + auto_open_source_db_key: &str, + url_field_value: &str, +) -> Result { + let db_dir_path = Path::new(auto_open_source_db_key); + + if !db_dir_path.exists() { + let er = format!("Invalid db_key {}", &auto_open_source_db_key); + return Err(Error::UnexpectedError(er)); + } + + if !url_field_value.starts_with(PREFIX1) || !url_field_value.starts_with(PREFIX2) { + return Err(Error::UnexpectedError( + "Invalid url. Should start with kdbx:// or ./".into(), + )); + } + + if let Some(parent_path) = db_dir_path.parent() { + let v = if url_field_value.starts_with(PREFIX1) { + url_field_value + .split_once(PREFIX1) + .map(|v| parent_path.join(v.1)) + } else { + Some(parent_path.join(url_field_value)) + }; + + return v + .map(|p| p.to_string_lossy().to_string()) + .ok_or(Error::UnexpectedError("Conversion error".into())); + } else { + return Err(Error::UnexpectedError(format!( + "Could not find parent dir from {:?}", + &db_dir_path + ))); + } +} + + +pub(crate) fn resolve_auto_open_paths( + auto_open_path_input: &AutoOpenPathInput, +) -> Result { + let url_field_value = auto_open_path_input + .url_field_value + .as_ref() + .map(|p| resolve_auto_open_url(&auto_open_path_input.source_db_key, p).ok()) + .flatten(); + + let key_file_path = auto_open_path_input + .key_file_path + .as_ref() + .map(|p| resolve_auto_open_url(&auto_open_path_input.source_db_key, p).ok()) + .flatten(); + + Ok(AutoOpenPathResolved { + url_field_value, + key_file_path, + }) +} + +*/ diff --git a/src-tauri/src/commands.rs b/src-tauri/src/commands.rs index 6c6b426..69a7d5b 100644 --- a/src-tauri/src/commands.rs +++ b/src-tauri/src/commands.rs @@ -13,6 +13,7 @@ use std::path::Path; use uuid::Uuid; use crate::app_state::SystemInfoWithPreference; +use crate::auto_open::{AutoOpenProperties, AutoOpenPropertiesResolved}; use crate::menu::{self, MenuActionRequest, MenuTitleChangeRequest}; use crate::{app_paths, translation}; use crate::{app_preference, app_state}; @@ -345,6 +346,13 @@ pub(crate) async fn form_otp_url(otp_settings: kp_service::OtpSettings) -> Resul Ok(kp_service::form_otp_url(&otp_settings)?) } +#[command] +pub(crate) async fn resolve_auto_open_properties( + auto_open_properties: AutoOpenProperties, +) -> Result { + Ok(auto_open_properties.resolve()?) +} + #[command] pub(crate) async fn history_entry_by_index( db_key: &str, diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index c4634ca..a1b0797 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -3,6 +3,7 @@ windows_subsystem = "windows" )] +mod auto_open; mod app_paths; mod app_preference; mod app_state; @@ -142,6 +143,7 @@ fn main() { commands::reload_kdbx, commands::remove_entry_permanently, commands::remove_group_permanently, + commands::resolve_auto_open_properties, commands::save_all_modified_dbs, commands::save_as_kdbx, commands::save_attachment_as_temp_file, diff --git a/src/main/onekeepass/frontend/background.cljs b/src/main/onekeepass/frontend/background.cljs index d85304c..28dbcf8 100644 --- a/src/main/onekeepass/frontend/background.cljs +++ b/src/main/onekeepass/frontend/background.cljs @@ -7,15 +7,15 @@ [camel-snake-kebab.extras :as cske] [camel-snake-kebab.core :as csk] [onekeepass.frontend.utils :refer [contains-val?]] - - [onekeepass.frontend.background-common :as bg-cmn] + + [onekeepass.frontend.background-common :as bg-cmn :refer [to-snake-case]] [onekeepass.frontend.background-password :as bg-pwd] ;; All tauri side corresponding endpoint command apis can be found in ;; https://github.com/tauri-apps/tauri/tree/tauri-v1.8.1/core/tauri/src/endpoints ;; The api implementation is in ;; https://github.com/tauri-apps/tauri/tree/tauri-v1.8.1/core/tauri/src/api - + ["@tauri-apps/api/dialog" :refer (open,save)] #_["@tauri-apps/api/tauri" :refer (invoke)] ["@tauri-apps/api/clipboard" :refer [writeText readText]] @@ -101,20 +101,33 @@ ;;TODO Add returning error to dispatch-fn (catch js/Error err (js/console.log (ex-cause err)))))) -(defn open-file - "Opens a file passed as 'file-name' from the local file system with the system's default app - The arg 'file-name' expected to be the complete path. - Any error in opening is passed as {:error msg} to the 'dispatch-fn' +;; https://v1.tauri.app/v1/api/js/shell#open +(defn- tauri-shell-open + "Uses tauri shell open api to open a website or a file using + the system's default app " - [file-name dispatch-fn] + [path dispatch-fn] (go (try - (let [f (js api-args) dispatch-fn :convert-request false))) +;;;;;;;;;;;;;;; Auto open ;;;;;;;;;;;;;; + +(defn resolve-auto-open-properties [auto-open-properties dispatch-fn] + (invoke-api "resolve_auto_open_properties" {:autoOpenProperties auto-open-properties} dispatch-fn)) + ;;;;;;;;;;;;;;;; OTP related ;;;;;;;;;;;; ;; deprecate @@ -635,6 +653,10 @@ (comment + (def auto-open-properties {:source-db-key "/Users/jeyasankar/Documents/OneKeePass/TestAutoOpenXC.kdbx" + :url-field-value "kdbx://{DB_DIR}/f1/PasswordsUsesKeyFile2.kdbx" + :key-file-path "./f1//mytestkey2.keyx" + :device_if_val nil}) (-> @re-frame.db/app-db keys) (def db-key (:current-db-file-name @re-frame.db/app-db)) (-> @re-frame.db/app-db (get db-key) keys) diff --git a/src/main/onekeepass/frontend/background_common.cljs b/src/main/onekeepass/frontend/background_common.cljs index 3f050a6..c9b3e25 100644 --- a/src/main/onekeepass/frontend/background_common.cljs +++ b/src/main/onekeepass/frontend/background_common.cljs @@ -5,15 +5,37 @@ [cljs.core.async.interop :refer-macros [> cljs-map (cske/transform-keys csk/->snake_case))) + +;; Tauri expects all API arguments names passed in JS api to be in camelCase which +;; are in turn deserialized as snake_case to match rust argument names used in tauri commands. + +(defn as-tauri-args + " + The arg 'api-args' is a map and its keys are converted to be in 'camelCase' as expected by tauri. + These keys of 'api-args' are then converted to command fns args 'snake_case' by tauri deserilaization. + However if we pass any map as value in the tauri command fn arg, then we need to make sure keys of that map are in 'snake_case' + + Returns a json object as expected by tauri's 'invoke' command + " + [api-args] + (clj->js + (reduce (fn [acc [k v]] + (assoc + ;; arg map keys are in camelCase + acc (csk/->camelCaseString k) + (if (map? v) + ;; keys of value map should be in snake_case + (to-snake-case v) v))) {} api-args))) (defn invoke-api "Invokes the backend command API calls using the tauri's 'invoke' command. @@ -38,7 +60,7 @@ ;; that can deserialized to Rust names and types as expected by the 'command' api ;; When convert-request is true, the api args are converted to 'camelCaseString' as expected by tauri command fns ;; so that args can be deserialized to tauri types - ;; When convert-request is true and api-args is a js object, (cske/transform-keys csk/->camelCaseString) + ;; When convert-request is false and api-args is a js object, (cske/transform-keys csk/->camelCaseString) ;; does not make any changes as expected to be in a proper deserilaizable format args (if convert-request ;; changes all keys to camelCase (e.g db-key -> dbKey) @@ -48,7 +70,14 @@ ;; Note ;; Only the api argument names are expected to be in camelCase. The keys of value passed are not changed to cameCase ;; and they deserialized by the the corresponding struct serde definition. As result, mostly convert-request = false - (->> api-args (cske/transform-keys csk/->camelCaseString) clj->js) + + ;; (->> api-args (cske/transform-keys csk/->camelCaseString) clj->js) + + ;; TODO: + ;; Review all background fns where we are using :convert-request false and + ;; see whether that is required any more or not as using as-tauri-args in most of the cases + (as-tauri-args api-args) + api-args) r ( (when protected (if visibile? @@ -41,6 +41,12 @@ :edge "end" :on-click #(form-events/entry-form-field-visibility-toggle key)} [mui-icon-visibility-off]])) + ;; Open with the url + (when (= key URL) + [mui-icon-button {:sx {:margin-right "-8px"} + :edge "end" + :on-click #(form-events/entry-form-open-url value)} + [m/mui-icon-launch]]) ;; Password generator (when (and edit protected (= key PASSWORD)) [mui-icon-button {:sx {:margin-right "-8px"} @@ -76,13 +82,17 @@ (doall (for [y select-field-options] ^{:key y} [mui-menu-item {:value y} y]))]) +;; Added field-name and read-value +;; as additional fields to get the label and value +;; Initially tried with auto open field. (defn text-field [{:keys [key + field-name value + read-value protected visible edit - on-change-handler - required + on-change-handler disabled password-score placeholder @@ -94,56 +104,70 @@ edit false no-end-icons false protected false - disabled false - on-change-handler #(println (str "No on change handler yet registered for " key)) - required false}}] + disabled false + on-change-handler #(println (str "No on change handler yet registered for the key"))}}] ;;:margin-top "16px" here is equivalent to the one used by "entry-cnt-field" - [m/text-field {:sx (merge {:margin-top "16px"} (cc/password-helper-text-sx (:name password-score))) - :fullWidth true - :label (if standard-field (tr-entry-field-name-cv key) key) - :variant "standard" - ;;:classes {:root "entry-cnt-field"} - :value value - :placeholder placeholder - :error (not (nil? error-text)) - :helperText (cond - (and (nil? error-text) (not (nil? password-score))) - (-> password-score :name lstr-l-cv) - #_(:score-text password-score) + (let [label (cond + (not (nil? field-name)) + ;; It is assumed translation is done already + field-name - (nil? error-text) - helper-text + standard-field + (tr-entry-field-name-cv key) - :else - error-text) - :onChange on-change-handler - ;;:required required - :required false - :disabled disabled - :InputLabelProps {} - :InputProps {:id key - :sx (theme-text-field-sx edit @custom-theme-atom) - :endAdornment (if no-end-icons nil - (r/as-element - [mui-input-adornment {:position "end"} - [end-icons key value protected visible edit] - #_(seq icons)])) - :type (if (or (not protected) visible) "text" "password")} - ;;attributes for 'input' tag can be added here - ;;It seems adding these 'InputProps' also works - ;;We need to use 'readOnly' and not 'readonly' - :inputProps {:readOnly (not edit) - ;;:sx (if edit sx2 sx1) - ;;:readonly "readonly" - }}]) + :else + ;; It is assumed translation is done already + key) + val (cond + edit + value + + (and (not edit) (not (nil? read-value))) + read-value + + :else + value)] + [m/text-field {:sx (merge {:margin-top "16px"} (cc/password-helper-text-sx (:name password-score))) + :fullWidth true + :label label + :variant "standard" + :value val + :placeholder placeholder + :error (not (nil? error-text)) + :helperText (cond + (and (nil? error-text) (not (nil? password-score))) + (-> password-score :name lstr-l-cv) + + (nil? error-text) + helper-text + + :else + error-text) + :onChange on-change-handler + :required false + :disabled disabled + :InputLabelProps {} + :InputProps {:id key + :sx (theme-text-field-sx edit @custom-theme-atom) + :endAdornment (if no-end-icons nil + (r/as-element + [mui-input-adornment {:position "end"} + [end-icons key value protected visible edit] + #_(seq icons)])) + :type (if (or (not protected) visible) "text" "password")} + ;;attributes for 'input' tag can be added here + ;;It seems adding these 'InputProps' also works + ;;We need to use 'readOnly' and not 'readonly' + :inputProps {:readOnly (not edit) + ;;:sx (if edit sx2 sx1) ;;:readonly "readonly" + }}])) ;; Both works ;;"& .MuiInputBase-input" ;; "& .MuiInput-input" -(def otp-txt-input-sx - { - "& .MuiInputBase-input" +(def otp-txt-input-sx + {"& .MuiInputBase-input" {:color "green" :font-size "1.75em" :font-weight "300" ;; To make it bold diff --git a/src/main/onekeepass/frontend/entry_form_ex.cljs b/src/main/onekeepass/frontend/entry_form_ex.cljs index d5d2011..26c21fd 100644 --- a/src/main/onekeepass/frontend/entry_form_ex.cljs +++ b/src/main/onekeepass/frontend/entry_form_ex.cljs @@ -208,7 +208,9 @@ [mui-icon-add-circle-outline-outlined]]]])])) ;; Note translations for field names (labels) are done in 'text-field' defined in fields.cljs -(defn section-content [edit section-name section-data group-uuid] +(defn section-content + "This is called for each section of an entry" + [{:keys [edit section-name section-data group-uuid]}] (let [errors @(form-events/entry-form-field :error-fields)] ;; Show a section in edit mode irrespective of its contents; In non edit mode a section is shown only ;; if it has some fields with non blank value. @@ -220,23 +222,23 @@ } [section-header section-name] (doall - (for [{:keys [key value + (for [{:keys [key + value protected required data-type select-field-options - standard-field - password-score] :as kv} section-data] - ;; All fields of this section is shown in edit mode. In case of non edit mode, only the - ;; fields with values are shown + ;; standard-field indicates a predefined field of an entry type or not + standard-field] :as kv} section-data] + ;; All fields of this section is shown in edit mode. In case of non edit mode, only the + ;; fields with values are shown (when (or edit (not (str/blank? value))) #_(or edit (or required (not (str/blank? value)))) ^{:key key} [mui-stack {:direction "row" - :ref (fn [e] - ;; We keep a ref to the underlying HtmlElememnt - #object[HTMLDivElement [object HTMLDivElement]] - ;; The ref is kept for each filed's enclosing container 'Stack' component so that we can position the Popper - ;; Sometimes the value of e is nil as react redraws the node - (swap! refs assoc key e))} + ;; We keep a ref to the underlying HtmlElememnt - #object[HTMLDivElement [object HTMLDivElement]] + ;; The ref is kept for each field's enclosing container 'Stack' component so that we can position the Popper. + ;; Sometimes the value of e is nil as react redraws the node + :ref (fn [e] (swap! refs assoc key e))} [mui-stack {:direction "row" :sx {:width (if edit "92%" "100%")}} (cond ;; select-field-options is vec of strings and gets data from @@ -257,7 +259,6 @@ [text-field (assoc kv :edit edit :error-text (get errors key) - :password-score password-score :visible @(form-events/visible? key) :on-change-handler #(form-events/update-section-value-on-change section-name key (-> % .-target .-value)))])] @@ -280,9 +281,36 @@ #_[custom-field-delete-confirm @(form-events/field-delete-dialog-data)] #_[custom-section-delete-confirm @(form-events/section-delete-dialog-data)]])))) -(defn all-sections-content [] +(defn get-section-data + "Called to set up any entry type specific data in kv + Returns an vec of kvd map for a section + " + [entry-type-uuid section-name section-fields] + (let [section-data (get section-fields section-name)] + (if (not= entry-type-uuid const/UUID_OF_ENTRY_TYPE_AUTO_OPEN) + section-data + (let [adjusted-section-data (mapv (fn [{:keys [key] :as m}] + (cond + (= key const/URL) + ;; for now read-value is not used + (assoc m :field-name "KDBX file to open" :read-value (:url-field-value m) ) + + ;; for now read-value is not used + (= key const/USERNAME) + (assoc m :field-name "Key file" :read-value (:key-file-path m)) + + (= key const/IFDEVICE) + (assoc m :field-name "Device ids to include or exclude") + + :else + m)) section-data)] + adjusted-section-data)))) + +(defn all-sections-content + "Component for all sections of an entry" + [] (let [{:keys [edit showing] - {:keys [section-names section-fields uuid group-uuid]} :data} + {:keys [entry-type-uuid section-names section-fields uuid group-uuid]} :data} @(form-events/entry-form-all) deleted? @(form-events/is-entry-parent-group-deleted group-uuid)] (m/react-use-effect @@ -302,7 +330,11 @@ [mui-stack (doall (for [section-name section-names] - ^{:key section-name} [section-content edit section-name (get section-fields section-name) group-uuid]))])) + ^{:key section-name} [section-content {:entry-type-uuid entry-type-uuid + :edit edit + :section-name section-name + :section-data (get-section-data entry-type-uuid section-name section-fields) #_(get section-fields section-name) + :group-uuid group-uuid}]))])) (defn title-with-icon-field [] ;;(println "title-with-icon-field called ") @@ -319,15 +351,13 @@ :required true :helper-text (tr-h "entryTitle") :error-text (:title errors) - :on-change-handler #(form-events/entry-form-data-update-field-value - :title (-> % .-target .-value))}]] + :on-change-handler (on-change-factory form-events/entry-form-data-update-field-value :title)}]] [mui-stack {:direction "row" :sx {:width "12%" :justify-content "center" :align-items "center"}} [mui-typography {:sx {:padding-left "5px"} :align "center" :paragraph false :variant "subtitle1"} (tr-l "icons")] - [mui-icon-button {:edge "end" :color "primary" :sx {;;:margin-top "16px" - ;;:margin-right "-8px" - } + [mui-icon-button {:edge "end" :color "primary" + :sx {} #_{:margin-top "16px" :margin-right "-8px"} :on-click show-icons-dialog} [entry-icon (:icon-id fields)]]] [icons-dialog @icons-dialog-flag]]]))) @@ -616,11 +646,11 @@ :label (tr-l entryType) :value entry-type-uuid ;;field-type :helper-text (tr-h entryTypeFields) - :on-change (on-change-factory2 form-events/entry-type-uuid-on-change) #_de/custom-field-type-edit-on-change + :on-change (on-change-factory2 form-events/entry-type-uuid-on-change) :variant "standard" :fullWidth true} ;; select fields options (doall - (for [{:keys [name uuid]} @entry-type-headers] + (for [{:keys [name uuid]} @entry-type-headers] ^{:key uuid} [mui-menu-item {:value uuid} (translated-entry-type-name name)]))]] [mui-stack {:direction "row" @@ -671,7 +701,7 @@ [mui-stack {:sx {:align-items "flex-end"}} [:div.buttons1 [mui-button {:variant "contained" :color "secondary" - :on-click form-events/new-entry-cancel-on-click #_ee/new-entry-cancel-on-click} "Cancel"] + :on-click form-events/new-entry-cancel-on-click} "Cancel"] [mui-button {:variant "contained" :color "secondary" :on-click form-events/ok-new-entry-add} "Ok"]]]] @@ -741,10 +771,11 @@ [mui-stack {:direction "row" :sx {:width "8%" :align-items "flex-end"}} [mui-tooltip {:title "Modify Field" :enterDelay 2500} [mui-icon-button {:edge "end" - :on-click #(form-events/open-section-field-modify-dialog {:key key - :protected protected - :required required - :section-name section-name})} + :on-click #(form-events/open-section-field-modify-dialog + {:key key + :protected protected + :required required + :section-name section-name})} [mui-icon-edit-outlined]]] [mui-tooltip {:title "Delete Field" :enterDelay 2500} [mui-icon-button {:edge "end" diff --git a/src/main/onekeepass/frontend/events/common_supports.cljs b/src/main/onekeepass/frontend/events/common_supports.cljs index 9c3f470..322d010 100644 --- a/src/main/onekeepass/frontend/events/common_supports.cljs +++ b/src/main/onekeepass/frontend/events/common_supports.cljs @@ -46,6 +46,8 @@ ([{:keys [error]} error-fn] (if-not (nil? error) (do + ;; Ensure that we hide this message box + (dispatch [:common/progress-message-box-hide]) (if (nil? error-fn) #_(println "API returned error: " error) ;; Should we use a generic error dialog instead of snackbar ? diff --git a/src/main/onekeepass/frontend/events/entry_form_auto_open.cljs b/src/main/onekeepass/frontend/events/entry_form_auto_open.cljs new file mode 100644 index 0000000..f343ea2 --- /dev/null +++ b/src/main/onekeepass/frontend/events/entry_form_auto_open.cljs @@ -0,0 +1,115 @@ +(ns onekeepass.frontend.events.entry-form-auto-open + (:require + [clojure.string :as str] + [onekeepass.frontend.background :as bg] + [onekeepass.frontend.constants :as const :refer [IFDEVICE PASSWORD URL + USERNAME]] + [onekeepass.frontend.events.common :as cmn-events :refer [active-db-key + check-error + on-error]] + [onekeepass.frontend.events.entry-form-common :refer [extract-form-field-names-values + form-data-kv-data + get-form-data]] + [re-frame.core :refer [dispatch reg-event-fx reg-fx]])) + + +(defn entry-form-open-url [url-value] + (dispatch [:entry-form-open-url url-value])) + +(reg-fx + :bg-open-url + (fn [[path]] + (bg/open-url path + (fn [api-response] + (on-error api-response))))) + +(reg-event-fx + :entry-form-open-url + (fn [{:keys [_db]} [_event-id url-value]] + (cond + (str/starts-with? url-value "kdbx:") + {:fx [[:dispatch [:entry-form-auto-open-resolve-properties]]]} + + (or (str/starts-with? url-value "https://") (str/starts-with? url-value "http://")) + {:fx [[:bg-open-url [url-value]]]} + + :else + {}))) + +(def all-auto-open-kvd-keys [URL USERNAME IFDEVICE]) + +;; ao-keys is all-auto-open-kvd-keys and is not yet used +(defn auto-open-properties-dispatch-fn [ao-keys api-response] + (when-let [auto-props-resolved + (check-error api-response + #(dispatch [:entry-form-auto-open-properties-resolve-error %]))] + (dispatch [:entry-form-auto-open-properties-resolved ao-keys auto-props-resolved]))) +;; +(reg-event-fx + :entry-form-auto-open-resolve-properties + (fn [{:keys [db]} [_event-id]] + (let [{:keys [entry-type-uuid] :as form-data} (get-form-data db)] + ;; Should entry-type-uuid check is required ? + (if (= entry-type-uuid const/UUID_OF_ENTRY_TYPE_AUTO_OPEN) + (let [field-m (extract-form-field-names-values form-data) + auto-props {:source-db-key (active-db-key db) + :url-field-value (get field-m URL) + :key-file-path (get field-m USERNAME) + :device_if_val (get field-m const/IFDEVICE)}] + {:fx [[:bg-resolve-auto-open-properties [auto-props (partial auto-open-properties-dispatch-fn all-auto-open-kvd-keys)]]]}) + {})))) + +(reg-fx + :bg-resolve-auto-open-properties + (fn [[auto-props dispatch-fn]] + (bg/resolve-auto-open-properties auto-props dispatch-fn))) + +(reg-event-fx + :entry-form-auto-open-properties-resolved + (fn [{:keys [db]} [_event-id _ao-keys {:keys [url-field-value key-file-path can-open]}]] + (if (not can-open) + {:fx [[:dispatch [:common/error-info-box-show {:title "Database auto open" :error-text "The device is excluded in opening this database url"}]]]} + (let [{:keys [value]} (form-data-kv-data (get-form-data db) PASSWORD)] + {:fx [[:dispatch [:open-db/auto-open-with-credentials url-field-value value key-file-path]]]})))) + +(reg-event-fx + :entry-form-auto-open-properties-resolve-error + (fn [{:keys [_db]} [_event-id error]] + {:fx [[:dispatch [:common/error-info-box-show {:title "Auto open error" :error-text error}]]]})) + + +(comment) + + +#_(reg-event-fx + :entry-form-auto-open-properties-resolved + (fn [{:keys [db]} [_event-id ao-keys {:keys [url-field-value key-file-path can-open]} :as _auto-props-resolved]] + (let [{:keys [section-fields] :as _form-data} (get-form-data db) + [section-name section-kvs] (section-containing-field section-fields URL) + + section-kvs (if (contains-val? ao-keys URL) + (section-kvs-updated-with-field-value section-kvs (assoc (field-key-value-data section-kvs URL) :url-field-value url-field-value)) + section-kvs) + + section-kvs (if (contains-val? ao-keys USERNAME) + (section-kvs-updated-with-field-value section-kvs (assoc (field-key-value-data section-kvs USERNAME) :key-file-path key-file-path)) + section-kvs) + + section-kvs (if (contains-val? ao-keys IFDEVICE) + (section-kvs-updated-with-field-value section-kvs (assoc (field-key-value-data section-kvs IFDEVICE) :can-open can-open)) + section-kvs) + + + ;; kvd (field-key-value-data section-kvs URL) + ;; section-kvs (section-kvs-updated-with-field-value section-kvs (assoc kvd :url-field-value url-field-value)) + + ;; kvd (field-key-value-data section-kvs USERNAME) + ;; section-kvs (section-kvs-updated-with-field-value section-kvs (assoc kvd :key-file-path key-file-path)) + + ;; kvd (field-key-value-data section-kvs IFDEVICE) + ;; section-kvs (section-kvs-updated-with-field-value section-kvs (assoc kvd :can-open can-open)) + ] + {:db (assoc-in-key-db db [entry-form-key :data :section-fields section-name] section-kvs)}))) + + + diff --git a/src/main/onekeepass/frontend/events/entry_form_common.cljs b/src/main/onekeepass/frontend/events/entry_form_common.cljs index c062919..8009276 100644 --- a/src/main/onekeepass/frontend/events/entry_form_common.cljs +++ b/src/main/onekeepass/frontend/events/entry_form_common.cljs @@ -11,6 +11,11 @@ (def Favorites "Favorites") +(defn get-form-data + "Gets the current form data of a currently opened db from the app-db" + [app-db] + (get-in-key-db app-db [entry-form-key :data])) + (defn is-field-exist "Checks that a given field name exists in the entry form or not " [app-db field-name] @@ -55,6 +60,23 @@ section-kvs (mapv (fn [m] (if (= (:key m) key) (assoc m :value value) m)) section-kvs)] section-kvs)) +(defn form-data-kvd-fields + "Gets the vec of all Kvd map found in an entry" + [form-data] + (-> form-data :section-fields vals flatten)) + +(defn extract-form-field-names-values + "Returns a map with field name as key (a string type) and field value as value" + [form-data] + ;; :section-fields returns a map with section name as keys + ;; vals fn return 'values' ( a vec of field info map) for all sections. Once vec for each section. + ;; And need to use flatten to combine all section values + ;; For example if two sections, vals call will return a two member ( 2 vec) + ;; sequence. Flatten combines both vecs and returns a single sequence of field info maps + (let [fields (form-data-kvd-fields form-data) #_(-> form-data :section-fields vals flatten) + names-values (into {} (for [{:keys [key value]} fields] [key value]))] + names-values)) + (defn extract-form-otp-fields "Returns a map with a otp field name as key and current-opt-token value as value This is formed by going through all otp fields in KVs (section-fields) @@ -66,8 +88,65 @@ ;; For example if we have two sections, vals call will return a two member ( 2 vec) ;; sequence. Flatten combines both vecs and returns a single sequence of field info maps (let [;; fields is a vec of KV maps - fields (-> form-data :section-fields vals flatten) + fields (form-data-kvd-fields form-data) ;; otp-fields is a vec of KV maps only for otp fields otp-fields (filter (fn [m] (= ONE_TIME_PASSWORD_TYPE (:data-type m))) fields) names-values (into {} (for [{:keys [key current-opt-token]} otp-fields] [key current-opt-token]))] - names-values)) \ No newline at end of file + names-values)) + +(defn field-key-value-data + "Checks whether the arg 'field-maps-vec' (a vec of kvd maps) has a map + with kvd field map (struct KeyValueData) for the key 'field-name' + + The arg 'field-name' is a string value like 'URL' 'Password' or 'UserName' + Reurns the kvd map if the passed vec of maps has a map with :key = field-name + " + ([field-maps-vec field-name] + (->> field-maps-vec (filter + (fn [kvd] (= (:key kvd) field-name))) first))) + +(defn form-data-kv-data + "Gets the kvd map for this 'field-name' from all kvds found for an entry in form-data map" + [form-data field-name] + (field-key-value-data (form-data-kvd-fields form-data) field-name ) ) + + +;; Few other fns that may be useful +;; Not used for now +#_(defn- has-field + " Checks whether the arg 'field-maps-vec' has a map with entry form entry field map + (struct KeyValueData) that has a 'key' with value of the arg 'field-name' ( a string value) + Reurns true if the passed vec of maps has a map with :key = field-name + " + [field-maps-vec field-name] + (->> field-maps-vec (filter + (fn [m] (= (:key m) field-name))) empty? boolean not)) + +#_(defn- section-containing-field + "Called to get the section of a field + Returns a vec (2 elements) of section name and a vec of field maps (kvd maps) + " + [section-fields field-name] + (let [section-name-with-kvs (->> + section-fields + (filterv (fn [[_section-name field-maps-vec]] + (has-field field-maps-vec field-name))) first)] + ;; [section-name section-kvs] + section-name-with-kvs)) + +#_(defn- section-kvs-updated-with-field-value + "The arg 'section-kvs' is a vec of kvd (struct KeyValueData) maps of a section + Returns the updated kvd map + " + [section-kvs {:keys [key] :as kvd-m}] + (let [section-kvs (mapv (fn [m] (if (= (:key m) key) kvd-m m)) section-kvs)] + section-kvs)) + +#_(defn- section-updated-with-field-value + "Updates the kvd found in a section with the kvd found in arg 'kvd-m + Returns a vector (2 elements) with section name and a vec of kvd maps + " + [section-fields {:keys [key] :as kvd-m}] + (let [[section-name section-kvs] (section-containing-field section-fields key) + section-kvs (section-kvs-updated-with-field-value section-kvs kvd-m)] + [section-name section-kvs])) diff --git a/src/main/onekeepass/frontend/events/entry_form_ex.cljs b/src/main/onekeepass/frontend/events/entry_form_ex.cljs index c3e99a1..adb31c4 100644 --- a/src/main/onekeepass/frontend/events/entry_form_ex.cljs +++ b/src/main/onekeepass/frontend/events/entry_form_ex.cljs @@ -1,7 +1,7 @@ (ns onekeepass.frontend.events.entry-form-ex - (:require + (:require [clojure.string :as str] - [onekeepass.frontend.background :as bg] + [onekeepass.frontend.background :as bg] [onekeepass.frontend.constants :as const :refer [PASSWORD]] [onekeepass.frontend.events.common :as cmn-events :refer [active-db-key assoc-in-key-db @@ -11,16 +11,143 @@ on-error]] [onekeepass.frontend.events.entry-form-common :refer [add-section-field entry-form-key + extract-form-field-names-values extract-form-otp-fields + get-form-data is-field-exist merge-section-key-value]] ;; Need to be called here so that events are registered + [onekeepass.frontend.events.entry-form-auto-open :as ao-events] [onekeepass.frontend.translation :refer [lstr-sm]] [onekeepass.frontend.utils :as u :refer [contains-val?]] - [re-frame.core :refer [dispatch reg-event-db reg-event-fx reg-fx - reg-sub subscribe]])) + [re-frame.core :refer [dispatch reg-event-db reg-event-fx reg-fx reg-sub + subscribe]])) (def Favorites "Favorites") +(def entry-form-open-url ao-events/entry-form-open-url) + +;;;;;;;;;;;;;;;;;;;;;; Support functions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defn- validate-entry-form-data + "Verifies that the user has entered valid values in some of the required fields of the entry form + Returns a map of fileds with errors and error-fields will be {} in case no error is found + " + [{:keys [group-uuid title]}] + ;;(println "group-uuid title are " group-uuid title) + (let [error-fields (cond-> {} + (u/uuid-nil-or-default? group-uuid) + (assoc :group-selection "Please select a group ") + + (str/blank? title) + (assoc :title "Please enter a title for this form"))] + error-fields)) + +(defn- validate-required-fields [error-fields _kvsd] + error-fields + #_(loop [{:keys [key value required] :as m} (first kvsd) + rest-kvsd (next kvsd) + acc error-fields] + (if (nil? m) acc + (let [acc (if (and required (str/blank? value)) + (assoc acc key "Please enter a valid value for this required field") + acc)] + (recur (first rest-kvsd) (next rest-kvsd) acc))))) + +(defn- validate-all + "Validates all required fields including title, parent group etc + Returns the error-fields map or an empty map if all required values are present + " + [form-data] + (let [error-fields (validate-entry-form-data form-data) + ;; We get all fields across all sections + ;; Need to make a flattened sequence of all KV maps + kvds (flatten (vals (:section-fields form-data))) + error-fields (validate-required-fields error-fields kvds)] + error-fields)) + +(defn- init-expiry-duration-selection + "Iniatializes the expiry related data in entry-form top level field. + Returns the updated app-db" + [app-db entry-form-data] + (if (:expires entry-form-data) + (assoc-in-key-db app-db [entry-form-key :expiry-duration-selection] "custom-date") + (assoc-in-key-db app-db [entry-form-key :expiry-duration-selection] "no-expiry"))) + +;; TODO: Need to replace with generic fns from common +(defn- has-password-field + "Checks whether the arg 'field-maps-vec' has a map with entry form entry field map + (struct KeyValueData) that has a 'key' for password + Reurns true if the passed vec of maps has a map with :key = Password + " + [field-maps-vec] + (->> field-maps-vec (filter + (fn [m] (= (:key m) PASSWORD))) empty? boolean not)) + +(defn- section-with-password-score + "Returns a vector of two elements [section-name [{:key..} {:key ..}]] or empty vector + if no PASSWORD field is found + " + [db] + (let [section-fields (get-in-key-db db [entry-form-key :data :section-fields]) + ;; filter returns a seq with 0 or 1 member vec [k v] + section-name-with-kvs (->> section-fields + (filterv (fn [[_section-name field-maps-vec]] + (has-password-field field-maps-vec))) first)] + section-name-with-kvs)) + +(defn- adjust-expiration-time + "Returns the updated app-db" + [app-db selection expiry-time] + (println "adjust-expiration-time in " expiry-time) + (if (= selection "no-expiry") + (assoc-in-key-db app-db [entry-form-key :data :expires] false) + ;; value is js Date utc string of format "2022-05-13T04:02:44.481Z" + ;; The backend rust deserialization fails with this value + ;; Removing the '.481Z' and using just "2022-05-13T04:02:44" works for now + ;; Need to fix the backend to accept the date string ending in Z without this hack + (-> app-db (assoc-in-key-db [entry-form-key :data :expires] true) + (assoc-in-key-db [entry-form-key :data :expiry-time] (u/strip-utc-tz expiry-time) #_(first (str/split expiry-time #"\.")))))) + +(defn expiry-date-on-change-factory + "Creates an event handler to handle an event when the date is changed in the date time picker" + [] + ;; Returns a function that acceps two arguments 'value: TValue, keyboardInputValue: string' + ;; See @mui/x-date-pickers-pro/DateTimePicker onChange prop + (fn [v kb] + ;;(println "kb is " kb) + ;; (println " exp v str is " (str v) " v as date " v ) + + ;; Following is not used as kb will be in the format of '09/29/2022 08:53 pm' and this is not in the + ;; format as expected by backend api and call will fail + #_(let [d (cond + (= (str v) "Invalid Date") + ;; kb is nil if v is a valid date; + kb + + (instance? js/Date v) + (u/to-UTC-ISO-string v) + + :else + v)] + (dispatch [:entry-form-update-section [:main {:fields [:expiry :value] + :value d}]]) + (dispatch [:entry-form-update-section [:main {:fields [:expiry :expiry-duration-selection] + :value "custom-date"}]])) + + ;; If we edit the field directly, we get #inst "0NaN-NaN-NaNTNaN:NaN:NaN.NaN-00:00" in v + ;; This causes 'Compile Exception: Unrecognized date/time syntax: 0NaN-NaN-NaNTNaN:NaN:NaN.NaN-00:00' + ;; For now we ignore any attempt changes in the input and allow the date change by datetime picker + ;; by using the following check. (str v) returns the string "Invalid Date" and kb will have keyboard input + ;; in the format '09/29/2022 08:53 pm'. + (when-not (= (str v) "Invalid Date") + (let [d (if (instance? js/Date v) (u/to-UTC-ISO-string v) v)] + ;; Need to strip 'Z' indicating UTC from datetime str + (dispatch [:entry-form-data-update-field-value :expiry-time (u/strip-utc-tz d)]) + (dispatch [:entry-form-data-update-field-value :expires true]) + (dispatch [:entry-form-all-update-field-value :expiry-duration-selection "custom-date"]))))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + (defn password-generator-show [] (dispatch [:password-generator/start ;; A call back fn that is to be called with the new generated password and score @@ -74,51 +201,13 @@ (dispatch [:entry-form-tags-selected-ex (fix-tags-selection-prefix tags)])) #_(defn section-date-field-on-change-factory - "Creates an event handler to handle an event when the date is changed in the date picker" - [section key] - (fn [date-val kb] + "Creates an event handler to handle an event when the date is changed in the date picker" + [section key] + (fn [date-val kb] ;;(println "date-val is " date-val " and type is " (type date-val)) - (when-not (= (str date-val) "Invalid Date") - (let [date-val-str (if (instance? js/Date date-val) (.toLocaleDateString date-val) date-val)] - (dispatch [:entry-form-update-section-value section key date-val-str]))))) - -(defn expiry-date-on-change-factory - "Creates an event handler to handle an event when the date is changed in the date time picker" - [] - ;; Returns a function that acceps two arguments 'value: TValue, keyboardInputValue: string' - ;; See @mui/x-date-pickers-pro/DateTimePicker onChange prop - (fn [v kb] - ;;(println "kb is " kb) - ;; (println " exp v str is " (str v) " v as date " v ) - - ;; Following is not used as kb will be in the format of '09/29/2022 08:53 pm' and this is not in the - ;; format as expected by backend api and call will fail - #_(let [d (cond - (= (str v) "Invalid Date") - ;; kb is nil if v is a valid date; - kb - - (instance? js/Date v) - (u/to-UTC-ISO-string v) - - :else - v)] - (dispatch [:entry-form-update-section [:main {:fields [:expiry :value] - :value d}]]) - (dispatch [:entry-form-update-section [:main {:fields [:expiry :expiry-duration-selection] - :value "custom-date"}]])) - - ;; If we edit the field directly, we get #inst "0NaN-NaN-NaNTNaN:NaN:NaN.NaN-00:00" in v - ;; This causes 'Compile Exception: Unrecognized date/time syntax: 0NaN-NaN-NaNTNaN:NaN:NaN.NaN-00:00' - ;; For now we ignore any attempt changes in the input and allow the date change by datetime picker - ;; by using the following check. (str v) returns the string "Invalid Date" and kb will have keyboard input - ;; in the format '09/29/2022 08:53 pm'. - (when-not (= (str v) "Invalid Date") - (let [d (if (instance? js/Date v) (u/to-UTC-ISO-string v) v)] - ;; Need to strip 'Z' indicating UTC from datetime str - (dispatch [:entry-form-data-update-field-value :expiry-time (u/strip-utc-tz d)]) - (dispatch [:entry-form-data-update-field-value :expires true]) - (dispatch [:entry-form-all-update-field-value :expiry-duration-selection "custom-date"]))))) + (when-not (= (str date-val) "Invalid Date") + (let [date-val-str (if (instance? js/Date date-val) (.toLocaleDateString date-val) date-val)] + (dispatch [:entry-form-update-section-value section key date-val-str]))))) (defn expiry-duration-selection-on-change [value] (dispatch [:expiry-duration-selection-ex value])) @@ -198,44 +287,8 @@ [group-uuid] (subscribe [:group-tree-content/group-in-recycle-bin group-uuid])) -;;;;;;;;;;;;;;;;;;;;;;; Form Events ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defn validate-entry-form-data - "Verifies that the user has entered valid values in some of the required fields of the entry form - Returns a map of fileds with errors and error-fields will be {} in case no error is found - " - [{:keys [group-uuid title]}] - ;;(println "group-uuid title are " group-uuid title) - (let [error-fields (cond-> {} - (u/uuid-nil-or-default? group-uuid) - (assoc :group-selection "Please select a group ") - - (str/blank? title) - (assoc :title "Please enter a title for this form"))] - error-fields)) +;;;;;;;;;;;;;;;;;;;;;;; Form Events ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -(defn validate-required-fields [error-fields _kvsd] - error-fields - #_(loop [{:keys [key value required] :as m} (first kvsd) - rest-kvsd (next kvsd) - acc error-fields] - (if (nil? m) acc - (let [acc (if (and required (str/blank? value)) - (assoc acc key "Please enter a valid value for this required field") - acc)] - (recur (first rest-kvsd) (next rest-kvsd) acc))))) - -(defn validate-all - "Validates all required fields including title, parent group etc - Returns the error-fields map or an empty map if all required values are present - " - [form-data] - (let [error-fields (validate-entry-form-data form-data) - ;; We get all fields across all sections - ;; Need to use make a sequence of all KV maps - kvds (flatten (vals (:section-fields form-data))) - error-fields (validate-required-fields error-fields kvds)] - error-fields)) (reg-event-fx :entry-form-ex/find-entry-by-id @@ -245,21 +298,14 @@ (fn [api-response] (when-let [entry (check-error api-response - #(dispatch [:entry-form-data-load-completed :error %]))] + #(dispatch [:entry-form-data-load-error %]))] (dispatch [:entry-form-data-load-completed-ok entry])))) {})) -(defn- init-expiry-duration-selection - "Iniatializes the expiry related data in entry-form top level field. - Returns the updated app-db" - [app-db entry-form-data] - (if (:expires entry-form-data) - (assoc-in-key-db app-db [entry-form-key :expiry-duration-selection] "custom-date") - (assoc-in-key-db app-db [entry-form-key :expiry-duration-selection] "no-expiry"))) (reg-event-fx :entry-form-data-load-completed-ok - (fn [{:keys [db]} [_event-id entry-data]] + (fn [{:keys [db]} [_event-id entry-data]] (let [otp-fields (extract-form-otp-fields entry-data)] {:db (-> db (assoc-in-key-db [entry-form-key :data] entry-data) @@ -270,28 +316,30 @@ ;; This map is updated periodically when polling is started (assoc-in-key-db [entry-form-key :otp-fields] otp-fields))}))) -;; Rename :entry-form-data-load-completed-error -;; and remove ok part (reg-event-db - :entry-form-data-load-completed - (fn [db [_event-id status result]] ;;result is ) - (if (= status :ok) - (-> db - #_(assoc-in-key-db [entry-form-key] {}) - (assoc-in-key-db [entry-form-key :data] result) - (assoc-in-key-db [entry-form-key :edit] false) - (init-expiry-duration-selection result) - (assoc-in-key-db [entry-form-key :showing] :selected)) + :entry-form-data-load-error + (fn [db [_event-id error]] + (-> db (assoc-in-key-db [entry-form-key :api-error-text] error)))) - (-> db (assoc-in-key-db [entry-form-key :api-error-text] result))))) +;; Rename :entry-form-data-load-completed-error +;; and remove ok part +#_(reg-event-db + :entry-form-data-load-completed + (fn [db [_event-id status result]] ;;result is ) + (if (= status :ok) + (-> db + #_(assoc-in-key-db [entry-form-key] {}) + (assoc-in-key-db [entry-form-key :data] result) + (assoc-in-key-db [entry-form-key :edit] false) + (init-expiry-duration-selection result) + (assoc-in-key-db [entry-form-key :showing] :selected)) + (-> db (assoc-in-key-db [entry-form-key :api-error-text] result))))) (reg-event-fx :entry-form-update-section-value (fn [{:keys [db]} [_event-id section key value]] - (let [;;section-kvs (get-in-key-db db [entry-form-key :data :section-fields section]) - ;;section-kvs (mapv (fn [m] (if (= (:key m) key) (assoc m :value value) m)) section-kvs) - section-kvs (merge-section-key-value db section key value)] + (let [section-kvs (merge-section-key-value db section key value)] (if-not (= key PASSWORD) {:db (assoc-in-key-db db [entry-form-key :data :section-fields section] section-kvs)} @@ -308,27 +356,6 @@ ;; password-score is a map from struct 'PasswordScore' (dispatch [:entry-form-update-section-password-score password-score])))))) -(defn- has-password-field - "Checks whether the arg 'field-maps-vec' has a map with entry form entry field map - (struct KeyValueData) has a 'key' for password - Reurns true if the passed vec of maps has a map with :key = Password - " - [field-maps-vec] - (->> field-maps-vec (filter - (fn [m] (= (:key m) PASSWORD))) empty? boolean not)) - -(defn- section-with-password-score - "Returns a vector of two elements [section-name [{:key..} {:key ..}]] or empty vector - if no PASSWORD field is found - " - [db] - (let [section-fields (get-in-key-db db [entry-form-key :data :section-fields]) - ;; filter returns a seq with 0 or 1 member vec [k v] - section-name-with-kvs (->> section-fields - (filterv (fn [[_section-name field-maps-vec]] - (has-password-field field-maps-vec))) first)] - section-name-with-kvs)) - ;; Updates the new score (reg-event-db :entry-form-update-section-password-score @@ -414,26 +441,15 @@ (fn [{:keys [db]} [_event-id edit?]] (if edit? {:db (-> db - (assoc-in-key-db [entry-form-key :undo-data] (get-in-key-db db [entry-form-key :data])) + (assoc-in-key-db [entry-form-key :undo-data] (get-form-data db)) (assoc-in-key-db [entry-form-key :edit] edit?))} {:db (assoc-in-key-db db [entry-form-key :edit] edit?)}))) - - -#_(reg-event-db - :entry-form-ex/edit - (fn [db [_event-id edit?]] - (if edit? - (-> db - (assoc-in-key-db [entry-form-key :undo-data] (get-in-key-db db [entry-form-key :data])) - (assoc-in-key-db [entry-form-key :edit] edit?)) - (assoc-in-key-db db [entry-form-key :edit] edit?)))) - (reg-event-fx :cancel-entry-edit-ex (fn [{:keys [db]} [_event-id]] (let [undo-data (get-in-key-db db [entry-form-key :undo-data]) - data (get-in-key-db db [entry-form-key :data])] + data (get-form-data db)] {:db (if (and (seq undo-data) (not= undo-data data)) (-> db (assoc-in-key-db [entry-form-key :data] undo-data) (assoc-in-key-db [entry-form-key :undo-data] {}) @@ -444,7 +460,6 @@ (assoc-in-key-db [entry-form-key :error-fields] {}))) :fx []}))) - #_(reg-event-db :cancel-entry-edit-ex (fn [db [_event-id]] @@ -460,14 +475,14 @@ (assoc-in-key-db [entry-form-key :error-fields] {})))))) (defn- update-entry [db dispatch-fn] - (let [form-data (get-in-key-db db [entry-form-key :data])] + (let [form-data (get-form-data db)] (bg/update-entry (active-db-key db) form-data dispatch-fn))) ;; Edit is accepted and calls the backend API to update the Db (reg-event-fx :ok-entry-edit-ex (fn [{:keys [db]} [_event-id]] - (let [form-data (get-in-key-db db [entry-form-key :data]) + (let [form-data (get-form-data db) error-fields (validate-all form-data)] ;;(println "auto type is " (:auto-type form-data)) (if (boolean (seq error-fields)) @@ -482,7 +497,7 @@ (reg-event-fx :entry-form/validate-form-fields (fn [{:keys [db]} [_event-id callback-fn]] - (let [form-data (get-in-key-db db [entry-form-key :data]) + (let [form-data (get-form-data db) error-fields (validate-all form-data)] (if (boolean (seq error-fields)) {:db (assoc-in-key-db db [entry-form-key :error-fields] error-fields)} @@ -535,18 +550,6 @@ {:db (assoc-in-key-db db [entry-form-key :data :tags] tags) :fx [[:dispatch [:ok-entry-edit-ex]]]}))) -(defn- adjust-expiration-time - "Returns the updated app-db" - [app-db selection expiry-time] - (println "adjust-expiration-time in " expiry-time) - (if (= selection "no-expiry") - (assoc-in-key-db app-db [entry-form-key :data :expires] false) - ;; value is js Date utc string of format "2022-05-13T04:02:44.481Z" - ;; The backend rust deserialization fails with this value - ;; Removing the '.481Z' and using just "2022-05-13T04:02:44" works for now - ;; Need to fix the backend to accept the date string ending in Z without this hack - (-> app-db (assoc-in-key-db [entry-form-key :data :expires] true) - (assoc-in-key-db [entry-form-key :data :expiry-time] (u/strip-utc-tz expiry-time) #_(first (str/split expiry-time #"\.")))))) (reg-event-db :expiry-duration-selection-ex @@ -584,7 +587,7 @@ (reg-sub :entry-form-data-ex (fn [db _query-vec] - (get-in-key-db db [entry-form-key :data]))) + (get-form-data db))) ;; Gets the only section data (reg-sub @@ -629,7 +632,7 @@ :modified-ex (fn [db _query-vec] (let [undo-data (get-in-key-db db [entry-form-key :undo-data]) - data (get-in-key-db db [entry-form-key :data])] + data (get-form-data db)] (if (and (seq undo-data) (not= undo-data data)) true false)))) @@ -1179,7 +1182,7 @@ (fn [{:keys [db]} [_event-id]] {:db (-> db (assoc-in-key-db [entry-form-key :undo-data] - (get-in-key-db db [entry-form-key :data])) + (get-form-data db)) (assoc-in-key-db [entry-form-key :data] entry-type-data) (assoc-in-key-db [entry-form-key :error-fields] {}) (assoc-in-key-db [entry-form-key :showing] :custom-entry-type-new))})) @@ -1212,7 +1215,7 @@ (reg-event-fx :create-custom-entry-type (fn [{:keys [db]} [_event-id]] - (let [entry-type-form-data (get-in-key-db db [entry-form-key :data]) + (let [entry-type-form-data (get-form-data db) error-fields (validate-entry-type-form-data entry-type-form-data)] (if (boolean (seq error-fields)) {:db (assoc-in-key-db db [entry-form-key :error-fields] error-fields)} @@ -1337,13 +1340,8 @@ (reg-event-fx :ok-new-entry-add-ex (fn [{:keys [db]} [_event-id]] - (let [form-data (get-in-key-db db [entry-form-key :data]) - error-fields (validate-all form-data) - ;; error-fields (validate-entry-form-data form-data) - ;; ;; We get all fields across all sections - ;; ;; Need to use make a sequence of all KV maps - ;; kvds (flatten (vals (:section-fields form-data))) - ;; error-fields (validate-required-fields error-fields kvds) + (let [form-data (get-form-data db) + error-fields (validate-all form-data) errors-found (boolean (seq error-fields))] (if errors-found {:db (assoc-in-key-db db [entry-form-key :error-fields] error-fields)} @@ -1668,7 +1666,6 @@ (fn [db _query-vec] (get-in-key-db db [:entry-delete]))) -;;;;;;;;;;;;;;; Entry delete End ;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;; Auto type ;;;;;;;;;;;;;;;;;;;;;; (defn perform-auto-type-start [] @@ -1683,30 +1680,15 @@ (reg-event-fx :entry-perform-auto-type (fn [{:keys [db]} [_event-id]] - (let [{:keys [uuid auto-type]} (get-in-key-db db [entry-form-key :data])] + (let [{:keys [uuid auto-type]} (get-form-data db)] {:fx [[:auto-type/bg-active-window-to-auto-type [uuid auto-type]]]}))) - - -(defn extract-form-field-names-values - "Returns a map with field name as key and field value as value" - [form-data] - ;; :section-fields returns a map with section name as keys - ;; vals fn return 'values' ( a vec of field info map) for all sections. Once vec for each section. - ;; And need to use flatten to combine all section values - ;; For example if two sections, vals call will return a two member ( 2 vec) - ;; sequence. Flatten combines both vecs and returns a single sequence of field info maps - (let [fields (-> form-data :section-fields vals flatten) - names-values (into {} (for [{:keys [key value]} fields] [key value]))] - names-values)) - (reg-event-fx :entry-auto-type-edit (fn [{:keys [db]} [_event-id]] - (let [{:keys [uuid auto-type] :as form-data} (get-in-key-db db [entry-form-key :data]) + (let [{:keys [uuid auto-type] :as form-data} (get-form-data db) entry-form-fields (extract-form-field-names-values form-data)] {:fx [[:dispatch [:auto-type/edit-init uuid auto-type entry-form-fields]]]}))) - ;;;;;;;;;;;;;;;;;;;;; Otp (TOPT) related ;;;;;;;;;;; ;; All entry-form otp related events are moved to the @@ -1747,8 +1729,6 @@ ;; :notes :section-names :entry-type-icon-name :last-access-time :uuid :entry-type-uuid :group-uuid :creation-time ) - - ;;;;;;;;;;;;;;;;;;;;; Custom Field Add Dialog ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; (defn open-custom-field-dialog [] diff --git a/src/main/onekeepass/frontend/events/entry_form_otp.cljs b/src/main/onekeepass/frontend/events/entry_form_otp.cljs index 92464d6..b543af4 100644 --- a/src/main/onekeepass/frontend/events/entry_form_otp.cljs +++ b/src/main/onekeepass/frontend/events/entry_form_otp.cljs @@ -7,7 +7,8 @@ [onekeepass.frontend.events.entry-form-common :refer [entry-form-key extract-form-otp-fields merge-section-key-value]] - [re-frame.core :refer [reg-event-fx reg-fx reg-sub]])) + [re-frame.core :refer [reg-event-fx reg-fx reg-sub]] + [onekeepass.frontend.constants :as const])) ;; Called to update with the current tokens @@ -34,7 +35,7 @@ (defn remove-section-otp-field [otp-field-name {:keys [key] :as section-field-m}] (cond ;; current-opt-token is Option type in struct CurrentOtpTokenData and should be set to nil and not {} - (= key "otp") + (= key const/OTP) (assoc section-field-m :value nil :current-opt-token nil) (= key otp-field-name) diff --git a/src/main/onekeepass/frontend/events/open_db_form.cljs b/src/main/onekeepass/frontend/events/open_db_form.cljs index 0c7e6a0..d0ebaba 100644 --- a/src/main/onekeepass/frontend/events/open_db_form.cljs +++ b/src/main/onekeepass/frontend/events/open_db_form.cljs @@ -165,9 +165,11 @@ (reg-event-fx :open-db-file-loading-done (fn [{:keys [db]} [_event-id kdbx-loaded]] - {:db (-> db init-open-db-vals) ;; will hide dialog - :fx [[:dispatch [:common/kdbx-database-opened kdbx-loaded]]]})) - + ;; will hide dialog + {:db (-> db init-open-db-vals) + ;; Need to hide any progress msg dialog if shown + :fx [[:dispatch [:common/progress-message-box-hide]] + [:dispatch [:common/kdbx-database-opened kdbx-loaded]]]})) (defn- on-file-loading [api-response] (let [error-fn (fn [err] (dispatch [:open-db-error err]))] @@ -194,8 +196,7 @@ (reg-fx :bg-unlock-kdbx-file - (fn [[db-key pwd key-file-name dispatch-fn]] - (println "bg-unlock-kdbx-file is called") + (fn [[db-key pwd key-file-name dispatch-fn]] (bg/unlock-kdbx db-key pwd key-file-name dispatch-fn))) (reg-event-fx @@ -253,10 +254,6 @@ ;;;;;;;;;;;;;;;;;;;; auto db open ;;;;;;;;;;;;;;;;;;; - -(defn open-db-with-auto-open-credentials [db-file-full-path pwd key-file-name] - (dispatch [:open-db-with-auto-open-credentials db-file-full-path pwd key-file-name])) - (defn- handle-auto-open-response [api-response] (when-let [kdbx-loaded (check-error api-response)] (dispatch [:open-db-file-loading-done kdbx-loaded]))) @@ -265,24 +262,31 @@ (when-let [kdbx-loaded (check-error api-response #(dispatch [:open-db-error %]))] + (dispatch [:common/progress-message-box-hide]) (dispatch [:auto-open-unlock-db-file-loading-done kdbx-loaded]))) (reg-event-fx - :open-db-with-auto-open-credentials + :open-db/auto-open-with-credentials (fn [{:keys [db]} [_event-id db-file-full-path pwd key-file-name]] (let [db-list (cmn-events/opened-db-list db) already_opened (cmn-events/is-in-opend-db-list db-file-full-path db-list) - db-locked (cmn-events/locked? db db-file-full-path)] - #_(println " opened locked " opened locked) + db-locked (cmn-events/locked? db db-file-full-path)] (cond db-locked - {:fx [[:bg-unlock-kdbx-file [db-file-full-path pwd key-file-name handle-auto-open-unlock-response]]]} + {:fx [[:dispatch [:common/progress-message-box-show + "Unlocking database" + "Please wait..."]] + [:bg-unlock-kdbx-file [db-file-full-path pwd key-file-name handle-auto-open-unlock-response]]]} + ;; Just make that tab active already_opened {:fx [[:dispatch [:common/change-active-db-complete db-file-full-path]]]} :else - {:fx [[:bg-load-kdbx-file [db-file-full-path pwd key-file-name handle-auto-open-response]]]})))) + {:fx [[:dispatch [:common/progress-message-box-show + "Opening database" + "Please wait..."]] + [:bg-load-kdbx-file [db-file-full-path pwd key-file-name handle-auto-open-response]]]})))) (reg-event-fx :auto-open-unlock-db-file-loading-done diff --git a/src/main/onekeepass/frontend/password_generator.cljs b/src/main/onekeepass/frontend/password_generator.cljs index 6f39803..4d275ee 100644 --- a/src/main/onekeepass/frontend/password_generator.cljs +++ b/src/main/onekeepass/frontend/password_generator.cljs @@ -42,7 +42,11 @@ [mui-tab {:label (lstr-l 'passwordPhrase) :value :pass-phrase}]]) -;; TODO: Move to 'common-components' and also change in 'src/main/onekeepass/frontend/entry_form/fields.cljs' +;; When this field has the focus, Shift + Down key will show the menu items and can then be used to move up or down. +;; Also if we press the first letter (case sensitive ) of any options, then cursor moves to that menu item option + +;; TODO: +;; Move to 'common-components' and also change in 'src/main/onekeepass/frontend/entry_form/fields.cljs' ;; to use this common one (defn simple-selection-field [{:keys [id field-name @@ -71,11 +75,32 @@ (let [{:keys [value label]} (if (string? y) {:value y :label y} y)] ^{:key y} [m/mui-menu-item {:value value} label])))]) +;; Another way of doings 'select' field. Not complete. Leaving it here as an example +#_(defn simple-selection-field-1 + [{:keys [id + field-name + value + edit + error-text + helper-text + on-change-handler + select-field-options]} & {:as opts}] + + [m/mui-form-control + [m/mui-input-label {:id (if (nil? id) field-name id) :variant "standard"}] + [m/mui-select {:labelId (str (if (nil? id) field-name id) "-select") + :label field-name + :value value + :on-change on-change-handler} + (doall (for [y select-field-options] + (let [{:keys [value label]} (if (string? y) {:value y :label y} y)] + ^{:key y} [m/mui-menu-item {:value value} label])))]]) + ;; values should match enum WordListSource (def all-wl [{:value "EFFLarge" :label "EFF Large List"} {:value "EFFShort1" :label "EFF Short List 1"} {:value "EFFShort2" :label "EFF Short List 2"} - {:value "Google10000UsaEnglishNoSwearsMedium" :label "Google (U.S English,No Swears words)"} + {:value "Google10000UsaEnglishNoSwearsMedium" :label "U.S English,No Swears words"} ;; "Google (U.S English,No Swears words)" {:value "FrenchDicewareWordlist" :label "French Word List"} {:value "GermanDicewareWordlist" :label "German Word List"}]) @@ -126,7 +151,7 @@ [m/text-field {:label (lstr-l 'separator) :value separator :variant "standard" - :on-change (cc/on-change-factory gen-events/pass-phrase-options-update :separator)}]] + :on-change (cc/on-change-factory gen-events/pass-phrase-options-update :separator)}]] [mui-stack {:direction "row"} [mui-stack {:direction "row" :sx {:width "50%"}} [simple-selection-field {:field-name (lstr-l "capitalizeWords") From de3e713b3b0e3cb298f065ba0dee5c807c93085e Mon Sep 17 00:00:00 2001 From: jeyasankar Date: Wed, 29 Jan 2025 18:13:48 -0800 Subject: [PATCH 07/15] Added parsed fields data map use --- src-tauri/Cargo.lock | 1 + src-tauri/src/auto_open.rs | 184 ++++------------- src-tauri/src/auto_type/parsing.rs | 16 ++ src/main/onekeepass/frontend/background.cljs | 5 +- .../onekeepass/frontend/entry_form_ex.cljs | 193 ++++++++++-------- 5 files changed, 166 insertions(+), 233 deletions(-) diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index af2325b..5f4fee6 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -3101,6 +3101,7 @@ dependencies = [ "hmac", "lazy_static", "log", + "nom", "once_cell", "passwords", "quick-xml 0.30.0", diff --git a/src-tauri/src/auto_open.rs b/src-tauri/src/auto_open.rs index c3d6cca..4a7da21 100644 --- a/src-tauri/src/auto_open.rs +++ b/src-tauri/src/auto_open.rs @@ -112,14 +112,20 @@ fn resolved_path(parent_dir_path: &Path, in_path: &String) -> Result { return Err(Error::UnexpectedError("Url parsing is not complete".into())); } - let mut p = parent_dir_path.join(&parsed.full_path_part); + let final_path = if parsed.full_path_part.starts_with("file://") { + parsed.full_path_part.to_string() + } else { + let p = parent_dir_path.join(&parsed.full_path_part); + // If the canonicalize path is not found, then this will return an error + p.canonicalize().map_err(|e| Error::UnexpectedError(format!("Error: Path {:?} : {}", &p,e)))?.to_string_lossy().to_string() + }; + + // let mut p = parent_dir_path.join(&parsed.full_path_part); - // If the canonicalize path is not found, then this will return an error - p = p - .canonicalize() - .map_err(|e| Error::UnexpectedError(format!("Error: Path {:?} : {}", &p,e)))?; + // // If the canonicalize path is not found, then this will return an error + // p = p.canonicalize().map_err(|e| Error::UnexpectedError(format!("Error: Path {:?} : {}", &p,e)))?; - Ok(p.to_string_lossy().to_string()) + Ok(final_path) } #[derive(Debug)] @@ -128,12 +134,16 @@ struct ParsedVal<'a> { } fn parse_field_value(field_value: &str) -> IResult<&str, ParsedVal<'_>> { + // The incoming 'field_value' should be parsed by one of the 'alt' parsers let r = alt(( + // rest parser will have the part after removing the matching tag preceded(tag("kdbx://{DB_DIR}/"), rest), preceded(tag("kdbx://"), rest), + // This will match all other str value that do not start with 'kdbx' rest, ))(field_value)?; + // r.0 is remaining 'str'. It should be empty on successful parsing Ok(( r.0, ParsedVal { @@ -187,6 +197,8 @@ mod tests { let resolved = input.resolve().unwrap(); + println!("resolved is {:?}", resolved); + assert_eq!(resolved.can_open, true, "Expected true"); assert_eq!( resolved.url_field_value, @@ -195,9 +207,30 @@ mod tests { } #[test] + fn verify_file_path_resolve() { + let source_db_key = "/Users/jeyasankar/Documents/OneKeePass/TestAutoOpenXC.kdbx"; + let k_url = "file://f1//mytestkey2.keyx"; + let db_url = "kdbx://file://myshare/f1/PasswordsUsesKeyFile2.kdbx"; + + let input = AutoOpenProperties { + source_db_key: source_db_key.to_string(), + url_field_value: Some(db_url.into()), + key_file_path: Some(k_url.into()), + device_if_val: None, + }; + + let resolved = input.resolve().unwrap(); + + println!("resolved is {:?}", resolved); + + } +} + +/* +#[test] fn verify2() { - let cv = "Jeyasankars-MacBook-Pro16-M1.local".to_lowercase(); - let s = "Computer-one, Computer-Two, ! Computer-Six, !Computer-nine,!Jeyasankars-MacBook-Pro16-M1.local"; + let cv = "My-MacBook-Pro16-M1.local".to_lowercase(); + let s = "Computer-one, Computer-Two, ! Computer-Six, !Computer-nine,!My-MacBook-Pro16-M1.local"; let v: Vec = s.split(",").map(|s| s.trim().to_lowercase()).collect(); println!("v is {:?}", &v); @@ -247,138 +280,5 @@ mod tests { // println!("s is {:?}", &p); } -} - -/* - -fn parse_field_value(field_value: &str) -> IResult<&str, &str> { - let r = alt(( - preceded(tag("kdbx://{DB_DIR}/"), rest), - preceded(tag("kdbx://"), rest), - rest, - ))(field_value)?; - - Ok(r) -} - -pub(crate) fn resolve_auto_open_paths( - auto_open_path_input: &AutoOpenPathInput, -) -> Result { - println!("Incoming data {:?}", auto_open_path_input); - - let mut out = AutoOpenPathResolved::default(); - - let db_dir_path = Path::new(&auto_open_path_input.source_db_key); - - if !db_dir_path.exists() { - let er = format!("Invalid db_key {}", &auto_open_path_input.source_db_key); - return Err(Error::UnexpectedError(er)); - } - - let Some(parent_dir_path) = db_dir_path.parent() else { - return Err(Error::UnexpectedError("Parent dir is not found".into())); - }; - - if let Some(db_v) = auto_open_path_input.url_field_value.as_ref() { - out.url_field_value = Some(resolved_path(parent_dir_path, db_v)?); - } - - if let Some(kf_v) = auto_open_path_input.key_file_path.as_ref() { - out.key_file_path = Some(resolved_path(parent_dir_path, kf_v)?); - } - - Ok(out) -} - -const PREFIX1: &str = "kdbx://{DB_DIR}"; - -const PREFIX2: &str = "./"; - -fn resolve_auto_open_url(auto_open_source_db_key: &str, url_field_value: &str) -> Result { - let db_dir_path = Path::new(auto_open_source_db_key); - - if !db_dir_path.exists() { - let er = format!("Invalid db_key {}", &auto_open_source_db_key); - return Err(Error::UnexpectedError(er)); - } - - if let Some(parent_path) = db_dir_path.parent() { - let v = if url_field_value.starts_with(PREFIX1) { - url_field_value - .split_once(PREFIX1) - .map(|v| parent_path.join(v.1)) - } else { - Some(parent_path.join(url_field_value)) - }; - - return v - .map(|p| p.to_string_lossy().to_string()) - .ok_or(Error::UnexpectedError("Conversion error".into())); - } else { - return Err(Error::UnexpectedError(format!( - "Could not find parent dir from {:?}", - &db_dir_path - ))); - } -} - -pub(crate) fn resolve_auto_open_url( - auto_open_source_db_key: &str, - url_field_value: &str, -) -> Result { - let db_dir_path = Path::new(auto_open_source_db_key); - - if !db_dir_path.exists() { - let er = format!("Invalid db_key {}", &auto_open_source_db_key); - return Err(Error::UnexpectedError(er)); - } - - if !url_field_value.starts_with(PREFIX1) || !url_field_value.starts_with(PREFIX2) { - return Err(Error::UnexpectedError( - "Invalid url. Should start with kdbx:// or ./".into(), - )); - } - - if let Some(parent_path) = db_dir_path.parent() { - let v = if url_field_value.starts_with(PREFIX1) { - url_field_value - .split_once(PREFIX1) - .map(|v| parent_path.join(v.1)) - } else { - Some(parent_path.join(url_field_value)) - }; - - return v - .map(|p| p.to_string_lossy().to_string()) - .ok_or(Error::UnexpectedError("Conversion error".into())); - } else { - return Err(Error::UnexpectedError(format!( - "Could not find parent dir from {:?}", - &db_dir_path - ))); - } -} - - -pub(crate) fn resolve_auto_open_paths( - auto_open_path_input: &AutoOpenPathInput, -) -> Result { - let url_field_value = auto_open_path_input - .url_field_value - .as_ref() - .map(|p| resolve_auto_open_url(&auto_open_path_input.source_db_key, p).ok()) - .flatten(); - - let key_file_path = auto_open_path_input - .key_file_path - .as_ref() - .map(|p| resolve_auto_open_url(&auto_open_path_input.source_db_key, p).ok()) - .flatten(); - - Ok(AutoOpenPathResolved { - url_field_value, - key_file_path, - }) -} -*/ +*/ \ No newline at end of file diff --git a/src-tauri/src/auto_type/parsing.rs b/src-tauri/src/auto_type/parsing.rs index 1f44e3d..fb26f35 100644 --- a/src-tauri/src/auto_type/parsing.rs +++ b/src-tauri/src/auto_type/parsing.rs @@ -126,6 +126,8 @@ fn to_num<'a>(default_val: i32) -> impl FnMut(&'a str) -> IResult<&'a str, i32> // Gets any key name with any optional repeat value // Repeat a key x times (e.g., {SPACE 5} inserts five spaces) fn key_name_opt_repeat_parser<'a>() -> impl FnMut(&'a str) -> IResult<&'a str, PlaceHolder<'a>> { + // map_parser takes the result of the first parser 'fenced_name()' and tries to apply the second parser to it. + // If both parsers succeed, then it returns the value. map_parser( fenced_name(), map( @@ -345,6 +347,20 @@ mod tests { println!("Parsed output is {:?}", r); assert!(r.is_ok()) } + + #[test] + fn verify_parsing_error() { + // No place holder variable is found + let sample1 = "Some random text"; + + let entry_fields = HashMap::default(); + + let r = parse_auto_type_sequence(sample1, &entry_fields); + + println!("Parsed output is {:?}", r); + + assert!(r.is_err()) + } } /* // Gets the delay to use between the key presses to x milliseconds diff --git a/src/main/onekeepass/frontend/background.cljs b/src/main/onekeepass/frontend/background.cljs index 28dbcf8..9f0cb87 100644 --- a/src/main/onekeepass/frontend/background.cljs +++ b/src/main/onekeepass/frontend/background.cljs @@ -218,9 +218,10 @@ using custom key transformer " [entry] - (let [keys_exclude (-> entry (get "section_fields") keys vec) + (let [keys-exclude (-> entry (get "section_fields") keys vec) + keys-exclude (into keys-exclude (-> entry (get "parsed_fields") keys vec)) t-fn (fn [k] - (if (contains-val? keys_exclude k) + (if (contains-val? keys-exclude k) k (csk/->kebab-case-keyword k)))] (cske/transform-keys t-fn entry))) diff --git a/src/main/onekeepass/frontend/entry_form_ex.cljs b/src/main/onekeepass/frontend/entry_form_ex.cljs index 26c21fd..e9d31ff 100644 --- a/src/main/onekeepass/frontend/entry_form_ex.cljs +++ b/src/main/onekeepass/frontend/entry_form_ex.cljs @@ -1,73 +1,69 @@ (ns onekeepass.frontend.entry-form-ex - (:require [clojure.string :as str] - [onekeepass.frontend.common-components :as cc :refer [list-items-factory - selection-autocomplete - tags-field]] - [onekeepass.frontend.constants :as const :refer [ADDITIONAL_ONE_TIME_PASSWORDS - ONE_TIME_PASSWORD_TYPE - STANDARD_ENTRY_TYPES]] - [onekeepass.frontend.db-icons :as db-icons :refer [entry-icon - entry-type-icon]] - [onekeepass.frontend.entry-form.common :as ef-cmn :refer [ENTRY_DATETIME_FORMAT - theme-content-sx]] - [onekeepass.frontend.entry-form.dialogs :as dlg :refer [add-modify-section-field-dialog - add-modify-section-popper - attachment-delete-confirm-dialog - custom-field-delete-confirm - custom-section-delete-confirm - clone-entry-options-dialog - delete-all-confirm-dialog - delete-confirm-dialog - delete-permanent-dialog - delete-totp-confirm-dialog - icons-dialog - icons-dialog-flag - restore-confirm-dialog - set-up-totp-dialog - show-icons-dialog]] - [onekeepass.frontend.entry-form.fields :refer [datetime-field - otp-field - simple-selection-field - text-area-field - text-field]] - [onekeepass.frontend.entry-form.menus :as menus] - [onekeepass.frontend.events.common :as ce] - [onekeepass.frontend.events.entry-form-dialogs :as dlg-events] - [onekeepass.frontend.events.entry-form-ex :as form-events] - [onekeepass.frontend.events.move-group-entry :as move-events] - [onekeepass.frontend.group-tree-content :as gt-content] - [onekeepass.frontend.mui-components :as m :refer [custom-theme-atom - mui-alert - mui-avatar - mui-box - mui-button - mui-button - mui-divider - mui-icon-add-circle-outline-outlined - mui-icon-article-outlined - mui-icon-button - mui-icon-button - mui-icon-delete-outline - mui-icon-edit-outlined - mui-icon-save-as-outlined - mui-link - mui-list-item - mui-list-item-avatar - mui-list-item-text - mui-list-item-text - mui-menu-item - mui-stack - mui-text-field - mui-tooltip - mui-typography - theme-color]] - [onekeepass.frontend.translation :as t :refer-macros [tr-bl tr-l tr-h tr-t - tr-entry-field-name-cv - tr-entry-section-name-cv - tr-entry-type-title-cv]] - [onekeepass.frontend.utils :as u :refer [contains-val? - to-file-size-str]] - [reagent.core :as r])) + (:require + [clojure.string :as str] + [onekeepass.frontend.common-components :as cc :refer [list-items-factory + selection-autocomplete + tags-field]] + [onekeepass.frontend.constants :as const :refer [ADDITIONAL_ONE_TIME_PASSWORDS + IFDEVICE + ONE_TIME_PASSWORD_TYPE + PASSWORD + STANDARD_ENTRY_TYPES URL + USERNAME]] + [onekeepass.frontend.db-icons :as db-icons :refer [entry-icon + entry-type-icon]] + [onekeepass.frontend.entry-form.common :as ef-cmn :refer [ENTRY_DATETIME_FORMAT + theme-content-sx]] + [onekeepass.frontend.entry-form.dialogs :as dlg :refer [add-modify-section-field-dialog + add-modify-section-popper + attachment-delete-confirm-dialog + clone-entry-options-dialog + custom-field-delete-confirm + custom-section-delete-confirm + delete-all-confirm-dialog + delete-confirm-dialog + delete-permanent-dialog + delete-totp-confirm-dialog + icons-dialog + icons-dialog-flag + restore-confirm-dialog + set-up-totp-dialog + show-icons-dialog]] + [onekeepass.frontend.entry-form.fields :refer [datetime-field otp-field + simple-selection-field + text-area-field text-field]] + [onekeepass.frontend.entry-form.menus :as menus] + [onekeepass.frontend.events.common :as ce] + [onekeepass.frontend.events.entry-form-dialogs :as dlg-events] + [onekeepass.frontend.events.entry-form-ex :as form-events] + [onekeepass.frontend.events.move-group-entry :as move-events] + [onekeepass.frontend.group-tree-content :as gt-content] + [onekeepass.frontend.mui-components :as m :refer [custom-theme-atom + mui-alert mui-avatar + mui-box mui-button + mui-button mui-divider + mui-icon-add-circle-outline-outlined + mui-icon-article-outlined + mui-icon-button + mui-icon-button + mui-icon-delete-outline + mui-icon-edit-outlined + mui-icon-save-as-outlined + mui-link mui-list-item + mui-list-item-avatar + mui-list-item-text + mui-list-item-text + mui-menu-item mui-stack + mui-text-field + mui-tooltip + mui-typography + theme-color]] + [onekeepass.frontend.translation :as t :refer-macros [tr-bl tr-l tr-h tr-t + tr-entry-field-name-cv + tr-entry-section-name-cv + tr-entry-type-title-cv]] + [onekeepass.frontend.utils :as u :refer [contains-val? to-file-size-str]] + [reagent.core :as r])) ;;(set! *warn-on-infer* true) @@ -88,6 +84,13 @@ ;;(println "e is " (-> e .-target .-value)) (handler-name (-> e .-target .-value)))) +(defn read-value-from-parsed + ([field-name parsed-fields default-value] + (let [v (get parsed-fields (-> field-name name str/upper-case))] + (if-not (nil? v) v default-value))) + ([field-name parsed-fields] + (get parsed-fields (-> field-name name str/upper-case)))) + ;;;;;;;;;;;;;;;;;;;;;; Menu ;;;;;;;;;;;;;;;; ;; Re-exported for use in entry-list #_{:clj-kondo/ignore [:redefined-var]} @@ -281,29 +284,36 @@ #_[custom-field-delete-confirm @(form-events/field-delete-dialog-data)] #_[custom-section-delete-confirm @(form-events/section-delete-dialog-data)]])))) -(defn get-section-data +(defn get-section-data "Called to set up any entry type specific data in kv Returns an vec of kvd map for a section " - [entry-type-uuid section-name section-fields] - (let [section-data (get section-fields section-name)] + [entry-type-uuid section-name section-fields parsed-fields] + (let [section-data (get section-fields section-name)] (if (not= entry-type-uuid const/UUID_OF_ENTRY_TYPE_AUTO_OPEN) - section-data + (let [adjusted-section-data (mapv (fn [{:keys [key] :as m}] - (cond - (= key const/URL) - ;; for now read-value is not used - (assoc m :field-name "KDBX file to open" :read-value (:url-field-value m) ) - - ;; for now read-value is not used - (= key const/USERNAME) - (assoc m :field-name "Key file" :read-value (:key-file-path m)) - - (= key const/IFDEVICE) - (assoc m :field-name "Device ids to include or exclude") - - :else - m)) section-data)] + (assoc m :read-value (read-value-from-parsed key parsed-fields))) + section-data)] + adjusted-section-data) + (let [adjusted-section-data (mapv (fn [{:keys [key] :as m}] + (cond + (= key URL) + ;; for now read-value is not used + ;;:read-value (:url-field-value m) + (assoc m :field-name "KDBX file to open") + + (= key USERNAME) + (assoc m :field-name "Key file" :read-value (read-value-from-parsed key parsed-fields)) ;; :read-value (:key-file-path m) + + (= key PASSWORD) + (assoc m :read-value (read-value-from-parsed key parsed-fields)) + + (= key IFDEVICE) + (assoc m :field-name "Device ids to include or exclude") + + :else + m)) section-data)] adjusted-section-data)))) (defn all-sections-content @@ -312,7 +322,8 @@ (let [{:keys [edit showing] {:keys [entry-type-uuid section-names section-fields uuid group-uuid]} :data} @(form-events/entry-form-all) - deleted? @(form-events/is-entry-parent-group-deleted group-uuid)] + deleted? @(form-events/is-entry-parent-group-deleted group-uuid) + parsed-fields @(form-events/entry-form-data-fields :parsed-fields)] (m/react-use-effect (fn [] #_(println "init - uuid showing edit deleted? : \n" uuid showing edit deleted?) @@ -332,8 +343,9 @@ (for [section-name section-names] ^{:key section-name} [section-content {:entry-type-uuid entry-type-uuid :edit edit + :parsed-fields parsed-fields :section-name section-name - :section-data (get-section-data entry-type-uuid section-name section-fields) #_(get section-fields section-name) + :section-data (get-section-data entry-type-uuid section-name section-fields parsed-fields) #_(get section-fields section-name) :group-uuid group-uuid}]))])) (defn title-with-icon-field [] @@ -500,6 +512,9 @@ (defn entry-content [] (fn [] (let [title @(form-events/entry-form-data-fields :title) + parsed-fields @(form-events/entry-form-data-fields :parsed-fields) + title (read-value-from-parsed :title parsed-fields title) + icon-id @(form-events/entry-form-data-fields :icon-id) entry-uuid @(form-events/entry-form-data-fields :uuid) edit @(form-events/form-edit-mode) From 3dbe9af48bd6a58ac224e84efb46005ca06b3a03 Mon Sep 17 00:00:00 2001 From: jeyasankar Date: Sun, 2 Feb 2025 09:00:14 -0800 Subject: [PATCH 08/15] Username and Password can use reference wheile cloning; entry selected from search result is focused properly;fixed some camelCase conversion issues --- resources/public/translations/en.json | 8 + src-tauri/src/app_preference.rs | 30 ++-- .../onekeepass/frontend/app_settings.cljs | 6 +- src/main/onekeepass/frontend/background.cljs | 55 ++++--- .../frontend/common_components.cljs | 60 +++++--- src/main/onekeepass/frontend/constants.cljs | 2 +- src/main/onekeepass/frontend/db_icons.cljs | 9 +- .../frontend/entry_form/dialogs.cljs | 30 ++-- .../frontend/entry_form/fields.cljs | 142 ++++++++++++------ .../onekeepass/frontend/entry_form_ex.cljs | 61 ++++---- src/main/onekeepass/frontend/entry_list.cljs | 12 +- .../onekeepass/frontend/events/auto_type.cljs | 8 + .../onekeepass/frontend/events/common.cljs | 15 ++ .../frontend/events/entry_form_auto_open.cljs | 37 ++--- .../frontend/events/entry_form_common.cljs | 11 ++ .../frontend/events/entry_form_dialogs.cljs | 9 +- .../frontend/events/entry_form_ex.cljs | 15 +- .../frontend/events/entry_list.cljs | 51 +++++-- .../onekeepass/frontend/mui_components.cljs | 3 + src/main/onekeepass/frontend/okp_macros.clj | 3 +- src/main/onekeepass/frontend/search.cljs | 42 ++++-- src/main/onekeepass/frontend/translation.clj | 1 + src/main/onekeepass/frontend/translation.cljs | 12 +- 23 files changed, 407 insertions(+), 215 deletions(-) diff --git a/resources/public/translations/en.json b/resources/public/translations/en.json index 8186541..d3b0e67 100644 --- a/resources/public/translations/en.json +++ b/resources/public/translations/en.json @@ -6,6 +6,7 @@ "databaseSettingsChange": "Database settings change is in progress", "dbDisplayName": "Display name for your database", "entryTitle": "Title of this entry", + "doubleClickOnEntry": "Double click on an entry to see details", "entryTypeFields": "An entry's type determines available fields", "groupOrCategory": "An entry's group/category", "invalidOtpUrl": "Invalid otp url. No token is generated", @@ -14,7 +15,9 @@ "keyFileWillBeRemoved": "You are removing the use of key file", "keyFileWillBeUsed": "Key file will be used in master key", "keyOrAuthurl": "Please enter encoded key or full TOTPAuth URL", + "noOfEntriesFound": "Number of entries found", "noEntrySelected": "No entry content is selected. Select or create a new one", + "noMatchingEntryFound": "No matching entry is found", "passwordForYourDb": "Password for your database", "passwordIsChanged": "Password is removed and is not used in master key", "passwordNotUsed": "Password is removed and is not used in master key", @@ -145,6 +148,7 @@ "tokenlength": "Token length", "types": "Types", "upperCaseAZ": "Uppercase (A-Z)", + "useRefForUsernamePassword":"Use references for username and password", "uuid": "Uuid", "veryDangerous": "Very Dangerous", "veryStrong": "Very Strong", @@ -207,6 +211,7 @@ } }, "entryTypeTitles": { + "autoDatabaseOpen": "Auto Database Open", "bankAccount": "Bank Account", "credit/DebitCard": "Credit/Debit Card", "login": "Login", @@ -219,6 +224,9 @@ "additionalUrLs": "Additional URLs", "addressLine1": "Address Line1", "addressLine2": "Address Line2", + "autoOpenKdbxFileOpen": "KDBX file to open", + "autoOpenKeyFile": "Key file", + "autoOpenIfDevice": "Device ids to include or exclude", "bankCode/RoutingNumber": "Bank Code/Routing number", "baseStationNameOrSsid": "Base Station Name or SSID", "brand": "Brand", diff --git a/src-tauri/src/app_preference.rs b/src-tauri/src/app_preference.rs index ed26471..c7571b0 100644 --- a/src-tauri/src/app_preference.rs +++ b/src-tauri/src/app_preference.rs @@ -1,13 +1,15 @@ -use log::{error, info}; use serde::{Deserialize, Serialize}; use std::fs; use crate::{ - app_paths::app_backup_dir, constants::{standard_file_names::APP_PREFERENCE_FILE, themes::LIGHT}, password_gen_preference::PasswordGeneratorPreference, translation + app_paths::app_backup_dir, + constants::{standard_file_names::APP_PREFERENCE_FILE, themes::LIGHT}, + password_gen_preference::PasswordGeneratorPreference, + translation, }; -use onekeepass_core::db_service as kp_service; use crate::app_paths::app_home_dir; +use onekeepass_core::db_service as kp_service; #[derive(Clone, Serialize, Deserialize, Debug)] pub struct BackupPreference { @@ -31,7 +33,7 @@ pub struct PreferenceData { pub default_entry_category_groupings: Option, pub theme: Option, pub language: Option, - pub pass_phrase_options:Option, + pub pass_phrase_options: Option, } // Old preference used before introduction of fields clipboard_timeout,theme ,language // Leaving it here for documentation purpose only @@ -45,7 +47,7 @@ pub struct PreferenceData { // pub backup: BackupPreference, // } -// Old preference used in the earlier version v0.14.0 +// Old preference used in the earlier version v0.14.0 #[derive(Clone, Serialize, Deserialize, Debug)] pub struct Preference1 { pub version: String, @@ -84,7 +86,7 @@ pub struct Preference { pub backup: BackupPreference, - pub password_gen_preference:PasswordGeneratorPreference, + pub password_gen_preference: PasswordGeneratorPreference, } impl Default for Preference { @@ -101,7 +103,7 @@ impl Default for Preference { default_entry_category_groupings: "Groups".into(), recent_files: vec![], backup: BackupPreference::default(), - password_gen_preference:PasswordGeneratorPreference::default(), + password_gen_preference: PasswordGeneratorPreference::default(), } } } @@ -170,7 +172,6 @@ impl Preference { fn read_previous_preference(pref_str: &str) -> Option { if let Ok(p1) = toml::from_str::(&pref_str) { - // As the logging is not enabled, we will see this logging output // info!("Found previous version of Preference and using that"); #[cfg(feature = "onekeepass-dev")] @@ -185,7 +186,7 @@ impl Preference { p.language = p1.language; p.theme = p1.theme; p.clipboard_timeout = p1.clipboard_timeout; - + Some(p) } else { None @@ -220,14 +221,17 @@ impl Preference { let toml_str_result = toml::to_string(self); if let Ok(toml_str) = toml_str_result { if let Err(err) = fs::write(pref_file_name, toml_str.as_bytes()) { - error!("Prefernce write failed and error is {}", err.to_string()); + log::error!("Prefernce write failed and error is {}", err.to_string()); } } } // Update the preference with any non null values pub fn update(&mut self, preference_data: PreferenceData) { - // TODO: Need to have a 'macro' for this + // debug!("Preference update is called {:?}",&preference_data); + // debug!("Preference before {:?}",&self); + + // TODO: Need to have a 'macro' for this let mut updated = false; if let Some(v) = preference_data.language { self.language = v; @@ -258,7 +262,7 @@ impl Preference { self.password_gen_preference.update_pass_phrase_options(v); updated = true; } - + // debug!("Preference after updated {}, {:?}",updated,&self); if updated { self.write_toml(); } @@ -283,7 +287,7 @@ impl Preference { let pref_file_name = app_home_dir().join("preference.json"); if let Ok(json_str) = json_str_result { if let Err(err) = fs::write(pref_file_name, json_str.as_bytes()) { - error!("Prefernce write failed and error is {}", err.to_string()); + log::error!("Prefernce write failed and error is {}", err.to_string()); } } } diff --git a/src/main/onekeepass/frontend/app_settings.cljs b/src/main/onekeepass/frontend/app_settings.cljs index 3f6236e..d157efd 100644 --- a/src/main/onekeepass/frontend/app_settings.cljs +++ b/src/main/onekeepass/frontend/app_settings.cljs @@ -47,11 +47,15 @@ (def entry-groupings [{:name "Groups" :value "Groups"} {:name "Categories" :value "Categories"} {:name "Types" :value "Types"} {:name "Tags" :value "Tags"}]) +;; Here we list all lanaguages that we support. +;; We need to have the corresponding translation json files in the dir resources/public/translations +;; See translation.rs for the backend loading of these json files (def languages [{:name "en - English" :value "en"} {:name "es - Español" :value "es"} + {:name "de - Deutsch" :value "de"} + {:name "zh - 中文" :value "zh"} #_{:name "fr - Français" :value "fr"}]) - (defn- user-interface "Incoming settings map has nested maps and are destructred" [{:keys [_error-fields] diff --git a/src/main/onekeepass/frontend/background.cljs b/src/main/onekeepass/frontend/background.cljs index 9f0cb87..214b32f 100644 --- a/src/main/onekeepass/frontend/background.cljs +++ b/src/main/onekeepass/frontend/background.cljs @@ -8,7 +8,7 @@ [camel-snake-kebab.core :as csk] [onekeepass.frontend.utils :refer [contains-val?]] - [onekeepass.frontend.background-common :as bg-cmn :refer [to-snake-case]] + [onekeepass.frontend.background-common :as bg-cmn ] [onekeepass.frontend.background-password :as bg-pwd] ;; All tauri side corresponding endpoint command apis can be found in @@ -201,14 +201,30 @@ `allEntries`, `favourites`, `deleted`, `{:group \"valid uuid\"}`, `{:entry-type-uuid \"9e644c27-d00b-4aca-8355-5078c5a4fb44\"}` - `{:tag \"Bank\"}`, + `{:tag \"Bank\"}`, + + Returns a vec of maps (struct EntrySummary) " - [db-key entry-category dispatch-fn] - (invoke-api "entry_summary_data" - {:db-key db-key :entry-category - (if (map? entry-category) - entry-category - (csk/->camelCaseString entry-category))} dispatch-fn :convert-response true)) + [db-key entry-category dispatch-fn] + ;; We need to do a custom conversion of request because of the use of #[serde(rename_all = "camelCase")] + ;; for the enum 'EntryCategory'. This was done during very early time and needs the following fix + ;; fix mentioned in TODO + ;; TODO: + ;; We need to fix this and change it to use serde attribute tag and content + ;; Changes to be done for both Desktop and Mobile same time if we change this in enum EntryCategory + (let [args (clj->js {:dbKey db-key + :entryCategory + (if (map? entry-category) + (cske/transform-keys csk/->camelCaseString entry-category) + (csk/->camelCaseString entry-category))})] + ;; We must pass :convert-request false as we have done all conversions of args + (invoke-api "entry_summary_data" args dispatch-fn :convert-request false :convert-response true)) + ;; Leaving the old one before the introduction of 'as-tauri-args' + #_(invoke-api "entry_summary_data" + {:db-key db-key :entry-category + (if (map? entry-category) + entry-category + (csk/->camelCaseString entry-category))} dispatch-fn :convert-response true)) (defn history-entries-summary [db-key entry-uuid dispatch-fn] (invoke-api "history_entries_summary" {:db-key db-key :entry-uuid entry-uuid} dispatch-fn)) @@ -292,13 +308,9 @@ [db-key entry-uuid entry-clone-option dispatch-fn] ;; All args for tauri api are in cameCase. ;; But keys in 'entry-clone-option' map (passed as value in :entryCloneOption) - ;; are to be in snake_case - (invoke-api "clone_entry" (clj->js - {:dbKey db-key - :entryUuid entry-uuid - :entryCloneOption (->> entry-clone-option (cske/transform-keys csk/->snake_case))}) + ;; are to be in snake_case - see the use of 'as-tauri-args' to take care of this + (invoke-api "clone_entry" {:db-key db-key :entry-uuid entry-uuid :entry-clone-option entry-clone-option} dispatch-fn - :convert-request false ;; clone_entry api call returns clone entry's uuid string ;; and the usual conversion should not be used on this uuid string :convert-response false)) @@ -312,9 +324,10 @@ "Called to update the group data in the backend storage" [db-key group dispatch-fn] ;;(println "Going to update group..." group) - (let [args (clj->js {:dbKey db-key - :group (->> group (cske/transform-keys csk/->snake_case))})] - (invoke-api "update_group" args dispatch-fn :convert-request false))) + (invoke-api "update_group" {:db-key db-key :group group} dispatch-fn) + #_(let [args (clj->js {:dbKey db-key + :group (->> group (cske/transform-keys csk/->snake_case))})] + (invoke-api "update_group" args dispatch-fn :convert-request false))) (defn insert-group [db-key group dispatch-fn] (let [args (clj->js {:dbKey db-key @@ -467,9 +480,11 @@ (invoke-api "system_info_with_preference" {} dispatch-fn)) (defn update-preference [preference-data dispatch-fn] - (let [args (clj->js {:preferenceData (->> preference-data (cske/transform-keys csk/->snake_case))})] + (invoke-api "update_preference" {:preference-data preference-data} dispatch-fn :convert-response false) + #_(let [args (clj->js {:preferenceData (->> preference-data (cske/transform-keys csk/->snake_case))})] ;; We transform args to statisfy the requirements of arg name to tauri command should be in cameCase ;; and field names of preference-data should be snake_case + (println "update-preference is called " preference-data) (invoke-api "update_preference" args dispatch-fn :convert-response false))) (defn clear-recent-files [dispatch-fn] @@ -562,7 +577,9 @@ (invoke-api "platform_window_titles" {} dispatch-fn)) (defn active-window-to-auto-type - "Gets the top most window to which auto type sequence will be sent" + "Gets the top most window to which auto type sequence will be sent. + Returns a map (struct WindowInfo) in response + " [dispatch-fn] (invoke-api "active_window_to_auto_type" {} dispatch-fn)) diff --git a/src/main/onekeepass/frontend/common_components.cljs b/src/main/onekeepass/frontend/common_components.cljs index cd4b2bd..307fc1f 100644 --- a/src/main/onekeepass/frontend/common_components.cljs +++ b/src/main/onekeepass/frontend/common_components.cljs @@ -24,7 +24,8 @@ react-use-state]] [onekeepass.frontend.translation :refer-macros [tr-bl] :refer [lstr-sm]] [onekeepass.frontend.utils :refer [contains-val? str->int]] - [reagent.core :as r])) + [reagent.core :as r] + [reagent.ratom])) #_(set! *warn-on-infer* true) @@ -248,8 +249,9 @@ This 'row-item-fn' is the returned value of the function of 'render-row-factory' The various options are passed in the map 'options' " - [items row-item-fn {:keys [item-size list-style div-style] + [items row-item-fn {:keys [item-size scroll-to-item-index list-style div-style] :or {item-size 60 + scroll-to-item-index 0 div-style {} list-style {:max-width 275}}}] ;; This component makes use of 'fixed-size-list' and 'auto-sizer' (Function-as-child Components) @@ -265,21 +267,28 @@ ;; Need to set this so that splitpane's left side has some min width when content is small [:div {:style (merge {:min-width 200 :height "100%" :width "275"} div-style)} ;;AutoSizer needs to be a child of div for its to work within a flex container - (when (not-empty @items) - [auto-sizer {} - ;; auto-sizer child should be a function - (fn [dims] - (let [dims (js->clj dims :keywordize-keys true)] - ;; (println "dims are " dims) - (r/as-element - [:div {:style {:min-width 200 :height (:height dims)}} - [fixed-size-list {:style list-style ;;{:max-width 275} ;; Need to set this so that splitpane's left side does not expand - :height (:height dims) - :width (:width dims) - ;; this is the size of the row component returned by render-row fn - :itemSize item-size - :itemCount (count @items) - :overscanCount 1} row-item-fn]])))])])) + (let [list-items (if (instance? reagent.ratom/Reaction items) @items items)] + (when (not-empty list-items) #_(not-empty @items) + [auto-sizer {} + ;; auto-sizer child should be a function + (fn [dims] + (let [dims (js->clj dims :keywordize-keys true)] + ;; (println "dims are " dims) + (r/as-element + [:div {:style {:min-width 200 :height (:height dims)}} + [fixed-size-list {:style list-style ;;{:max-width 275} ;; Need to set this so that splitpane's left side does not expand + :height (:height dims) + :width (:width dims) + ;; this is the size of the row component returned by render-row fn + :itemSize item-size + :overflow-y "scroll" + ;; Need to get ref to access methods scrollToItem or scrollTo + ;; See https://react-window.vercel.app/#/api/FixedSizeList + ;; See https://react-window.vercel.app/#/examples/list/scroll-to-item + :ref (fn [^js/Ref e] + (some-> e (.scrollToItem scroll-to-item-index))) + :itemCount (count list-items) + :overscanCount 1} row-item-fn]])))]))])) (defn list-items-factory "Returns a function that can be used as a child in fixed-size-list. @@ -522,7 +531,7 @@ with supplied arg 'field-name-kw' and the event value Returns a function that can be used in a on-change handler of a text field " - ([handler-name field-name-kw int-val] + ([handler-name field-name-kw int-val] (fn [^js/Event e] (let [val (-> e .-target .-value) ;; Need to ensure that length is an int as expected by backend api @@ -532,7 +541,10 @@ (on-change-factory handler-name field-name-kw false))) (defn on-check-factory - "Called in on-change handler of a check field" + "Called in on-change handler of a check field. + Returns a fn that accepts check event + and this fn in turn calls the 'handler-name' fn with 'field-name-kw' and value + " [handler-name field-name-kw] (fn [e] (handler-name field-name-kw (-> e .-target .-checked)))) @@ -595,4 +607,12 @@ (fn [^js/Event e] (reset! anchor-el nil) (apply action action-args) - (.stopPropagation ^js/Event e))) \ No newline at end of file + (.stopPropagation ^js/Event e))) + + +#_(fn [e] (println "ref is called ..." (when-not (nil? e) + (js/Object.getOwnPropertyNames e) + (println " ref acess " (-> e (.scrollToItem 1)) + #_(-> e .-state .-instance js/Object.entries #_js/Object.getOwnPropertyNames) + #_(-> e js/Object.entries) + #_(js/Object.entries (.-_outerRef e)))))) \ No newline at end of file diff --git a/src/main/onekeepass/frontend/constants.cljs b/src/main/onekeepass/frontend/constants.cljs index e47cb6b..1a0e3af 100644 --- a/src/main/onekeepass/frontend/constants.cljs +++ b/src/main/onekeepass/frontend/constants.cljs @@ -14,7 +14,7 @@ (def WIRELESS_ROUTER_TYPE_NAME "Wireless Router") (def PASSPORT_TYPE_NAME "Passport") (def BANK_ACCOUNT_TYPE_NAME "Bank Account") -(def AUTO_DB_OPEN "Auto/Child Database Open") +(def AUTO_DB_OPEN "Auto Database Open") ;; This list is used in Entry Type select menu items on the new entry form (def STANDARD_ENTRY_TYPES [LOGIN_TYPE_NAME diff --git a/src/main/onekeepass/frontend/db_icons.cljs b/src/main/onekeepass/frontend/db_icons.cljs index 0110d4b..4043b9c 100644 --- a/src/main/onekeepass/frontend/db_icons.cljs +++ b/src/main/onekeepass/frontend/db_icons.cljs @@ -7,6 +7,7 @@ mui-icon-vpn-key-outlined mui-icon-credit-card-outlined mui-icon-flight-takeoff-outlined + mui-icon-launch mui-icon-login-outlined mui-icon-wifi-outlined mui-icon-account-balance-outlined]])) @@ -774,17 +775,19 @@ :display "flex" :alignItems "center"}} (get all-icons index [mui-icon-vpn-key-outlined])])) -(def entry-type-icons-m "Icons shown while showing entry types in category panel" +(def entry-type-icons-m + "Icons shown while showing entry types in category panel" {const/LOGIN_TYPE_NAME mui-icon-login-outlined const/CREDIT_DEBIT_CARD_TYPE_NAME mui-icon-credit-card-outlined const/BANK_ACCOUNT_TYPE_NAME mui-icon-account-balance-outlined const/WIRELESS_ROUTER_TYPE_NAME mui-icon-wifi-outlined - const/PASSPORT_TYPE_NAME mui-icon-flight-takeoff-outlined}) + const/PASSPORT_TYPE_NAME mui-icon-flight-takeoff-outlined + const/AUTO_DB_OPEN mui-icon-launch}) (defn entry-type-icon "Resturns an as form-1 reagent component for the given name" [name icon-name] - (let [icon (get entry-type-icons-m name)] + (let [icon (get entry-type-icons-m name)] (if icon [icon] [entry-icon (str->int icon-name)]))) diff --git a/src/main/onekeepass/frontend/entry_form/dialogs.cljs b/src/main/onekeepass/frontend/entry_form/dialogs.cljs index ddc0cc0..11a0625 100644 --- a/src/main/onekeepass/frontend/entry_form/dialogs.cljs +++ b/src/main/onekeepass/frontend/entry_form/dialogs.cljs @@ -3,10 +3,10 @@ [onekeepass.frontend.common-components :refer [alert-dialog-factory confirm-text-dialog enter-key-pressed-factory selection-autocomplete on-change-factory - on-check-factory]] + on-check-factory]] [onekeepass.frontend.db-icons :as db-icons] [onekeepass.frontend.entry-form.common :as ef-cmn :refer [popper-button-sx - theme-popper-box-sx]] + theme-popper-box-sx]] [onekeepass.frontend.events.entry-form-dialogs :as dlg-events] [onekeepass.frontend.events.entry-form-ex :as form-events] [onekeepass.frontend.events.move-group-entry :as move-events] @@ -352,6 +352,7 @@ new-title parent-group-uuid keep-histories + link-by-reference _error-fields]}] [mui-dialog {:open dialog-show :on-click #(.stopPropagation ^js/Event %) ;; This will set the Paper width in all child components @@ -365,18 +366,15 @@ ;;group-selection-field-error-text (:group-selection error-fields) title-error-text (when (str/blank? new-title) (tr-m entryForm cloneEntryTitleName))] [mui-dialog-content {:dividers true} - [mui-stack {:sx {:width "80%"}} + [mui-stack {:sx {:width "100%"}} [mui-stack {:direction "row" :sx {:width "100%" :margin-bottom "10px"}} [mui-text-field {:label (tr-l "newTitle") :value new-title :sx {} :error (not (nil? title-error-text)) - :helperText (if-not (nil? title-error-text) title-error-text nil #_(tr-h "entryTitle")) - :on-change (fn [^js/Event e] - (dlg-events/clone-entry-options-dialog-update - :new-title - (-> e .-target .-value))) + :helperText (if-not (nil? title-error-text) title-error-text nil) + :on-change (on-change-factory dlg-events/clone-entry-options-dialog-update :new-title) :InputProps {} :variant "standard" :fullWidth true}]] @@ -397,16 +395,20 @@ ;;:error-text group-selection-field-error-text }]] - [mui-stack {:sx {:width "50%"}} + [mui-stack {:direction "row" :sx {:justify-content "space-between" :width "100%"}} [mui-form-control-label {:control (r/as-element [mui-checkbox {:checked keep-histories - :on-change (fn [^js/Event e] - (dlg-events/clone-entry-options-dialog-update - :keep-histories - (-> e .-target .-checked)))}]) - :label (tr-l "keepHistories")}]]]]) + :on-change (on-check-factory dlg-events/clone-entry-options-dialog-update :keep-histories)}]) + :label (tr-l "keepHistories")}] + + [mui-form-control-label + {:control (r/as-element + [mui-checkbox + {:checked link-by-reference + :on-change (on-check-factory dlg-events/clone-entry-options-dialog-update :link-by-reference)}]) + :label (tr-l "useRefForUsernamePassword")}]]]]) [mui-dialog-actions [mui-button diff --git a/src/main/onekeepass/frontend/entry_form/fields.cljs b/src/main/onekeepass/frontend/entry_form/fields.cljs index 491d683..3fadca1 100644 --- a/src/main/onekeepass/frontend/entry_form/fields.cljs +++ b/src/main/onekeepass/frontend/entry_form/fields.cljs @@ -1,35 +1,75 @@ (ns onekeepass.frontend.entry-form.fields - (:require [clojure.string :as str] - [onekeepass.frontend.common-components :as cc :refer [theme-text-field-sx]] - [onekeepass.frontend.constants :as const :refer [OTP PASSWORD URL]] - [onekeepass.frontend.entry-form.common :as ef-cmn] - [onekeepass.frontend.events.entry-form-dialogs :as dlg-events] - [onekeepass.frontend.events.entry-form-ex :as form-events] - [onekeepass.frontend.mui-components :as m :refer [custom-theme-atom - mui-box - mui-circular-progress - mui-date-time-picker - mui-icon-autorenew - mui-icon-button - mui-icon-button - mui-icon-delete-outline - mui-icon-visibility - mui-icon-visibility-off - mui-input-adornment - mui-link - mui-localization-provider - mui-menu-item - mui-stack - mui-text-field - mui-tooltip - mui-typography]] - [onekeepass.frontend.translation :as t :refer [lstr-l-cv] :refer-macros [tr-h - tr-l - tr-l-cv - tr-entry-field-name-cv]] - [reagent.core :as r])) - -(defn- end-icons [key value protected visibile? edit] + (:require + [clojure.string :as str] + [onekeepass.frontend.common-components :as cc :refer [theme-text-field-sx]] + [onekeepass.frontend.constants :as const :refer [OTP PASSWORD URL]] + [onekeepass.frontend.entry-form.common :as ef-cmn] + [onekeepass.frontend.events.entry-form-dialogs :as dlg-events] + [onekeepass.frontend.events.entry-form-ex :as form-events] + [onekeepass.frontend.mui-components :as m :refer [custom-theme-atom mui-box + mui-circular-progress + mui-date-time-picker + mui-icon-autorenew + mui-icon-button + mui-icon-button + mui-icon-delete-outline + mui-icon-visibility + mui-icon-visibility-off + mui-input-adornment + mui-link + mui-localization-provider + mui-menu-item mui-stack + mui-text-field + mui-tooltip + mui-typography]] + #_[onekeepass.frontend.okp-macros :refer [as-map]] + [onekeepass.frontend.translation :as t :refer [lstr-l-cv] :refer-macros [tr-h + tr-l + tr-l-cv + tr-entry-field-name-cv]] + [reagent.core :as r])) + +(defn- to-value [{:keys [value read-value edit]}] + (cond + edit + value + + (and (not edit) (not (nil? read-value))) + read-value + + :else + value)) + +(defn- end-icons-1 [{:keys [key protected visibile edit] :as kv}] + (let [val (to-value kv)] + [:<> + (when protected + (if visibile + [mui-icon-button {:sx {:margin-right "-8px"} + :edge "end" + :on-click #(form-events/entry-form-field-visibility-toggle key)} + [mui-icon-visibility]] + [mui-icon-button {:sx {:margin-right "-8px"} + :edge "end" + :on-click #(form-events/entry-form-field-visibility-toggle key)} + [mui-icon-visibility-off]])) + ;; Open with the url + (when (= key URL) + [mui-icon-button {:sx {:margin-right "-8px"} + :edge "end" + :on-click #(form-events/entry-form-open-url val)} + [m/mui-icon-launch]]) + ;; Password generator + (when (and edit protected (= key PASSWORD)) + [mui-icon-button {:sx {:margin-right "-8px"} + :edge "end" + :on-click form-events/password-generator-show} + [mui-icon-autorenew]]) + ;; Copy + [(cc/copy-icon-factory) val {:sx {:mr "-1px"}}]])) + + +#_(defn- end-icons [key value protected visibile? edit] [:<> (when protected (if visibile? @@ -92,7 +132,7 @@ protected visible edit - on-change-handler + on-change-handler disabled password-score placeholder @@ -104,8 +144,9 @@ edit false no-end-icons false protected false - disabled false - on-change-handler #(println (str "No on change handler yet registered for the key"))}}] + disabled false + on-change-handler #(println (str "No on change handler yet registered for the key"))} + :as kv}] ;;:margin-top "16px" here is equivalent to the one used by "entry-cnt-field" (let [label (cond @@ -119,19 +160,19 @@ :else ;; It is assumed translation is done already key) - val (cond - edit - value + val (to-value kv) #_(cond + edit + value - (and (not edit) (not (nil? read-value))) - read-value + (and (not edit) (not (nil? read-value))) + read-value - :else - value)] + :else + value)] [m/text-field {:sx (merge {:margin-top "16px"} (cc/password-helper-text-sx (:name password-score))) - :fullWidth true + :fullWidth true :label label - :variant "standard" + :variant "standard" :value val :placeholder placeholder :error (not (nil? error-text)) @@ -144,7 +185,7 @@ :else error-text) - :onChange on-change-handler + :onChange on-change-handler :required false :disabled disabled :InputLabelProps {} @@ -153,7 +194,7 @@ :endAdornment (if no-end-icons nil (r/as-element [mui-input-adornment {:position "end"} - [end-icons key value protected visible edit] + [end-icons-1 kv] #_(seq icons)])) :type (if (or (not protected) visible) "text" "password")} ;;attributes for 'input' tag can be added here @@ -205,13 +246,14 @@ (defn otp-read-field "This is called only during read time and edit flag is false" - [_kv] + [_m] (fn [{:keys [key visible error-text no-end-icons] :or {visible true - no-end-icons false}}] + no-end-icons false} + :as kv}] (let [;; ensure that edit is always false edit false @@ -237,7 +279,11 @@ :endAdornment (if (or (not valid-token-found) no-end-icons) nil (r/as-element [mui-input-adornment {:position "end"} - [end-icons key token false visible edit]])) + #_[end-icons key token false visible edit] + [end-icons-1 (assoc kv + :value token + :read-value nil + :protected false)]])) :type "text"} :inputProps {:readOnly true}}] diff --git a/src/main/onekeepass/frontend/entry_form_ex.cljs b/src/main/onekeepass/frontend/entry_form_ex.cljs index e9d31ff..2480afb 100644 --- a/src/main/onekeepass/frontend/entry_form_ex.cljs +++ b/src/main/onekeepass/frontend/entry_form_ex.cljs @@ -35,7 +35,7 @@ [onekeepass.frontend.entry-form.menus :as menus] [onekeepass.frontend.events.common :as ce] [onekeepass.frontend.events.entry-form-dialogs :as dlg-events] - [onekeepass.frontend.events.entry-form-ex :as form-events] + [onekeepass.frontend.events.entry-form-ex :as form-events :refer [place-holder-resolved-value]] [onekeepass.frontend.events.move-group-entry :as move-events] [onekeepass.frontend.group-tree-content :as gt-content] [onekeepass.frontend.mui-components :as m :refer [custom-theme-atom @@ -58,10 +58,10 @@ mui-tooltip mui-typography theme-color]] - [onekeepass.frontend.translation :as t :refer-macros [tr-bl tr-l tr-h tr-t - tr-entry-field-name-cv - tr-entry-section-name-cv - tr-entry-type-title-cv]] + [onekeepass.frontend.translation :as t :refer [lstr-field-name] :refer-macros [tr-bl tr-l tr-h tr-t + tr-entry-field-name-cv + tr-entry-section-name-cv + tr-entry-type-title-cv]] [onekeepass.frontend.utils :as u :refer [contains-val? to-file-size-str]] [reagent.core :as r])) @@ -74,7 +74,7 @@ (handler-name field-name-kw (-> e .-target .-value)) (handler-name field-name-kw (-> e .-target .-checked))))) -(defn on-check-factory [handler-name field-name-kw] +#_(defn on-check-factory [handler-name field-name-kw] (fn [e] (handler-name field-name-kw (-> e .-target .-checked)))) @@ -84,13 +84,6 @@ ;;(println "e is " (-> e .-target .-value)) (handler-name (-> e .-target .-value)))) -(defn read-value-from-parsed - ([field-name parsed-fields default-value] - (let [v (get parsed-fields (-> field-name name str/upper-case))] - (if-not (nil? v) v default-value))) - ([field-name parsed-fields] - (get parsed-fields (-> field-name name str/upper-case)))) - ;;;;;;;;;;;;;;;;;;;;;; Menu ;;;;;;;;;;;;;;;; ;; Re-exported for use in entry-list #_{:clj-kondo/ignore [:redefined-var]} @@ -292,28 +285,34 @@ (let [section-data (get section-fields section-name)] (if (not= entry-type-uuid const/UUID_OF_ENTRY_TYPE_AUTO_OPEN) - (let [adjusted-section-data (mapv (fn [{:keys [key] :as m}] - (assoc m :read-value (read-value-from-parsed key parsed-fields))) - section-data)] + (let [adjusted-section-data (mapv + (fn [{:keys [key] :as m}] + (assoc m :read-value (place-holder-resolved-value parsed-fields key))) + section-data)] adjusted-section-data) - (let [adjusted-section-data (mapv (fn [{:keys [key] :as m}] - (cond - (= key URL) + (let [adjusted-section-data (mapv + (fn [{:keys [key] :as m}] + ;; Note the use of lstr-field-name vs tr-entry-field-name-cv + ;; lstr-field-name is fn and tr-entry-field-name-cv is a macro + (cond + (= key URL) ;; for now read-value is not used ;;:read-value (:url-field-value m) - (assoc m :field-name "KDBX file to open") - - (= key USERNAME) - (assoc m :field-name "Key file" :read-value (read-value-from-parsed key parsed-fields)) ;; :read-value (:key-file-path m) + (assoc m :field-name (tr-entry-field-name-cv "autoOpenKdbxFileOpen")) - (= key PASSWORD) - (assoc m :read-value (read-value-from-parsed key parsed-fields)) + (= key USERNAME) + (assoc m :field-name (lstr-field-name 'autoOpenKeyFile) + :read-value (place-holder-resolved-value parsed-fields key)) ;; :read-value (:key-file-path m) + + (= key PASSWORD) + (assoc m :read-value (place-holder-resolved-value parsed-fields key)) - (= key IFDEVICE) - (assoc m :field-name "Device ids to include or exclude") + (= key IFDEVICE) + (assoc m :field-name (tr-entry-field-name-cv "autoOpenIfDevice")) - :else - m)) section-data)] + :else + m)) + section-data)] adjusted-section-data)))) (defn all-sections-content @@ -328,7 +327,7 @@ (fn [] #_(println "init - uuid showing edit deleted? : \n" uuid showing edit deleted?) (when (and (= showing :selected) (not edit) (not deleted?)) - ;; (println "Will fire entry-form-otp-start-polling") + #_(println "Will fire entry-form-otp-start-polling") (form-events/entry-form-otp-start-polling)) (fn [] @@ -513,7 +512,7 @@ (fn [] (let [title @(form-events/entry-form-data-fields :title) parsed-fields @(form-events/entry-form-data-fields :parsed-fields) - title (read-value-from-parsed :title parsed-fields title) + title (place-holder-resolved-value parsed-fields :title title) icon-id @(form-events/entry-form-data-fields :icon-id) entry-uuid @(form-events/entry-form-data-fields :uuid) diff --git a/src/main/onekeepass/frontend/entry_list.cljs b/src/main/onekeepass/frontend/entry_list.cljs index ea7e53a..4dcd2d1 100644 --- a/src/main/onekeepass/frontend/entry_list.cljs +++ b/src/main/onekeepass/frontend/entry_list.cljs @@ -100,19 +100,23 @@ ;; A functional component to use react useEffect (defn fn-entry-list-content [] - (let [;; See common-components for :div-style use - entries (el-events/get-selected-entry-items) + (let [entries (el-events/get-selected-entry-items) + + ;; See common-components for :div-style use + item-index @(el-events/selected-entry-item-index) entry-items (list-items-factory entries - row-item :div-style {:min-width 225}) + row-item :div-style {:min-width 225} + :scroll-to-item-index item-index) recycle-bin? (gt-events/recycle-group-selected?) deleted-cat? (el-events/deleted-category-showing) group-in-recycle-bin? (gt-events/selected-group-in-recycle-bin?) + group-info @(el-events/initial-group-selection-info) entry-type-uuid @(el-events/selected-entry-type) disable-action (or @recycle-bin? @group-in-recycle-bin? @deleted-cat?) {:keys [key-name direction]} @(el-events/entry-list-sort-creteria) - entries-found? (> (count @entries) 1) #_(boolean (seq @entries)) + entries-found? (> (count @entries) 1) entry-type-uuid (if (nil? entry-type-uuid) UUID_OF_ENTRY_TYPE_LOGIN diff --git a/src/main/onekeepass/frontend/events/auto_type.cljs b/src/main/onekeepass/frontend/events/auto_type.cljs index 2ac65d0..dbca382 100644 --- a/src/main/onekeepass/frontend/events/auto_type.cljs +++ b/src/main/onekeepass/frontend/events/auto_type.cljs @@ -62,6 +62,7 @@ (assoc-in-key-db [:auto-type-perform-dialog :api-error-text] nil) (assoc-in-key-db [:auto-type-perform-dialog :error-fields] nil)))})) +;; Shows the dialog to send the sequence to an active window (reg-event-fx :perform-dialog-init (fn [{:keys [db]} [_event-id entry-uuid window-info auto-type-m]] @@ -73,6 +74,7 @@ (assoc-in-key-db [:auto-type-perform-dialog :api-error-text] nil) (assoc-in-key-db [:auto-type-perform-dialog :error-fields] nil))})) +;; Called to send the sequence to an active window (reg-event-fx :send-auto-sequence (fn [{:keys [db]} [_event-id]] @@ -96,11 +98,17 @@ {:fx [[:dispatch [:perform-dialog-show-close]] [:dispatch [:common/message-snackbar-open "Auto typing is completed"]]]})) +;; Backend call to get the active to which we will be sending the sequence +;; auto-type-m (or auto-type) is a map from struct AutoType (for tag AutoType) +;; auto-type is from entry-form-data + (reg-fx :auto-type/bg-active-window-to-auto-type (fn [[entry-uuid auto-type-m]] (bg/active-window-to-auto-type (fn [api-response] (when-let [window-info (check-error api-response)] + ;; window-info is a map from struct WindowInfo + ;; Shows the dialog to send the sequence to an active window (dispatch [:perform-dialog-init entry-uuid window-info auto-type-m])))))) (reg-sub diff --git a/src/main/onekeepass/frontend/events/common.cljs b/src/main/onekeepass/frontend/events/common.cljs index bd5710e..fc5f2ce 100644 --- a/src/main/onekeepass/frontend/events/common.cljs +++ b/src/main/onekeepass/frontend/events/common.cljs @@ -1046,6 +1046,21 @@ ;; and session timeout happens during that time :fx [[:dispatch [:db-settings/notify-screen-locked]]]}))) +;;;;;;;;;; Tauri shell open common calls ;;;;;;;;;;; +(reg-fx + :common/bg-open-url + (fn [[path]] + (bg/open-url path + (fn [api-response] + (on-error api-response))))) + +(reg-fx + :common/bg-open-file + (fn [[path]] + (bg/open-file path + (fn [api-response] + (on-error api-response))))) + ;;;;;;;;;;;;;;;;;;;;;;;;;; Common Dialog ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; TODO: diff --git a/src/main/onekeepass/frontend/events/entry_form_auto_open.cljs b/src/main/onekeepass/frontend/events/entry_form_auto_open.cljs index f343ea2..eee38d1 100644 --- a/src/main/onekeepass/frontend/events/entry_form_auto_open.cljs +++ b/src/main/onekeepass/frontend/events/entry_form_auto_open.cljs @@ -9,32 +9,29 @@ on-error]] [onekeepass.frontend.events.entry-form-common :refer [extract-form-field-names-values form-data-kv-data - get-form-data]] + get-form-data + place-holder-resolved-value]] [re-frame.core :refer [dispatch reg-event-fx reg-fx]])) (defn entry-form-open-url [url-value] (dispatch [:entry-form-open-url url-value])) -(reg-fx - :bg-open-url - (fn [[path]] - (bg/open-url path - (fn [api-response] - (on-error api-response))))) - (reg-event-fx :entry-form-open-url - (fn [{:keys [_db]} [_event-id url-value]] + (fn [{:keys [_db]} [_event-id url-value]] (cond (str/starts-with? url-value "kdbx:") {:fx [[:dispatch [:entry-form-auto-open-resolve-properties]]]} (or (str/starts-with? url-value "https://") (str/starts-with? url-value "http://")) - {:fx [[:bg-open-url [url-value]]]} + {:fx [[:common/bg-open-url [url-value]]]} + + (str/starts-with? url-value "file://") + {:fx [[:common/bg-open-file [url-value]]]} :else - {}))) + {:fx [[:common/bg-open-url [(str "https://" url-value)]]]}))) (def all-auto-open-kvd-keys [URL USERNAME IFDEVICE]) @@ -47,14 +44,17 @@ ;; (reg-event-fx :entry-form-auto-open-resolve-properties - (fn [{:keys [db]} [_event-id]] + (fn [{:keys [db]} [_event-id]] (let [{:keys [entry-type-uuid] :as form-data} (get-form-data db)] ;; Should entry-type-uuid check is required ? - (if (= entry-type-uuid const/UUID_OF_ENTRY_TYPE_AUTO_OPEN) + (if (= entry-type-uuid const/UUID_OF_ENTRY_TYPE_AUTO_OPEN) (let [field-m (extract-form-field-names-values form-data) + parsed-fields (:parsed-fields form-data) + url (place-holder-resolved-value parsed-fields URL (get field-m URL)) + key-file-path (place-holder-resolved-value parsed-fields USERNAME (get field-m USERNAME)) auto-props {:source-db-key (active-db-key db) - :url-field-value (get field-m URL) - :key-file-path (get field-m USERNAME) + :url-field-value url + :key-file-path key-file-path :device_if_val (get field-m const/IFDEVICE)}] {:fx [[:bg-resolve-auto-open-properties [auto-props (partial auto-open-properties-dispatch-fn all-auto-open-kvd-keys)]]]}) {})))) @@ -69,8 +69,11 @@ (fn [{:keys [db]} [_event-id _ao-keys {:keys [url-field-value key-file-path can-open]}]] (if (not can-open) {:fx [[:dispatch [:common/error-info-box-show {:title "Database auto open" :error-text "The device is excluded in opening this database url"}]]]} - (let [{:keys [value]} (form-data-kv-data (get-form-data db) PASSWORD)] - {:fx [[:dispatch [:open-db/auto-open-with-credentials url-field-value value key-file-path]]]})))) + (let [form-data (get-form-data db) + parsed-fields (:parsed-fields form-data) + {:keys [value]} (form-data-kv-data form-data PASSWORD) + password (place-holder-resolved-value parsed-fields PASSWORD value)] + {:fx [[:dispatch [:open-db/auto-open-with-credentials url-field-value password key-file-path]]]})))) (reg-event-fx :entry-form-auto-open-properties-resolve-error diff --git a/src/main/onekeepass/frontend/events/entry_form_common.cljs b/src/main/onekeepass/frontend/events/entry_form_common.cljs index 8009276..81a8e21 100644 --- a/src/main/onekeepass/frontend/events/entry_form_common.cljs +++ b/src/main/onekeepass/frontend/events/entry_form_common.cljs @@ -11,6 +11,17 @@ (def Favorites "Favorites") +(defn place-holder-resolved-value + "Gets the any place holder resolved value for a given field name + We can pass a 'default-value' value to use if 'parsed-fields' returns nil for this field + " + ([parsed-fields field-name default-value] + #_(println "place-holder-resolved-value is called") + (let [v (get parsed-fields (-> field-name name str/upper-case))] + (if-not (nil? v) v default-value))) + ([parsed-fields field-name ] + (get parsed-fields (-> field-name name str/upper-case)))) + (defn get-form-data "Gets the current form data of a currently opened db from the app-db" [app-db] diff --git a/src/main/onekeepass/frontend/events/entry_form_dialogs.cljs b/src/main/onekeepass/frontend/events/entry_form_dialogs.cljs index c5a6d4b..70a79b2 100644 --- a/src/main/onekeepass/frontend/events/entry_form_dialogs.cljs +++ b/src/main/onekeepass/frontend/events/entry_form_dialogs.cljs @@ -253,7 +253,8 @@ :new-title nil :parent-group-uuid nil :entry-uuid nil - :keep-histories false}) + :keep-histories false + :link-by-reference false}) (defn- init-clone-entry-options-dialog-data [db] (assoc-in-key-db db [:clone-entry-options-dialog] clone-entry-options-dialog-init-data)) @@ -284,11 +285,11 @@ :clone-entry-options-dialog-ok (fn [{:keys [db]} [_event-id]] (let [db-key (active-db-key db) - {:keys [entry-uuid new-title parent-group-uuid keep-histories]} + {:keys [entry-uuid new-title parent-group-uuid keep-histories link-by-reference]} (get-in-key-db db [:clone-entry-options-dialog])] {:fx [[:bg-clone-entry [db-key entry-uuid - (as-map [new-title parent-group-uuid keep-histories])]]]}))) + (as-map [new-title parent-group-uuid keep-histories link-by-reference])]]]}))) (reg-fx :bg-clone-entry @@ -312,7 +313,7 @@ [:dispatch [:entry-form-ex/find-entry-by-id cloned-entry-uuid]] [:dispatch [:clone-entry-options-dialog-close]] - [:dispatch [:common/message-snackbar-open (lstr-sm 'entryCloned) ]]]})) + [:dispatch [:common/message-snackbar-open (lstr-sm 'entryCloned)]]]})) (reg-event-fx :clone-entry-options-dialog-close diff --git a/src/main/onekeepass/frontend/events/entry_form_ex.cljs b/src/main/onekeepass/frontend/events/entry_form_ex.cljs index adb31c4..265d5f0 100644 --- a/src/main/onekeepass/frontend/events/entry_form_ex.cljs +++ b/src/main/onekeepass/frontend/events/entry_form_ex.cljs @@ -9,13 +9,16 @@ fix-tags-selection-prefix get-in-key-db on-error]] - [onekeepass.frontend.events.entry-form-common :refer [add-section-field + ;; Do not remove. Required to register otp evets + [onekeepass.frontend.events.entry-form-otp] + [onekeepass.frontend.events.entry-form-common :as ef-events-cmn :refer [add-section-field entry-form-key extract-form-field-names-values extract-form-otp-fields get-form-data - is-field-exist - merge-section-key-value]] ;; Need to be called here so that events are registered + is-field-exist + merge-section-key-value]] + ;; Need to be called here so that events are registered [onekeepass.frontend.events.entry-form-auto-open :as ao-events] [onekeepass.frontend.translation :refer [lstr-sm]] [onekeepass.frontend.utils :as u :refer [contains-val?]] @@ -26,6 +29,8 @@ (def entry-form-open-url ao-events/entry-form-open-url) +(def place-holder-resolved-value ef-events-cmn/place-holder-resolved-value) + ;;;;;;;;;;;;;;;;;;;;;; Support functions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defn- validate-entry-form-data @@ -1677,11 +1682,15 @@ (defn auto-type-perform-dialog-data [] (subscribe [:auto-type/perform-dialog])) +;; auto-type is map from struct AutoType of EntryFormData as wells as Entry (for tag AutoType) +;; Sometime we use 'auto-type-m' for 'auto-type' (reg-event-fx :entry-perform-auto-type (fn [{:keys [db]} [_event-id]] (let [{:keys [uuid auto-type]} (get-form-data db)] + ;; Backend call to get the active to which we will be sending the sequence {:fx [[:auto-type/bg-active-window-to-auto-type [uuid auto-type]]]}))) + (reg-event-fx :entry-auto-type-edit (fn [{:keys [db]} [_event-id]] diff --git a/src/main/onekeepass/frontend/events/entry_list.cljs b/src/main/onekeepass/frontend/events/entry_list.cljs index cec5bca..aac6536 100644 --- a/src/main/onekeepass/frontend/events/entry_list.cljs +++ b/src/main/onekeepass/frontend/events/entry_list.cljs @@ -53,6 +53,9 @@ (defn entry-list-sort-creteria [] (subscribe [:entry-list-sort-creteria])) +(defn selected-entry-item-index [] + (subscribe [:selected-entry-item-index])) + ;;;;;;;;;;;;;;;;;;;;;;; Entries sorting ;;;;;;;;;;;;;;;;;;;;;;;;;; (def sort-default-key-name const/TITLE) @@ -68,7 +71,7 @@ el-sort)))) (defn sort-entries [{:keys [key-name direction]} entries] - (sort-by + (sort-by ;; This is the key fn that provides keys for the comparion (fn [{:keys [title modified-time created-time]}] @@ -84,7 +87,7 @@ :else title)) - + ;; This is comparater for the keys (fn [v1 v2] (if (= direction const/ASCENDING) (compare v1 v2) @@ -115,8 +118,8 @@ (fn [{:keys [db]} [_event-id]] (let [curr-direction (get-in-key-db db [:entry-list :sort :direction])] {:db (assoc-in-key-db db [:entry-list :sort :direction] - (if (or (nil? curr-direction) (= curr-direction const/ASCENDING)) - const/DESCENDING + (if (or (nil? curr-direction) (= curr-direction const/ASCENDING)) + const/DESCENDING const/ASCENDING)) :fx [[:dispatch [:sort-entry-items]]]}))) @@ -165,6 +168,7 @@ {:db db :fx [#_[:dispatch [:entry-category/selected-category-title category]] [:dispatch [:entry-category/select-all-entries-category]] + [:dispatch [:group-tree-content/clear-group-selection]] [:dispatch [:entry-list/update-selected-entry-id entry-uuid]] [:dispatch [:entry-form-ex/find-entry-by-id entry-uuid]] [:load-bg-entry-summary-data [(active-db-key db) category]]]}))) @@ -182,32 +186,41 @@ (fn [[db-key category]] (bg/entry-summary-data db-key category (fn [api-response] - (when-let [result (check-error api-response)] - (dispatch [:entry-list-load-complete result category]))) + (when-let [entry-summaries-v (check-error api-response)] + (dispatch [:entry-list-load-complete entry-summaries-v category]))) #_(partial summary-entry-items-loaded category)))) ;; When a list of all entry summary data is loaded successfully, this is called (reg-event-fx :entry-list-load-complete - (fn [{:keys [db]} [_event-id result category]] + (fn [{:keys [db]} [_event-id entry-summaries-v category]] (let [current-selected-entry-id (get-in-key-db db [:entry-list :selected-entry-id]) - found (filter (fn [m] (= current-selected-entry-id (:uuid m))) result)] + ;; When user selects an entry (double click) in the search list, current-selected-entry-id is set and + ;; entry summary vec is loaded to show in 'entry-list'. + ;; We need to find the entry's index in that vec so that we can use that info to scroll to that item. + ;; In all other cases, the index is 0 + [item-index item] (as-> entry-summaries-v coll + (map-indexed (fn [idx item] [idx item]) coll) + (filter (fn [[_idx m]] (= current-selected-entry-id (:uuid m))) coll) + (first coll))] - {:db db + {:db (-> db (assoc-in-key-db [:entry-list :selected-entry-item-index] item-index)) :fx [;; Need to sort the loaded entry list as per the current sort creteria - [:dispatch [:update-selected-entry-items (sort-entries-with-creteria db result)]] - - [:dispatch [:update-category-source category]] - (if-not (boolean (seq found)) + [:dispatch [:update-selected-entry-items (sort-entries-with-creteria db entry-summaries-v)]] + [:dispatch [:update-category-source category]] + (if-not (boolean (seq item)) [:dispatch [:entry-form-ex/show-welcome]] - (dispatch [:entry-form-ex/find-entry-by-id current-selected-entry-id]))]}))) + ;; Following event is dipatched only when 'item' is non nil value ( search time ) + [:dispatch [:entry-form-ex/find-entry-by-id current-selected-entry-id]] + ;; Following will not work as we see warning on console "re-frame: in ":fx" effect found" + #_[[:dispatch [:entry-form-ex/find-entry-by-id current-selected-entry-id]]])]}))) ;; list of entry items returned by backend api when a category selected ;; or entry items returned in a search result - Work is yet to be done (reg-event-db :update-selected-entry-items - (fn [db [_event-id v]] - (assoc-in-key-db db [:entry-list :selected-entry-items] v))) + (fn [db [_event-id entry-summaries-v]] + (assoc-in-key-db db [:entry-list :selected-entry-items] entry-summaries-v))) ;; Sets the category-source that is selected in the category view (reg-event-db @@ -242,6 +255,12 @@ (fn [{:keys [entry-type-uuid]} _query-vec] entry-type-uuid)) +(reg-sub + :selected-entry-item-index + (fn [db [_query-id]] + (let [index (get-in-key-db db [:entry-list :selected-entry-item-index])] + (if-not (nil? index) index 0)))) + (comment @re-frame.db/app-db diff --git a/src/main/onekeepass/frontend/mui_components.cljs b/src/main/onekeepass/frontend/mui_components.cljs index 1a4eb8a..964839b 100644 --- a/src/main/onekeepass/frontend/mui_components.cljs +++ b/src/main/onekeepass/frontend/mui_components.cljs @@ -39,6 +39,7 @@ (def react-use-state (.-useState ^js/React react)) (def react-use-effect (.-useEffect ^js/React react)) +#_(def react-use-ref (.-useRef ^js/React react)) #_(def use-idle-timer (.-useIdleTimer ^js/ReactIdleTimer react-idle-timer)) @@ -159,6 +160,8 @@ :else (-> theme .-palette .-primary .-main))) +(defn get-theme-color [color-kw] + (theme-color @custom-theme-atom color-kw)) (declare set-colors) diff --git a/src/main/onekeepass/frontend/okp_macros.clj b/src/main/onekeepass/frontend/okp_macros.clj index 9bca096..193ee0f 100644 --- a/src/main/onekeepass/frontend/okp_macros.clj +++ b/src/main/onekeepass/frontend/okp_macros.clj @@ -3,7 +3,8 @@ ;; (macroexpand-1 '(as-map [a b])) => {:a a, :b b} ;; Here variables a and b are already set in the calling site (defmacro as-map - "Returns a map using the passed variable names" + "The arg 'variable-names' is a vec of symbols. + Returns a map using the passed variable names" [variable-names] (reduce (fn [m s] (assoc m (keyword s) s)) {} variable-names)) diff --git a/src/main/onekeepass/frontend/search.cljs b/src/main/onekeepass/frontend/search.cljs index 73d81b6..e8d84a3 100644 --- a/src/main/onekeepass/frontend/search.cljs +++ b/src/main/onekeepass/frontend/search.cljs @@ -4,7 +4,8 @@ [onekeepass.frontend.db-icons :refer [entry-icon]] [onekeepass.frontend.events.common :as cmn-events] [onekeepass.frontend.events.search :as sch-event] - [onekeepass.frontend.mui-components :as m :refer [mui-alert + [onekeepass.frontend.mui-components :as m :refer [mui-typography + mui-alert mui-avatar mui-button mui-dialog @@ -20,8 +21,9 @@ mui-list-item-secondary-action mui-list-item-text mui-stack - mui-tooltip]] - [onekeepass.frontend.translation :refer [tr-dlg-title tr-l]] + mui-tooltip + get-theme-color]] + [onekeepass.frontend.translation :refer [tr-dlg-title tr-l tr-h]] [reagent.core :as r])) #_(set! *warn-on-infer* true) @@ -36,7 +38,7 @@ item (nth @items (:index props)) selected-id (sch-event/selected-entry-id)] ;; Need to use mui-list-item-button instead of mui-list-item so that focus to the list works - ;; while using tab. The other places the tab navigation works when mui-list-item is used + ;; while using 'Tab' key. The other places the tab navigation works when mui-list-item is used ;; As per API doc mui-list-item autoFocus prop is deprecated and recommended to use mui-list-item-button [mui-list-item-button {:style (:style props) :divider true @@ -56,16 +58,16 @@ ;; e.g :primary (r/as-element [:span (str "Primary:" (:title item))]) {:primary (:title item) :secondary (:secondary-title item)}] - (when (= @selected-id (:uuid item)) + (when (= @selected-id (:uuid item)) [mui-list-item-secondary-action - [mui-tooltip {:title "Show Details" :enterDelay 2000} + [mui-tooltip {:title "Show Details" :enterDelay 2000} [mui-icon-button {:edge "end" :on-click (fn [] (sch-event/show-selected-entry-item (:uuid item)))} [mui-icon-more-vert]]]])]))) -(defn search-result-list-content [] - (let [result-items (list-items-factory (sch-event/search-result-entry-items) row-item :list-style {})] +(defn search-result-list-content [matched-entries] + (let [result-items (list-items-factory matched-entries #_(sch-event/search-result-entry-items) row-item :list-style {})] [result-items])) (defn- focus [^js/InputRef comp-ref] @@ -77,7 +79,9 @@ (println "inputRef called back with invalid ref or nil ref"))) (defn search-dialog [{:keys [dialog-show term not-matched error-text result]} _db-key] - (let [input-comp-ref (atom nil)] + (let [input-comp-ref (atom nil) + matched-entries (:entry-items result) + matched-count (count matched-entries)] [mui-dialog {:open (if (nil? dialog-show) false dialog-show) :on-click #(.stopPropagation %) :classes {:paper "pwd-dlg-root"}} @@ -92,28 +96,34 @@ :inputRef (fn [e] (reset! input-comp-ref e)) :autoFocus (when (str/blank? term) true) - ;;:on-key-press (enter-key-pressed-factory #(sch-event/search-on-click db-key term)) + ;;:on-key-press (enter-key-pressed-factory #(sch-event/search-on-click db-key term)) :on-change sch-event/search-term-update ;; a fn that needs to accept an event object - :variant "standard" + :variant "standard" :fullWidth true :InputProps {:endAdornment (r/as-element [mui-input-adornment {:position "end"} - [mui-icon-button + [mui-icon-button {:edge false :on-click (fn [] (focus @input-comp-ref) (sch-event/search-term-clear))} [mui-icon-clear-outlined]]])}}] - (when (seq (:entry-items result)) - [mui-stack {:sx {:mt 2 :height "250px" :overflow-y "scroll"}} - [search-result-list-content]]) + (when (seq matched-entries) + [mui-stack {:sx {:mt 2 :height "250px" + :background-color (get-theme-color :header-footer)}} + [search-result-list-content matched-entries]]) (cond (not (nil? error-text)) [mui-alert {:severity "error" :sx {:mt 1}} error-text] + (> matched-count 0) + [mui-stack {:direction "row" :justify-content "space-between" :sx {:margin-top 1 :margin-bottom 1}} + [mui-typography (str (tr-h "noOfEntriesFound") " : " matched-count) #_(str "Matched entry count: " matched-count)] + [mui-typography (tr-h "doubleClickOnEntry")]] + (and not-matched (not (str/blank? term))) - [mui-alert {:severity "warning" :sx {:mt 1}} "No matching is found"])]] + [mui-alert {:severity "warning" :sx {:mt 1}} (tr-h "noMatchingEntryFound")])]] [mui-dialog-actions diff --git a/src/main/onekeepass/frontend/translation.clj b/src/main/onekeepass/frontend/translation.clj index bde346f..099f4b0 100644 --- a/src/main/onekeepass/frontend/translation.clj +++ b/src/main/onekeepass/frontend/translation.clj @@ -77,6 +77,7 @@ #_(str/join "." (conj v# "labels")) (onekeepass.frontend.translation/lstr (str/join "." (conj v# "entryTypeTitles"))))) +;; lstr-field-name is an equivalent impl using fn (defmacro tr-entry-field-name-cv "Uses values found in the symbols passed as keys and adds the prefix before calling lstr" [& keys] diff --git a/src/main/onekeepass/frontend/translation.cljs b/src/main/onekeepass/frontend/translation.cljs index d5960bb..36bc664 100644 --- a/src/main/onekeepass/frontend/translation.cljs +++ b/src/main/onekeepass/frontend/translation.cljs @@ -10,8 +10,6 @@ (def ^:private i18n-obj ^js/i18nObj i18n) - - ;; It appears that start page lstr calls are made before translations data are loaded because of async call nature ;; The "getStarted" key is called only once. Other keys are called second time and gets the translation data ;; Not sure why this is happening @@ -22,6 +20,8 @@ (def i18n-instance (atom nil)) +;; https://www.i18next.com/translation-function/plurals#singular-plural + ;; See interpolation options here ;;https://www.i18next.com/translation-function/interpolation (defn lstr @@ -133,12 +133,16 @@ (setup-i18n-with-backend prefered_language (create-back-end parsed-translations)))) +;; This loads the translation files for the selected language ( done in Settings screen) +;; We need to have the corresponding translation json files in the dir resources/public/translations +;; See load_language_translations fn of src-tauri/src/translation.rs + (defn load-language-translation - "Needs to be called on app loading in the very begining to load locale language and 'en' + "Needs to be called on app loading in the very begining to load locale language (or prefered_language) and 'en' tranalations json files found in app resource dir" ([] (tr-events/load-language-translation [] translations-loaded-callback)) - + ;; Not used at this time ([language-ids] ;; language-ids is a vec of two charater language ids ;; e.g ["en" "fr"] From 95355fc7a71f4fe56912f2b80d976b07f8664531 Mon Sep 17 00:00:00 2001 From: jeyasankar Date: Mon, 3 Feb 2025 11:01:11 -0800 Subject: [PATCH 09/15] Added group name to an entry's form in detail mode --- .../onekeepass/frontend/entry_form_ex.cljs | 117 ++++++++++++------ .../frontend/events/group_tree_content.cljs | 2 - .../frontend/password_generator.cljs | 3 +- src/main/onekeepass/frontend/search.cljs | 2 +- 4 files changed, 83 insertions(+), 41 deletions(-) diff --git a/src/main/onekeepass/frontend/entry_form_ex.cljs b/src/main/onekeepass/frontend/entry_form_ex.cljs index 2480afb..77617e6 100644 --- a/src/main/onekeepass/frontend/entry_form_ex.cljs +++ b/src/main/onekeepass/frontend/entry_form_ex.cljs @@ -75,8 +75,8 @@ (handler-name field-name-kw (-> e .-target .-checked))))) #_(defn on-check-factory [handler-name field-name-kw] - (fn [e] - (handler-name field-name-kw (-> e .-target .-checked)))) + (fn [e] + (handler-name field-name-kw (-> e .-target .-checked)))) (defn on-change-factory2 [handler-name] @@ -137,7 +137,10 @@ expiry-duration-selection @(form-events/entry-form-field :expiry-duration-selection) expiry-dt @(form-events/entry-form-data-fields :expiry-time) creation-time @(form-events/entry-form-data-fields :creation-time) - last-modification-time @(form-events/entry-form-data-fields :last-modification-time)] + last-modification-time @(form-events/entry-form-data-fields :last-modification-time) + parent-group-uuid @(form-events/entry-form-data-fields :group-uuid) + {:keys [name]} @(dlg-events/selected-group-info parent-group-uuid) + ] (when-not edit [mui-box {:sx (theme-content-sx @m/custom-theme-atom)} @@ -149,9 +152,13 @@ [mui-typography (str (tr-l "created") ":")] [mui-typography (u/to-local-datetime-str creation-time ENTRY_DATETIME_FORMAT)]] - [mui-stack {:direction "row" :sx {:justify-content "space-between"}} + [mui-stack {:direction "row" :sx {:justify-content "space-between" :margin-bottom "10px"}} [mui-typography (str (tr-l "lastModified") ":")] [mui-typography (u/to-local-datetime-str last-modification-time ENTRY_DATETIME_FORMAT)]] + + [mui-stack {:direction "row" :sx {:justify-content "space-between"}} + [mui-typography (str (tr-l "group") ":")] + [mui-typography name]] (when-not (= expiry-duration-selection "no-expiry") [mui-stack {:direction "row" :sx {:justify-content "space-between" :margin-top "10px"}} @@ -282,38 +289,39 @@ Returns an vec of kvd map for a section " [entry-type-uuid section-name section-fields parsed-fields] - (let [section-data (get section-fields section-name)] - (if (not= entry-type-uuid const/UUID_OF_ENTRY_TYPE_AUTO_OPEN) - - (let [adjusted-section-data (mapv - (fn [{:keys [key] :as m}] - (assoc m :read-value (place-holder-resolved-value parsed-fields key))) - section-data)] - adjusted-section-data) - (let [adjusted-section-data (mapv - (fn [{:keys [key] :as m}] - ;; Note the use of lstr-field-name vs tr-entry-field-name-cv - ;; lstr-field-name is fn and tr-entry-field-name-cv is a macro - (cond - (= key URL) - ;; for now read-value is not used - ;;:read-value (:url-field-value m) - (assoc m :field-name (tr-entry-field-name-cv "autoOpenKdbxFileOpen")) - - (= key USERNAME) - (assoc m :field-name (lstr-field-name 'autoOpenKeyFile) - :read-value (place-holder-resolved-value parsed-fields key)) ;; :read-value (:key-file-path m) - - (= key PASSWORD) - (assoc m :read-value (place-holder-resolved-value parsed-fields key)) - - (= key IFDEVICE) - (assoc m :field-name (tr-entry-field-name-cv "autoOpenIfDevice")) - - :else - m)) - section-data)] - adjusted-section-data)))) + (let [section-data (get section-fields section-name) + + adjusted-section-data (mapv + (fn [{:keys [key] :as m}] + (assoc m :read-value (place-holder-resolved-value parsed-fields key))) + section-data) + + adjusted-section-data (if (not= entry-type-uuid const/UUID_OF_ENTRY_TYPE_AUTO_OPEN) + adjusted-section-data + (mapv + (fn [{:keys [key] :as m}] + ;; Note the use of lstr-field-name vs tr-entry-field-name-cv + ;; lstr-field-name is fn and tr-entry-field-name-cv is a macro + (cond + (= key URL) + ;; for now read-value is not used + ;;:read-value (:url-field-value m) + (assoc m :field-name (tr-entry-field-name-cv "autoOpenKdbxFileOpen")) + + (= key USERNAME) + (assoc m :field-name (lstr-field-name 'autoOpenKeyFile) + :read-value (place-holder-resolved-value parsed-fields key)) ;; :read-value (:key-file-path m) + + (= key PASSWORD) + (assoc m :read-value (place-holder-resolved-value parsed-fields key)) + + (= key IFDEVICE) + (assoc m :field-name (tr-entry-field-name-cv "autoOpenIfDevice")) + + :else + m)) + adjusted-section-data))] + adjusted-section-data)) (defn all-sections-content "Component for all sections of an entry" @@ -1015,6 +1023,43 @@ ;;;;;;;;;;;;;;;;;;; +#_(defn get-section-data + "Called to set up any entry type specific data in kv + Returns an vec of kvd map for a section + " + [entry-type-uuid section-name section-fields parsed-fields] + (let [section-data (get section-fields section-name)] + (if (not= entry-type-uuid const/UUID_OF_ENTRY_TYPE_AUTO_OPEN) + (let [adjusted-section-data (mapv + (fn [{:keys [key] :as m}] + (assoc m :read-value (place-holder-resolved-value parsed-fields key))) + section-data)] + adjusted-section-data) + (let [adjusted-section-data (mapv + (fn [{:keys [key] :as m}] + ;; Note the use of lstr-field-name vs tr-entry-field-name-cv + ;; lstr-field-name is fn and tr-entry-field-name-cv is a macro + (cond + (= key URL) + ;; for now read-value is not used + ;;:read-value (:url-field-value m) + (assoc m :field-name (tr-entry-field-name-cv "autoOpenKdbxFileOpen")) + + (= key USERNAME) + (assoc m :field-name (lstr-field-name 'autoOpenKeyFile) + :read-value (place-holder-resolved-value parsed-fields key)) ;; :read-value (:key-file-path m) + + (= key PASSWORD) + (assoc m :read-value (place-holder-resolved-value parsed-fields key)) + + (= key IFDEVICE) + (assoc m :field-name (tr-entry-field-name-cv "autoOpenIfDevice")) + + :else + (assoc m :read-value (place-holder-resolved-value parsed-fields key)))) + section-data)] + adjusted-section-data)))) + #_(defn add-modify-section-field-popper [{:keys [dialog-show popper-anchor-el diff --git a/src/main/onekeepass/frontend/events/group_tree_content.cljs b/src/main/onekeepass/frontend/events/group_tree_content.cljs index 807b8e1..b7bf05d 100644 --- a/src/main/onekeepass/frontend/events/group_tree_content.cljs +++ b/src/main/onekeepass/frontend/events/group_tree_content.cljs @@ -58,14 +58,12 @@ (defn groups-listing [] (subscribe [:group-tree-content/groups-listing])) - (defn expanded-nodes [] (subscribe [:expanded-nodes])) (defn recycle-bin-empty-check [] (subscribe [:recycle-bin-empty-check])) - ;;;;;;;;; (reg-event-db diff --git a/src/main/onekeepass/frontend/password_generator.cljs b/src/main/onekeepass/frontend/password_generator.cljs index 4d275ee..df1a834 100644 --- a/src/main/onekeepass/frontend/password_generator.cljs +++ b/src/main/onekeepass/frontend/password_generator.cljs @@ -9,8 +9,7 @@ mui-icon-visibility mui-icon-visibility-off mui-input mui-input-adornment mui-slider mui-stack mui-tab mui-tabs mui-text-field mui-typography]] - [onekeepass.frontend.translation :refer-macros [tr-l tr-h tr-bl tr-dlg-title] :refer [lstr-l - lstr-l-cv]] + [onekeepass.frontend.translation :refer-macros [tr-l tr-h tr-bl] :refer [lstr-l lstr-l-cv]] [reagent.core :as r])) (defn- end-icons [visibile?] diff --git a/src/main/onekeepass/frontend/search.cljs b/src/main/onekeepass/frontend/search.cljs index e8d84a3..c08035e 100644 --- a/src/main/onekeepass/frontend/search.cljs +++ b/src/main/onekeepass/frontend/search.cljs @@ -119,7 +119,7 @@ (> matched-count 0) [mui-stack {:direction "row" :justify-content "space-between" :sx {:margin-top 1 :margin-bottom 1}} - [mui-typography (str (tr-h "noOfEntriesFound") " : " matched-count) #_(str "Matched entry count: " matched-count)] + [mui-typography (str (tr-h "noOfEntriesFound") " : " matched-count)] [mui-typography (tr-h "doubleClickOnEntry")]] (and not-matched (not (str/blank? term))) From 6b4de5cfae72c1a02629e217a6df64802b1e6423 Mon Sep 17 00:00:00 2001 From: jeyasankar Date: Thu, 6 Feb 2025 16:36:21 -0800 Subject: [PATCH 10/15] Using trait impl arg to load wordlist from resources instead of callback mechanism --- src-tauri/src/app_state.rs | 4 +- src-tauri/src/callback_service_provider.rs | 56 --------- src-tauri/src/commands.rs | 7 +- src-tauri/src/main.rs | 3 +- src-tauri/src/pass_phrase.rs | 112 ++++++++++++++++++ .../onekeepass/frontend/events/common.cljs | 9 ++ .../frontend/events/password_generator.cljs | 3 +- .../frontend/password_generator.cljs | 24 ++-- src/main/onekeepass/frontend/start_page.cljs | 24 ++-- 9 files changed, 162 insertions(+), 80 deletions(-) delete mode 100644 src-tauri/src/callback_service_provider.rs create mode 100644 src-tauri/src/pass_phrase.rs diff --git a/src-tauri/src/app_state.rs b/src-tauri/src/app_state.rs index 8f72291..fca16f5 100644 --- a/src-tauri/src/app_state.rs +++ b/src-tauri/src/app_state.rs @@ -18,7 +18,7 @@ use tauri::{ }; use crate::app_preference::{Preference, PreferenceData}; -use crate::{biometric, callback_service_provider}; +use crate::biometric; use crate::constants::standard_file_names::APP_PREFERENCE_FILE; use crate::key_secure; use crate::translation::current_locale_language; @@ -56,7 +56,7 @@ pub fn init_app(app: &App) { key_secure::init_key_main_store(); - callback_service_provider::init_callback_service_provider(app.app_handle().clone()); + // callback_service_provider::init_callback_service_provider(app.app_handle().clone()); onekeepass_core::async_service::start_runtime(); diff --git a/src-tauri/src/callback_service_provider.rs b/src-tauri/src/callback_service_provider.rs deleted file mode 100644 index 83c6a06..0000000 --- a/src-tauri/src/callback_service_provider.rs +++ /dev/null @@ -1,56 +0,0 @@ -use std::sync::Arc; - -use log::debug; -use onekeepass_core::callback_service::{CallbackServiceProvider, CommonCallbackService}; -use onekeepass_core::error::{self, Result}; -use tauri::Manager; - -use crate::app_state::AppState; - -// IMPORTANT: -// Should be called during app init call so that the backend api can make a callback to the Runtime -pub(crate) fn init_callback_service_provider(app_handle: tauri::AppHandle) { - let instance = Arc::new(CommonCallbackServiceImpl::new(app_handle)); - // In case, we need to hold any reference at this module, then we need to Arc::clone and use it - CallbackServiceProvider::init(instance); - debug!("init_callback_service_provider is called and CallbackServiceProvider init is done"); -} - -//#[derive(Default)] -struct CommonCallbackServiceImpl { - // We need to hold a copy of app handle to get back the AppState and use fields from that - app_handle: tauri::AppHandle, -} - -impl CommonCallbackServiceImpl { - fn new(app_handle: tauri::AppHandle) -> Self { - Self { app_handle } - } -} - -impl CommonCallbackService for CommonCallbackServiceImpl { - fn load_wordlist(&self, wordlist_file_name: &str) -> Result { - // Though we can get the resouerce dir from 'tauri::AppHandle', we are getting - // our own AppState from this handle and use it to get the resource dir. - // In that way our app specific preferences can be accessed if required - - let app_state = self.app_handle.state::(); - let Some(rseource_path) = app_state.resource_dir_path() else { - return Err(error::Error::DataError("No app resource dir is found")); - }; - - // IMPORTANT: - // We need to add "../resources/public/wordlists" src-tauri/tauri.conf.json - // in order for the file reading. See also translation::load_language_translations and 'load_custom_svg_icons' - // for other app level resources handling - - // _up_/resources/public is the resource dir and all wordlist files are found - // in the sub dir _up_/resources/public/wordlists - - let full_path = rseource_path.join("wordlists").join(wordlist_file_name); - - debug!("Going to load the wordlist file {:?}", &full_path); - - Ok(std::fs::read_to_string(&full_path)?) - } -} diff --git a/src-tauri/src/commands.rs b/src-tauri/src/commands.rs index 69a7d5b..d30f19b 100644 --- a/src-tauri/src/commands.rs +++ b/src-tauri/src/commands.rs @@ -15,7 +15,7 @@ use uuid::Uuid; use crate::app_state::SystemInfoWithPreference; use crate::auto_open::{AutoOpenProperties, AutoOpenPropertiesResolved}; use crate::menu::{self, MenuActionRequest, MenuTitleChangeRequest}; -use crate::{app_paths, translation}; +use crate::{app_paths, pass_phrase, translation}; use crate::{app_preference, app_state}; use crate::{auto_type, biometric, OTP_TOKEN_UPDATE_EVENT}; use onekeepass_core::async_service as kp_async_service; @@ -703,9 +703,12 @@ pub(crate) async fn analyzed_password( #[command] pub(crate) async fn generate_password_phrase( + app: tauri::AppHandle, password_phrase_options: kp_service::PassphraseGenerationOptions, ) -> Result { - Ok(password_phrase_options.generate()?) + let loader = pass_phrase::WordListLoaderImpl::new(app); + // loader impl may be called to load word list file from resource in generate fn + Ok(password_phrase_options.generate(&loader)?) } #[command] diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index a1b0797..4847ea0 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -15,8 +15,9 @@ mod file_util; mod key_secure; mod menu; mod translation; +mod pass_phrase; mod password_gen_preference; -mod callback_service_provider; +// mod callback_service_provider; use constants::event_action_names::*; use constants::event_names::*; diff --git a/src-tauri/src/pass_phrase.rs b/src-tauri/src/pass_phrase.rs new file mode 100644 index 0000000..1946070 --- /dev/null +++ b/src-tauri/src/pass_phrase.rs @@ -0,0 +1,112 @@ +use onekeepass_core::db_service::WordListLoader; +use onekeepass_core::error::{self, Error, Result}; +use tauri::Manager; + +use crate::app_state::AppState; + +pub(crate) struct WordListLoaderImpl { + app_handle: tauri::AppHandle, +} + +impl WordListLoaderImpl { + pub(crate) fn new(app_handle: tauri::AppHandle) -> Self { + Self { app_handle } + } +} + +impl WordListLoader for WordListLoaderImpl { + fn load_from_resource(&self, wordlist_file_name: &str) -> Result { + // Though we can get the resouerce dir from 'tauri::AppHandle', we are getting + // our own AppState from this handle and use it to get the resource dir. + // In that way our app specific preferences can be accessed if required + + let app_state = self.app_handle.state::(); + let Some(rseource_path) = app_state.resource_dir_path() else { + return Err(error::Error::DataError("No app resource dir is found")); + }; + + // IMPORTANT: + // We need to add "../resources/public/wordlists" src-tauri/tauri.conf.json + // in order for the file reading. See also translation::load_language_translations and 'load_custom_svg_icons' + // for other app level resources handling + + // _up_/resources/public is the resource dir and all wordlist files are found + // in the sub dir _up_/resources/public/wordlists + + let full_path = rseource_path.join("wordlists").join(wordlist_file_name); + + log::debug!("Going to load the wordlist file {:?}", &full_path); + + Ok(std::fs::read_to_string(&full_path)?) + } +} + + + +// Previously the following was used in module callback_service_provider.rs so that +// onekeepass_core we make use of the 'CoreCommonCallbackService' impl +// With the new 'WordListLoader' trait use ( passed as arg to 'generate' fn), this is no more +// required. Keeping it here in case, we can use the conccept if any other need comes +/* + +use std::sync::Arc; + +use log::debug; +use onekeepass_core::callback_service::{self, CoreCommonCallbackService}; +use onekeepass_core::error::{self, Result}; +use tauri::Manager; + +use crate::app_state::AppState; + +// IMPORTANT: +// Should be called during app init call so that the backend api can make a callback to the Runtime +pub(crate) fn init_callback_service_provider(app_handle: tauri::AppHandle) { + let instance = Arc::new(CommonCallbackServiceImpl::new(app_handle)); + // In case, we need to hold any reference at this module, then we need to Arc::clone and use it + // CallbackServiceProvider::init(instance); + callback_service::initialize_with_provider(instance); + debug!("init_callback_service_provider is called and CallbackServiceProvider init is done"); +} + +//#[derive(Default)] +struct CommonCallbackServiceImpl { + // We need to hold a copy of app handle to get back the AppState and use fields from that + app_handle: tauri::AppHandle, +} + +impl CommonCallbackServiceImpl { + fn new(app_handle: tauri::AppHandle) -> Self { + Self { app_handle } + } +} + +impl CoreCommonCallbackService for CommonCallbackServiceImpl { + fn load_wordlist(&self, wordlist_file_name: &str) -> Result { + // Though we can get the resouerce dir from 'tauri::AppHandle', we are getting + // our own AppState from this handle and use it to get the resource dir. + // In that way our app specific preferences can be accessed if required + + let app_state = self.app_handle.state::(); + let Some(rseource_path) = app_state.resource_dir_path() else { + return Err(error::Error::DataError("No app resource dir is found")); + }; + + // IMPORTANT: + // We need to add "../resources/public/wordlists" src-tauri/tauri.conf.json + // in order for the file reading. See also translation::load_language_translations and 'load_custom_svg_icons' + // for other app level resources handling + + // _up_/resources/public is the resource dir and all wordlist files are found + // in the sub dir _up_/resources/public/wordlists + + let full_path = rseource_path.join("wordlists").join(wordlist_file_name); + + debug!("Going to load the wordlist file {:?}", &full_path); + + Ok(std::fs::read_to_string(&full_path)?) + } +} + + + +*/ \ No newline at end of file diff --git a/src/main/onekeepass/frontend/events/common.cljs b/src/main/onekeepass/frontend/events/common.cljs index fc5f2ce..b322371 100644 --- a/src/main/onekeepass/frontend/events/common.cljs +++ b/src/main/onekeepass/frontend/events/common.cljs @@ -71,6 +71,9 @@ (defn app-theme-light? [] (subscribe [:app-theme-light])) +(defn app-version [] + (subscribe [:app-version])) + (defn biometric-type-available [] (subscribe [:biometric-type-available])) @@ -171,6 +174,12 @@ ;; valid values (:theme pref) => light or dark (= "light" (:theme pref)))) +(reg-sub + :app-version + :<- [:app-preference] + (fn [pref _query-vec] + (:version pref))) + (reg-sub :app-preference-loading-completed (fn [db _query-vec] diff --git a/src/main/onekeepass/frontend/events/password_generator.cljs b/src/main/onekeepass/frontend/events/password_generator.cljs index c08e4d1..c34208b 100644 --- a/src/main/onekeepass/frontend/events/password_generator.cljs +++ b/src/main/onekeepass/frontend/events/password_generator.cljs @@ -46,6 +46,7 @@ :password-visible true :text-copied false :callback-on-copy-fn nil + ;; :password or :pass-phrase :panel-shown :password ;; All fields from struct PasswordGenerationOptions :password-options {:length 8 @@ -56,7 +57,7 @@ :spaces false :exclude-similar-characters true :strict true} - ;; All fields from struct PassphraseGenerationOptions + ;; All fields from struct PassphraseGenerationOptions and intialized from app-preference :phrase-generator-options {} ;; some fields from struct 'AnalyzedPassword' form the map in :password-result :password-result {:password nil diff --git a/src/main/onekeepass/frontend/password_generator.cljs b/src/main/onekeepass/frontend/password_generator.cljs index df1a834..c96cb97 100644 --- a/src/main/onekeepass/frontend/password_generator.cljs +++ b/src/main/onekeepass/frontend/password_generator.cljs @@ -37,13 +37,19 @@ :on-change (fn [_event val] ;; val is of string type and need to be coverted as keyword (gen-events/set-active-password-generator-panel (keyword val)))} - [mui-tab {:label (lstr-l 'password) :value :password}] - [mui-tab {:label (lstr-l 'passwordPhrase) :value :pass-phrase}]]) + + ;; Saw default font-size used 0.875em when button label is uppercase + [mui-tab {:sx {:text-transform "capitalize" :font-size "0.900em"} :label (lstr-l 'password) :value :password}] + [mui-tab {:sx {:text-transform "capitalize" :font-size "0.900em"} :label (lstr-l 'passwordPhrase) :value :pass-phrase}]]) ;; When this field has the focus, Shift + Down key will show the menu items and can then be used to move up or down. ;; Also if we press the first letter (case sensitive ) of any options, then cursor moves to that menu item option +;; Saw this warning: MUI: You have provided an out-of-range value `2024` for the select component. +;; See https://lightrun.com/solutions/mui-material-ui-suppress-the-material-ui-select-component-out-of-range-error/ +;; May need to fix if any issue comes up + ;; TODO: ;; Move to 'common-components' and also change in 'src/main/onekeepass/frontend/entry_form/fields.cljs' ;; to use this common one @@ -99,14 +105,16 @@ (def all-wl [{:value "EFFLarge" :label "EFF Large List"} {:value "EFFShort1" :label "EFF Short List 1"} {:value "EFFShort2" :label "EFF Short List 2"} - {:value "Google10000UsaEnglishNoSwearsMedium" :label "U.S English,No Swears words"} ;; "Google (U.S English,No Swears words)" + {:value "Google10000UsaEnglishNoSwearsMedium" :label "U.S English, No Swears words"} ;; "Google (U.S English,No Swears words)" {:value "FrenchDicewareWordlist" :label "French Word List"} {:value "GermanDicewareWordlist" :label "German Word List"}]) ;; values should match enum ProbabilityOption -(def capitalize-word-choices [{:value "Always" :label (lstr-l 'always)} - {:value "Never" :label (lstr-l 'never)} - {:value "Sometimes" :label (lstr-l 'sometimes)}]) +(defn capitalize-word-choices [] + [{:value "Always" :label (lstr-l 'always)} + {:value "Never" :label (lstr-l 'never)} + {:value "Sometimes" :label (lstr-l 'sometimes)}] + ) ;; values should match enum ProbabilityOption (def capitalize-first-choices capitalize-word-choices) @@ -157,14 +165,14 @@ :value (:type-name capitalize-words) :edit true :on-change-handler (cc/on-change-factory gen-events/pass-phrase-options-select-field-update :capitalize-words) - :select-field-options capitalize-word-choices}]] + :select-field-options (capitalize-word-choices)}]] [mui-stack {:width 8}] [mui-stack {:direction "row" :sx {:width "50%"}} [simple-selection-field {:field-name (lstr-l 'capitalizeFirstLetter) :value (:type-name capitalize-first) :edit true :on-change-handler (cc/on-change-factory gen-events/pass-phrase-options-select-field-update :capitalize-first) - :select-field-options capitalize-first-choices}]]] + :select-field-options (capitalize-first-choices)}]]] [mui-stack {:direction "row" :sx {:width "100%" :margin-top "10px"}} [mui-text-field diff --git a/src/main/onekeepass/frontend/start_page.cljs b/src/main/onekeepass/frontend/start_page.cljs index 5f8e1b5..48ceed5 100644 --- a/src/main/onekeepass/frontend/start_page.cljs +++ b/src/main/onekeepass/frontend/start_page.cljs @@ -24,30 +24,31 @@ (set! *warn-on-infer* true) (defn main-content [] - (let [recent-files-list @(cmn-events/recent-files)] + (let [recent-files-list @(cmn-events/recent-files) + app-version @(cmn-events/app-version)] [mui-container {:sx {:height "100%" ;;:bgcolor "text.disabled" :bgcolor "background.default" :color "primary.main"}} ;;:mt 10 [mui-stack {:direction "row" :gap 2 :alignItems "center" - :divider (r/as-element [mui-divider + :divider (r/as-element [mui-divider {:sx {:border-color (theme-color @custom-theme-atom :divider-color1)} :orientation "vertical" :flexItem true}]) :sx {:height "100%"}} - + ;; Left side [mui-box {:sx {:display "flex" :width "50%" :height "100%" :flexDirection "column"}} - [mui-typography {:variant "h6"} + [mui-typography {:variant "h6"} (tr-t start)] [mui-stack {:direction "row" :gap 2 :alignItems "center"} [mui-icon-button {:edge "start" :color "inherit" :sx {:ml 0} :onClick nd-events/new-database-dialog-show} [cust-icons/database-cog-outline]] - + [mui-link {:variant "subtitle1" - :onClick nd-events/new-database-dialog-show} - (tr-l newDatabase)] + :onClick nd-events/new-database-dialog-show} + (tr-l newDatabase)] [nd-form/new-database-dialog-main]] [mui-stack {:direction "row" :gap 2 :alignItems "center"} @@ -60,7 +61,7 @@ [od-form/open-db-dialog-main]] [mui-typography {:sx {:mt 4} :variant "h6"} (tr-t recent)] - + [mui-stack {:mt 1} (doall (for [lnk recent-files-list] @@ -87,11 +88,14 @@ #_[mui-stack [m/example-comp]] [mui-stack {:direction "row" :align-self "center"} ;;:sx {:mt "25%"} - [mui-typography {:variant "h4" :sx {:color "text.primary"}} "OneKeePass"]]]]])) + [mui-typography {:variant "h4" :sx {:color "text.primary"}} "OneKeePass"]] + + [mui-stack {:direction "row" :align-self "center"} ;;:sx {:mt "25%"} + [mui-typography {:variant "h7" :sx {:color "text.primary"}} app-version #_(str "Version " app-version)]]]]])) (defn welcome-content [] [:div {:class "box" :style {:overflow "hidden" ;; hidden used so to avoid showing scrollbar - :background-color (theme-color @custom-theme-atom :bg-default)}} + :background-color (theme-color @custom-theme-atom :bg-default)}} [:div {:class "cust_row header" :style {:text-align "center"}} ;; Another way of getting color from theme (fn [^js/Mui.Theme theme] (-> theme .-status .-danger)) [mui-stack {:direction "row" :justify-content "center" :sx {:bgcolor "secondary.main"}} From f0bd1dedead52f916cbbb83e98b3719c13b80002 Mon Sep 17 00:00:00 2001 From: jeyasankar Date: Wed, 12 Feb 2025 18:17:40 -0800 Subject: [PATCH 11/15] Changed auto open place holder parsing error name --- src-tauri/src/auto_open.rs | 12 +++--- src/main/onekeepass/frontend/constants.cljs | 4 +- src/main/onekeepass/frontend/db_icons.cljs | 2 +- .../frontend/entry_form/fields.cljs | 37 ++----------------- .../frontend/events/entry_form_ex.cljs | 2 +- 5 files changed, 14 insertions(+), 43 deletions(-) diff --git a/src-tauri/src/auto_open.rs b/src-tauri/src/auto_open.rs index 4a7da21..07d421b 100644 --- a/src-tauri/src/auto_open.rs +++ b/src-tauri/src/auto_open.rs @@ -40,12 +40,12 @@ impl AutoOpenProperties { "Invalid db_key {}. The db file is not found", &self.source_db_key ); - return Err(Error::UnexpectedError(er)); + return Err(Error::AutoOpenError(er)); } // We should be able to find the parent dir from the auto open master db's path let Some(parent_dir_path) = db_dir_path.parent() else { - return Err(Error::UnexpectedError("Parent dir is not found".into())); + return Err(Error::AutoOpenError("Parent dir is not found".into())); }; // The child database path is parsed only if it is not an empty string @@ -106,10 +106,10 @@ impl AutoOpenProperties { fn resolved_path(parent_dir_path: &Path, in_path: &String) -> Result { let (remaining, parsed) = parse_field_value(in_path) - .map_err(|e| error::Error::UnexpectedError(format!("Parsing failed with error {}", e)))?; + .map_err(|e| error::Error::AutoOpenError(format!("Parsing failed with error {}", e)))?; if !remaining.is_empty() { - return Err(Error::UnexpectedError("Url parsing is not complete".into())); + return Err(Error::AutoOpenError("Url parsing is not complete".into())); } let final_path = if parsed.full_path_part.starts_with("file://") { @@ -117,13 +117,13 @@ fn resolved_path(parent_dir_path: &Path, in_path: &String) -> Result { } else { let p = parent_dir_path.join(&parsed.full_path_part); // If the canonicalize path is not found, then this will return an error - p.canonicalize().map_err(|e| Error::UnexpectedError(format!("Error: Path {:?} : {}", &p,e)))?.to_string_lossy().to_string() + p.canonicalize().map_err(|e| Error::AutoOpenError(format!("Error: Path {:?} : {}", &p,e)))?.to_string_lossy().to_string() }; // let mut p = parent_dir_path.join(&parsed.full_path_part); // // If the canonicalize path is not found, then this will return an error - // p = p.canonicalize().map_err(|e| Error::UnexpectedError(format!("Error: Path {:?} : {}", &p,e)))?; + // p = p.canonicalize().map_err(|e| Error::AutoOpenError(format!("Error: Path {:?} : {}", &p,e)))?; Ok(final_path) } diff --git a/src/main/onekeepass/frontend/constants.cljs b/src/main/onekeepass/frontend/constants.cljs index 1a0e3af..1792a81 100644 --- a/src/main/onekeepass/frontend/constants.cljs +++ b/src/main/onekeepass/frontend/constants.cljs @@ -14,14 +14,14 @@ (def WIRELESS_ROUTER_TYPE_NAME "Wireless Router") (def PASSPORT_TYPE_NAME "Passport") (def BANK_ACCOUNT_TYPE_NAME "Bank Account") -(def AUTO_DB_OPEN "Auto Database Open") +(def AUTO_DB_OPEN_TYPE_NAME "Auto Database Open") ;; This list is used in Entry Type select menu items on the new entry form (def STANDARD_ENTRY_TYPES [LOGIN_TYPE_NAME CREDIT_DEBIT_CARD_TYPE_NAME WIRELESS_ROUTER_TYPE_NAME BANK_ACCOUNT_TYPE_NAME - AUTO_DB_OPEN]) + AUTO_DB_OPEN_TYPE_NAME]) (def ADDITIONAL_ONE_TIME_PASSWORDS "Additional One-Time Passwords") ;; diff --git a/src/main/onekeepass/frontend/db_icons.cljs b/src/main/onekeepass/frontend/db_icons.cljs index 4043b9c..a6ddebf 100644 --- a/src/main/onekeepass/frontend/db_icons.cljs +++ b/src/main/onekeepass/frontend/db_icons.cljs @@ -782,7 +782,7 @@ const/BANK_ACCOUNT_TYPE_NAME mui-icon-account-balance-outlined const/WIRELESS_ROUTER_TYPE_NAME mui-icon-wifi-outlined const/PASSPORT_TYPE_NAME mui-icon-flight-takeoff-outlined - const/AUTO_DB_OPEN mui-icon-launch}) + const/AUTO_DB_OPEN_TYPE_NAME mui-icon-launch}) (defn entry-type-icon "Resturns an as form-1 reagent component for the given name" diff --git a/src/main/onekeepass/frontend/entry_form/fields.cljs b/src/main/onekeepass/frontend/entry_form/fields.cljs index 3fadca1..f1b3435 100644 --- a/src/main/onekeepass/frontend/entry_form/fields.cljs +++ b/src/main/onekeepass/frontend/entry_form/fields.cljs @@ -40,7 +40,7 @@ :else value)) -(defn- end-icons-1 [{:keys [key protected visibile edit] :as kv}] +(defn- end-icons [{:keys [key protected visibile edit] :as kv}] (let [val (to-value kv)] [:<> (when protected @@ -68,34 +68,6 @@ ;; Copy [(cc/copy-icon-factory) val {:sx {:mr "-1px"}}]])) - -#_(defn- end-icons [key value protected visibile? edit] - [:<> - (when protected - (if visibile? - [mui-icon-button {:sx {:margin-right "-8px"} - :edge "end" - :on-click #(form-events/entry-form-field-visibility-toggle key)} - [mui-icon-visibility]] - [mui-icon-button {:sx {:margin-right "-8px"} - :edge "end" - :on-click #(form-events/entry-form-field-visibility-toggle key)} - [mui-icon-visibility-off]])) - ;; Open with the url - (when (= key URL) - [mui-icon-button {:sx {:margin-right "-8px"} - :edge "end" - :on-click #(form-events/entry-form-open-url value)} - [m/mui-icon-launch]]) - ;; Password generator - (when (and edit protected (= key PASSWORD)) - [mui-icon-button {:sx {:margin-right "-8px"} - :edge "end" - :on-click form-events/password-generator-show} - [mui-icon-autorenew]]) - ;; Copy - [(cc/copy-icon-factory) value {:sx {:mr "-1px"}}]]) - (defn simple-selection-field [{:keys [key value edit @@ -194,7 +166,7 @@ :endAdornment (if no-end-icons nil (r/as-element [mui-input-adornment {:position "end"} - [end-icons-1 kv] + [end-icons kv] #_(seq icons)])) :type (if (or (not protected) visible) "text" "password")} ;;attributes for 'input' tag can be added here @@ -278,9 +250,8 @@ :sx (theme-text-field-sx edit @custom-theme-atom) :endAdornment (if (or (not valid-token-found) no-end-icons) nil (r/as-element - [mui-input-adornment {:position "end"} - #_[end-icons key token false visible edit] - [end-icons-1 (assoc kv + [mui-input-adornment {:position "end"} + [end-icons (assoc kv :value token :read-value nil :protected false)]])) diff --git a/src/main/onekeepass/frontend/events/entry_form_ex.cljs b/src/main/onekeepass/frontend/events/entry_form_ex.cljs index 265d5f0..1a98071 100644 --- a/src/main/onekeepass/frontend/events/entry_form_ex.cljs +++ b/src/main/onekeepass/frontend/events/entry_form_ex.cljs @@ -1733,7 +1733,7 @@ ;; All entry form data keys (-> (get @re-frame.db/app-db db-key) :entry-form-data :data keys) - ;; => :tags :icon-id :binary-key-values :section-fields :title :expiry-time :history-count + ;; => :tags :icon-id :parsed-fields :binary-key-values :section-fields :title :expiry-time :history-count ;; :expires :standard-section-names :last-modification-time :entry-type-name :auto-type ;; :notes :section-names :entry-type-icon-name :last-access-time :uuid :entry-type-uuid :group-uuid :creation-time ) From 3f5d49ec689e7805fe6a0b39845a3250cb094493 Mon Sep 17 00:00:00 2001 From: jeyasankar Date: Sun, 9 Mar 2025 15:45:21 -0700 Subject: [PATCH 12/15] Added events to open child databases --- resources/public/translations/en.json | 2 +- src-tauri/Cargo.toml | 2 +- src-tauri/src/app_state.rs | 7 +- src-tauri/src/auto_open/mod.rs | 176 ++++++++++++++++++ .../{auto_open.rs => auto_open/resolver.rs} | 22 ++- src-tauri/src/commands.rs | 20 +- src-tauri/src/main.rs | 2 + src/main/onekeepass/frontend/background.cljs | 8 +- .../frontend/background_auto_open.cljs | 59 ++++++ .../frontend/background_common.cljs | 18 +- .../frontend/background_password.cljs | 1 - src/main/onekeepass/frontend/core.cljs | 2 + .../frontend/entry_form/fields.cljs | 12 +- .../onekeepass/frontend/entry_form_ex.cljs | 37 ---- .../onekeepass/frontend/events/auto_open.cljs | 157 ++++++++++++++++ .../onekeepass/frontend/events/common.cljs | 56 +++++- .../frontend/events/common_supports.cljs | 8 +- .../frontend/events/entry_form_auto_open.cljs | 24 ++- .../frontend/events/open_db_form.cljs | 69 +++---- src/main/onekeepass/frontend/translation.cljs | 9 +- 20 files changed, 564 insertions(+), 127 deletions(-) create mode 100644 src-tauri/src/auto_open/mod.rs rename src-tauri/src/{auto_open.rs => auto_open/resolver.rs} (94%) create mode 100644 src/main/onekeepass/frontend/background_auto_open.cljs create mode 100644 src/main/onekeepass/frontend/events/auto_open.cljs diff --git a/resources/public/translations/en.json b/resources/public/translations/en.json index d3b0e67..a594f5a 100644 --- a/resources/public/translations/en.json +++ b/resources/public/translations/en.json @@ -154,7 +154,7 @@ "veryStrong": "Very Strong", "veryWeak": "Very Weak", "weak": "Weak", - "wordList": "Word List", + "wordList": "Word list", "words": "Words" }, "dialog": { diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index c8bfefc..d8e1a1a 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -7,7 +7,7 @@ license = "" repository = "" default-run = "onekeepass-frontend" edition = "2021" -rust-version = "1.60" +# rust-version = "1.60" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/src-tauri/src/app_state.rs b/src-tauri/src/app_state.rs index fca16f5..96b8c6b 100644 --- a/src-tauri/src/app_state.rs +++ b/src-tauri/src/app_state.rs @@ -124,7 +124,7 @@ impl AppState { *resource_dir_path = resource_path; } - pub(crate) fn resource_dir_path(&self,) -> Option { + pub(crate) fn resource_dir_path(&self) -> Option { let resource_dir_path = self.resource_dir_path.lock().unwrap(); resource_dir_path.clone() } @@ -145,6 +145,11 @@ impl AppState { (*store_pref.language).to_string() } + pub(crate) fn default_entry_category_groupings(&self) -> String { + let store_pref = self.preference.lock().unwrap(); + store_pref.default_entry_category_groupings.clone() + } + /// Reads the preference from file system and store in state pub fn read_preference(&self, app: &App) { let version = format!( diff --git a/src-tauri/src/auto_open/mod.rs b/src-tauri/src/auto_open/mod.rs new file mode 100644 index 0000000..f07cb70 --- /dev/null +++ b/src-tauri/src/auto_open/mod.rs @@ -0,0 +1,176 @@ +mod resolver; +use std::collections::HashMap; + +use log::debug; +pub(crate) use resolver::{AutoOpenProperties, AutoOpenPropertiesResolved}; + +use onekeepass_core::db_service::{ + self as kp_service, AllTags, EntryCategories, EntryCategoryGrouping, EntryTypeHeaders, GroupTree, + KdbxLoaded, +}; + +use onekeepass_core::error::Result; +use serde::Serialize; +use tauri::State; + +use crate::app_state; + +#[derive(Default, Serialize)] +pub(crate) struct AutoOpenDbsInfo { + // All dbs that are opened successfully + opened_dbs: Vec, + + // failed db keys with error message + opening_failed_dbs: HashMap, + + error_messages: Vec, +} + +// All relevant intial data that are used in UI on opening a database first time +#[derive(Serialize)] +pub(crate) struct AutoOpenedDbInitData { + kdbx_loaded: KdbxLoaded, + all_tags: AllTags, + groups_tree: GroupTree, + entry_categories: EntryCategories, + entry_type_headers: EntryTypeHeaders, +} + +pub(crate) fn open_all_auto_open_dbs( + auto_open_db_key: &str, + app_state: State<'_, app_state::AppState>, +) -> Result { + let mut auto_open_dbs_info = AutoOpenDbsInfo::default(); + + let grouping_kind: EntryCategoryGrouping = + app_state.default_entry_category_groupings().as_str().into(); + + inner_open_all_auto_open_dbs(auto_open_db_key, &mut auto_open_dbs_info, &grouping_kind); + + Ok(auto_open_dbs_info) +} + +fn inner_open_all_auto_open_dbs( + auto_open_db_key: &str, + auto_open_dbs_info: &mut AutoOpenDbsInfo, + grouping_kind: &EntryCategoryGrouping, +) { + // Get all entries of "AutoOpen" group for this db_key + let entry_uuids = + kp_service::auto_open_group_entry_uuids(auto_open_db_key).unwrap_or_else(|_| vec![]); + + // entry_uuids is empty when this db with db_key does not have AutoOpen group or when it does not have any entries + if entry_uuids.is_empty() { + return; + } + + debug!( + "Entry uuids found {:?} and grouping_kind used is {:?} for db_key {}", + &entry_uuids, grouping_kind, &auto_open_db_key + ); + + for entry_uuid in entry_uuids { + // All kvs with required place holder parsing for an entry with 'entry_uuid' are collected + let kvs_result = kp_service::entry_key_value_fields(auto_open_db_key, &entry_uuid); + if let Err(e) = kvs_result { + auto_open_dbs_info.error_messages.push(e.to_string()); + continue; + } + // unwrap is fine as we have checked for error + let kvs = kvs_result.unwrap(); + + // Prepare props to resolve + let auto_open_properties = AutoOpenProperties { + source_db_key: auto_open_db_key.to_string(), + url_field_value: kvs.get(kp_service::entry_keyvalue_key::URL).cloned(), + key_file_path: kvs.get(kp_service::entry_keyvalue_key::USER_NAME).cloned(), + device_if_val: kvs.get(kp_service::entry_keyvalue_key::IF_DEVICE).cloned(), + }; + + // Here we resolve any {DB_DIR} place holder found in url and username fields + // and make sure that the key file and db file are located + + let ao_val = auto_open_properties.resolve(); + if let Err(e) = ao_val { + // As there are errors in resolving, we skip this entry uuid + auto_open_dbs_info.error_messages.push(e.to_string()); + continue; + } + // unwrap is fine as we have checked for error + let ao_resolved = ao_val.unwrap(); + + // Proceed only if the db in 'url_field_value' can be opened in this device + if !ao_resolved.can_open { + debug!( + "Can not open db from entry uuid {} on this device as it excluded", + &entry_uuid + ); + continue; + } + + let password = kvs + .get(kp_service::entry_keyvalue_key::PASSWORD) + .map(|s| s.as_str()); + + let kf_path = ao_resolved.key_file_path.as_deref(); + + if let Some(db_key_to_open) = ao_resolved.url_field_value { + // Condider only the dbs that are not yet opened + if !kp_service::is_db_opened(&db_key_to_open) { + // Note: load_kdbx will add this db_key to 'all_kdbx_cache' + match kp_service::load_kdbx(&db_key_to_open, password, kf_path) { + // On opening, load all init data + Ok(kdbx_loaded) => match load_init_data(&grouping_kind, &kdbx_loaded) { + Ok(auto_open_db) => { + auto_open_dbs_info.opened_dbs.push(auto_open_db); + // recursive call to check that the newly opened db has 'AutoOpen' group or not + inner_open_all_auto_open_dbs(&kdbx_loaded.db_key, auto_open_dbs_info, grouping_kind); + } + // Init data loading of opened child db failed + Err(e) => { + auto_open_dbs_info + .opening_failed_dbs + .insert(db_key_to_open, e.to_string()); + } + }, + // load_kdbx call of child db failed + Err(e) => { + auto_open_dbs_info + .opening_failed_dbs + .insert(db_key_to_open, e.to_string()); + } + } + } + } else { + auto_open_dbs_info.error_messages.push(format!( + "Cound not form a valid url from {:?}", + kvs.get(kp_service::entry_keyvalue_key::USER_NAME).cloned() + )); + } + } +} + +// Here we collect all data on opening a database and this is +// based on the steps done in :common/kdbx-database-loading-complete of src/main/onekeepass/frontend/events/common.cljs +fn load_init_data( + grouping_kind: &EntryCategoryGrouping, + kdbx_loaded: &KdbxLoaded, +) -> Result { + let child_db_key = &kdbx_loaded.db_key; + + let all_tags = kp_service::collect_entry_group_tags(child_db_key)?; + + let groups_tree = kp_service::groups_summary_data(&child_db_key)?; + + let entry_categories = kp_service::combined_category_details(child_db_key, grouping_kind)?; + + let entry_type_headers = kp_service::entry_type_headers(child_db_key)?; + + Ok(AutoOpenedDbInitData { + kdbx_loaded: kdbx_loaded.clone(), + all_tags, + groups_tree, + entry_categories, + entry_type_headers, + }) +} \ No newline at end of file diff --git a/src-tauri/src/auto_open.rs b/src-tauri/src/auto_open/resolver.rs similarity index 94% rename from src-tauri/src/auto_open.rs rename to src-tauri/src/auto_open/resolver.rs index 07d421b..5b842f0 100644 --- a/src-tauri/src/auto_open.rs +++ b/src-tauri/src/auto_open/resolver.rs @@ -8,17 +8,17 @@ use std::path::Path; #[derive(Default, Debug, Deserialize)] pub(crate) struct AutoOpenProperties { - source_db_key: String, - url_field_value: Option, - key_file_path: Option, - device_if_val: Option, + pub(crate) source_db_key: String, + pub(crate) url_field_value: Option, + pub(crate) key_file_path: Option, + pub(crate) device_if_val: Option, } #[derive(Default, Debug, Serialize)] pub(crate) struct AutoOpenPropertiesResolved { - url_field_value: Option, - key_file_path: Option, - can_open: bool, + pub(crate) url_field_value: Option, + pub(crate) key_file_path: Option, + pub(crate) can_open: bool, } impl AutoOpenProperties { @@ -117,7 +117,10 @@ fn resolved_path(parent_dir_path: &Path, in_path: &String) -> Result { } else { let p = parent_dir_path.join(&parsed.full_path_part); // If the canonicalize path is not found, then this will return an error - p.canonicalize().map_err(|e| Error::AutoOpenError(format!("Error: Path {:?} : {}", &p,e)))?.to_string_lossy().to_string() + p.canonicalize() + .map_err(|e| Error::AutoOpenError(format!("Error: Path {:?} : {}", &p, e)))? + .to_string_lossy() + .to_string() }; // let mut p = parent_dir_path.join(&parsed.full_path_part); @@ -222,7 +225,6 @@ mod tests { let resolved = input.resolve().unwrap(); println!("resolved is {:?}", resolved); - } } @@ -281,4 +283,4 @@ mod tests { // println!("s is {:?}", &p); } -*/ \ No newline at end of file +*/ diff --git a/src-tauri/src/commands.rs b/src-tauri/src/commands.rs index d30f19b..6395fad 100644 --- a/src-tauri/src/commands.rs +++ b/src-tauri/src/commands.rs @@ -13,7 +13,7 @@ use std::path::Path; use uuid::Uuid; use crate::app_state::SystemInfoWithPreference; -use crate::auto_open::{AutoOpenProperties, AutoOpenPropertiesResolved}; +use crate::auto_open::{self, AutoOpenProperties, AutoOpenPropertiesResolved}; use crate::menu::{self, MenuActionRequest, MenuTitleChangeRequest}; use crate::{app_paths, pass_phrase, translation}; use crate::{app_preference, app_state}; @@ -353,6 +353,22 @@ pub(crate) async fn resolve_auto_open_properties( Ok(auto_open_properties.resolve()?) } +#[command] +pub(crate) async fn open_all_auto_open_dbs( + db_key: &str, + app_state: State<'_, app_state::AppState>, +) -> Result { + Ok(auto_open::open_all_auto_open_dbs(db_key, app_state)?) +} + + +#[command] +pub(crate) async fn auto_open_group_uuid( + db_key: &str, +) -> Result> { + Ok(kp_service::auto_open_group_uuid(db_key,)?) +} + #[command] pub(crate) async fn history_entry_by_index( db_key: &str, @@ -526,7 +542,7 @@ pub(crate) async fn combined_category_details( ) -> Result { Ok(kp_service::combined_category_details( &db_key, - grouping_kind, + &grouping_kind, )?) } diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 4847ea0..4af3731 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -93,6 +93,7 @@ fn main() { commands::active_window_to_auto_type, commands::analyzed_password, commands::authenticate_with_biometric, + commands::auto_open_group_uuid, commands::clear_recent_files, commands::clone_entry, commands::close_kdbx, @@ -137,6 +138,7 @@ fn main() { commands::move_group_to_recycle_bin, commands::new_blank_group, commands::new_entry_form_data, + commands::open_all_auto_open_dbs, commands::parse_auto_type_sequence, commands::platform_window_titles, commands::read_and_verify_db_file, diff --git a/src/main/onekeepass/frontend/background.cljs b/src/main/onekeepass/frontend/background.cljs index 214b32f..e8ae6a4 100644 --- a/src/main/onekeepass/frontend/background.cljs +++ b/src/main/onekeepass/frontend/background.cljs @@ -165,7 +165,7 @@ "Calls the API to unlock the previously opened db file. Calls the dispatch-fn with the received map of type 'KdbxLoaded' " - [db-key password key-file-name dispatch-fn] + [db-key password key-file-name dispatch-fn] (invoke-api "unlock_kdbx" {:db-key db-key :password password :key-file-name key-file-name} dispatch-fn)) @@ -493,6 +493,8 @@ (defn- handle-argon2-renaming "A custom transform fuction to make sure Argon2 is converted to :Argon2 not converted to :argon-2 so that we can keep same as generated by serde + + The arg 'data' is map (only js->clj done) from struct DbSettings " [data] (let [t (fn [k] (if (= k "Argon2") @@ -599,10 +601,6 @@ (invoke-api api-to-call (clj->js api-args) dispatch-fn :convert-request false))) -;;;;;;;;;;;;;;; Auto open ;;;;;;;;;;;;;; - -(defn resolve-auto-open-properties [auto-open-properties dispatch-fn] - (invoke-api "resolve_auto_open_properties" {:autoOpenProperties auto-open-properties} dispatch-fn)) ;;;;;;;;;;;;;;;; OTP related ;;;;;;;;;;;; diff --git a/src/main/onekeepass/frontend/background_auto_open.cljs b/src/main/onekeepass/frontend/background_auto_open.cljs new file mode 100644 index 0000000..b3e570e --- /dev/null +++ b/src/main/onekeepass/frontend/background_auto_open.cljs @@ -0,0 +1,59 @@ +(ns onekeepass.frontend.background-auto-open + (:require + [camel-snake-kebab.extras :as cske] + [camel-snake-kebab.core :as csk] + [onekeepass.frontend.background-common :as bg-cmn :refer [invoke-api]])) + +(def GT "groups_tree") + +(def GT-KW :groups-tree) + +(defn- transform-ao-init-data-response + "The arg is a map from struct AutoOpenedDbInitData where keys are still string" + [auto-open-init-data] + (let [;; We need to exclude 'groups_tree' field from the incoming map + without-groups-tree-m (dissoc auto-open-init-data GT) + ;; Groups tree data + groups-tree-data (get auto-open-init-data GT) + ;; We transform all other keys of maps recursively + transformed-m (cske/transform-keys csk/->kebab-case-keyword without-groups-tree-m)] + ;; Add back the Groups tree data to the final map + (assoc transformed-m GT-KW groups-tree-data))) + +(defn- transform-ao-dbs-info + "The arg auto-open-dbs-info is a map from struct AutoOpenDbsInfo" + [auto-open-dbs-info] + (let [;; Only top level keys of the incoming map are transformed + keys-transformed-m (->> auto-open-dbs-info (map (fn [[k v]] [(csk/->kebab-case-keyword k) v])) (into {})) + ;; extract the vec of maps (struct AutoOpenedDbInitData) in key :opened-dbs + init-data-v (:opened-dbs keys-transformed-m) + ;; Apply the custom key transform to each map found in that vec + init-data-v (mapv transform-ao-init-data-response init-data-v)] + ;; Replace the :opened-dbs value to this map with transformed key + (assoc keys-transformed-m :opened-dbs init-data-v))) + +(defn open-all-auto-open-dbs + "Called to auto open all child databases using entries found under AutoOpen group of this db" + [db-key dispatch-fn] + ;; The dispatch-fn is called with a map corresponding to struct 'AutoOpenDbsInfo' + ;; We need to take care of transformation of api response by custom transformer fn where we + ;; do 'keywordize-keys' all keys except "groups_tree" in the response + (invoke-api "open_all_auto_open_dbs" {:db-key db-key} dispatch-fn :convert-response-fn transform-ao-dbs-info)) + +(defn resolve-auto-open-properties [auto-open-properties dispatch-fn] + (invoke-api "resolve_auto_open_properties" {:autoOpenProperties auto-open-properties} dispatch-fn)) + +(defn auto-open-group-uuid [db-key dispatch-fn] + ;; ;convert-response false ensures that returned uuid is not transformed to kw + (invoke-api "auto_open_group_uuid" {:db-key db-key} dispatch-fn :convert-response false)) + +(comment + (-> @re-frame.db/app-db keys) + (require '[clojure.pprint :refer [pprint]]) + (-> @re-frame.db/app-db (get db-key) keys) + (def db-key (:current-db-file-name @re-frame.db/app-db)) + + (def test-atom (atom nil)) + + (open-all-auto-open-dbs (:current-db-file-name @re-frame.db/app-db) #(reset! test-atom %))) + diff --git a/src/main/onekeepass/frontend/background_common.cljs b/src/main/onekeepass/frontend/background_common.cljs index c9b3e25..43145a0 100644 --- a/src/main/onekeepass/frontend/background_common.cljs +++ b/src/main/onekeepass/frontend/background_common.cljs @@ -80,16 +80,19 @@ api-args) r (clj call) + ;; represented as #js {..} + ;; As compared to mobile cljs, here 'r' is typically serialized string from stuct Result (dispatch-fn {:result (cond (not (nil? convert-response-fn)) (-> r js->clj convert-response-fn) ;; custom transformer of response - + (and convert-response (string? r)) (csk/->kebab-case-keyword r) - + + ;; Recursively the keys are transformed as kw convert-response (->> r js->clj (cske/transform-keys csk/->kebab-case-keyword)) @@ -98,7 +101,12 @@ (js->clj r))}) ;; Just to track db modifications if any (dispatch [:common/db-api-call-completed name])) - (catch js/Error err + + ;; Promise returns error,when tauri calls return Err(..) and then this catch clause is called + ;; This is different from the way done in mobile cljs + ;; In mobile cljs r is a map {:ok somevalue, :error nil} or {:ok nil, :error someError} + ;; Also promise reject in mobile app results in {:ok nil, :error rejectError} + (catch js/Error err (do ;;Call the dispatch-fn with any error returned by the backend API (dispatch-fn {:error (ex-cause err)}) diff --git a/src/main/onekeepass/frontend/background_password.cljs b/src/main/onekeepass/frontend/background_password.cljs index eab1c80..b4204e4 100644 --- a/src/main/onekeepass/frontend/background_password.cljs +++ b/src/main/onekeepass/frontend/background_password.cljs @@ -4,7 +4,6 @@ [camel-snake-kebab.core :as csk] [onekeepass.frontend.background-common :as bg-cmn :refer [invoke-api]])) - (defn analyzed-password "Generates a password with the given options and returns the generated password with its analysis" diff --git a/src/main/onekeepass/frontend/core.cljs b/src/main/onekeepass/frontend/core.cljs index 6447bef..5ca3988 100644 --- a/src/main/onekeepass/frontend/core.cljs +++ b/src/main/onekeepass/frontend/core.cljs @@ -5,6 +5,8 @@ [onekeepass.frontend.entry-form-ex :as eform-ex] [onekeepass.frontend.entry-list :as el] [onekeepass.frontend.events.common :as cmn-events] + ;; Just to load events defined in this ns + [onekeepass.frontend.events.auto-open] [onekeepass.frontend.events.tauri-events :as tauri-events] [onekeepass.frontend.mui-components :as m :refer [custom-theme-atom mui-box diff --git a/src/main/onekeepass/frontend/entry_form/fields.cljs b/src/main/onekeepass/frontend/entry_form/fields.cljs index f1b3435..229a16f 100644 --- a/src/main/onekeepass/frontend/entry_form/fields.cljs +++ b/src/main/onekeepass/frontend/entry_form/fields.cljs @@ -54,7 +54,7 @@ :on-click #(form-events/entry-form-field-visibility-toggle key)} [mui-icon-visibility-off]])) ;; Open with the url - (when (= key URL) + (when (and (not edit) (= key URL)) [mui-icon-button {:sx {:margin-right "-8px"} :edge "end" :on-click #(form-events/entry-form-open-url val)} @@ -132,15 +132,7 @@ :else ;; It is assumed translation is done already key) - val (to-value kv) #_(cond - edit - value - - (and (not edit) (not (nil? read-value))) - read-value - - :else - value)] + val (to-value kv)] [m/text-field {:sx (merge {:margin-top "16px"} (cc/password-helper-text-sx (:name password-score))) :fullWidth true :label label diff --git a/src/main/onekeepass/frontend/entry_form_ex.cljs b/src/main/onekeepass/frontend/entry_form_ex.cljs index 77617e6..0e4174e 100644 --- a/src/main/onekeepass/frontend/entry_form_ex.cljs +++ b/src/main/onekeepass/frontend/entry_form_ex.cljs @@ -1023,43 +1023,6 @@ ;;;;;;;;;;;;;;;;;;; -#_(defn get-section-data - "Called to set up any entry type specific data in kv - Returns an vec of kvd map for a section - " - [entry-type-uuid section-name section-fields parsed-fields] - (let [section-data (get section-fields section-name)] - (if (not= entry-type-uuid const/UUID_OF_ENTRY_TYPE_AUTO_OPEN) - (let [adjusted-section-data (mapv - (fn [{:keys [key] :as m}] - (assoc m :read-value (place-holder-resolved-value parsed-fields key))) - section-data)] - adjusted-section-data) - (let [adjusted-section-data (mapv - (fn [{:keys [key] :as m}] - ;; Note the use of lstr-field-name vs tr-entry-field-name-cv - ;; lstr-field-name is fn and tr-entry-field-name-cv is a macro - (cond - (= key URL) - ;; for now read-value is not used - ;;:read-value (:url-field-value m) - (assoc m :field-name (tr-entry-field-name-cv "autoOpenKdbxFileOpen")) - - (= key USERNAME) - (assoc m :field-name (lstr-field-name 'autoOpenKeyFile) - :read-value (place-holder-resolved-value parsed-fields key)) ;; :read-value (:key-file-path m) - - (= key PASSWORD) - (assoc m :read-value (place-holder-resolved-value parsed-fields key)) - - (= key IFDEVICE) - (assoc m :field-name (tr-entry-field-name-cv "autoOpenIfDevice")) - - :else - (assoc m :read-value (place-holder-resolved-value parsed-fields key)))) - section-data)] - adjusted-section-data)))) - #_(defn add-modify-section-field-popper [{:keys [dialog-show popper-anchor-el diff --git a/src/main/onekeepass/frontend/events/auto_open.cljs b/src/main/onekeepass/frontend/events/auto_open.cljs new file mode 100644 index 0000000..3b71814 --- /dev/null +++ b/src/main/onekeepass/frontend/events/auto_open.cljs @@ -0,0 +1,157 @@ +(ns onekeepass.frontend.events.auto-open + (:require + [clojure.string :as str] + [onekeepass.frontend.background :as bg] + + [onekeepass.frontend.events.common :as cmn-events :refer [active-db-key + update-db-opened + assoc-in-with-db-key + get-in-with-db-key + check-error]] + [onekeepass.frontend.constants + :as const + :refer [GROUPING_LABEL_TYPES GROUPING_LABEL_TAGS + GROUPING_LABEL_CATEGORIES GROUPING_LABEL_GROUPS]] + [onekeepass.frontend.background-auto-open :as bg-ao] + [re-frame.core :refer [dispatch reg-event-fx reg-fx]])) + +(reg-event-fx + :auto-open/verify-and-load + (fn [{:keys [_db]} [_event-id main-db-key]] + (bg-ao/auto-open-group-uuid main-db-key (fn [api-response] + (when-some [ao-group-uuid (check-error api-response)] + (dispatch [:load-child-databases main-db-key])))) + {})) + +(reg-event-fx + :load-child-databases + (fn [{:keys [_db]} [_event-id main-db-key]] + {:fx [[:dispatch [:common/progress-message-box-show "Loading" "Please wait..."]] + [:bg-load-open-all-auto-open-dbs [main-db-key]]]})) + +(reg-fx + :bg-load-open-all-auto-open-dbs + (fn [[main-db-key]] + (bg-ao/open-all-auto-open-dbs main-db-key + (fn [api-response] + ;; auto-open-dbs-info is map from AutoOpenDbsInfo + (when-some [auto-open-dbs-info (check-error api-response)] + (dispatch [:common/progress-message-box-hide]) + (dispatch [:open-all-auto-open-dbs-done auto-open-dbs-info])))))) + +;; (dispatch [:load-all-tags-completed result]) +#_(assoc-in-key-db db + [:tags :all] + (into [] + (concat (:entry-tags result) + (:group-tags result)))) +#_(reg-event-db + :groups-tree-data-update + (fn [db [_event-id v]] + (assoc-in-key-db db [:groups-tree :data] v))) + +;; (reg-event-fx :update-category-data + +#_(let [{:keys [grouping-kind grouped-categories]} entry-categories + sorted-grouped-categories (if (= grouping-kind "AsTags") + (sort-by-tag-name grouped-categories) + grouped-categories) + entry-categories (merge entry-categories {:grouped-categories sorted-grouped-categories})] + {:db (assoc-in-key-db db [:entry-category :data] entry-categories)}) + +;; (assoc-in-key-db db [:entry-type-headers] et-headers-m) + +;; kdbx_loaded: KdbxLoaded, +;; all_tags: AllTags, +;; groups_tree: GroupTree, +;; entry_categories: EntryCategories, +;; entry_type_headers: EntryTypeHeaders, + +;; opened_dbs: Vec, + +;; // failed db keys with error message +;; opening_failed_dbs: HashMap, + +;; error_messages: Vec, + +;; (-> db :app-preference :default-entry-category-groupings) + +(defn to-entry-groupings-kind-kw + "Converts the string value of grouping label to an appropriate keyword" + [start-view-to-show] + (cond + (= start-view-to-show GROUPING_LABEL_TYPES) :type + (= start-view-to-show GROUPING_LABEL_CATEGORIES) :category + (= start-view-to-show GROUPING_LABEL_GROUPS) :group + (= start-view-to-show GROUPING_LABEL_TAGS) :tag + :else :type)) + +(defn sort-by-tag-name [grouped-categories] + ;; First fn provides the comparision key + ;; Second fn provides the comparator that uses the keys + (sort-by (fn [m] (:title m)) (fn [v1 v2] (compare v1 v2)) grouped-categories)) + +(defn open-child-database [app-db {:keys [kdbx-loaded all-tags groups-tree entry-categories entry-type-headers]}] + (let [{:keys [db-key]} kdbx-loaded + showing-as (to-entry-groupings-kind-kw (-> app-db :app-preference :default-entry-category-groupings)) + {:keys [grouping-kind grouped-categories]} entry-categories + sorted-grouped-categories (if (= grouping-kind "AsTags") + (sort-by-tag-name grouped-categories) + grouped-categories) + entry-categories (merge entry-categories {:grouped-categories sorted-grouped-categories})] + (-> app-db + (update-db-opened kdbx-loaded) + (assoc-in-with-db-key db-key + [:tags :all] + (into [] + (concat (:entry-tags all-tags) + (:group-tags all-tags)))) + (assoc-in-with-db-key db-key [:groups-tree :data] groups-tree) + (assoc-in-with-db-key db-key [:entry-category :showing-groups-as] showing-as) + (assoc-in-with-db-key db-key [:entry-category :data] entry-categories) + (assoc-in-with-db-key db-key [:entry-type-headers] entry-type-headers)))) + +(defn open-all-child-databases + "Returns the updated app-db" + [app-db opened-dbs] + (reduce (fn [db db-init-data] (open-child-database db db-init-data)) app-db opened-dbs)) + +(reg-event-fx + :open-all-auto-open-dbs-done + (fn [{:keys [db]} [_event-id {:keys [opened-dbs opening-failed-dbs error-messages] :as auto-open-dbs-info}]] + (if-not (empty? opened-dbs) + {:db (-> db (open-all-child-databases opened-dbs)) + + } + {}) + #_{:db (-> db (assoc-in [:auto-open-dbs-info] auto-open-dbs-info))})) + +(comment + (-> @re-frame.db/app-db keys) + (require '[clojure.pprint :refer [pprint]]) + (-> @re-frame.db/app-db (get db-key) keys) + (def db-key (:current-db-file-name @re-frame.db/app-db))) + + + +#_(reg-event-fx + :auto-open-load-databases + (fn [{:keys [_db]} [_event-id main-db-key]] + (bg-ao/open-all-auto-open-dbs main-db-key (fn [api-response] + ;; auto-open-dbs-info is map from AutoOpenDbsInfo + (when-some [auto-open-dbs-info (check-error api-response)] + (dispatch [:open-all-auto-open-dbs-done auto-open-dbs-info])))) + {})) + +#_(reg-event-fx + :auto-open/load-child-databases + (fn [{:keys [db]} [_event-id main-db-key]] + (let [group-tree-data (get-in-with-db-key db main-db-key [:groups-tree :data]) + ao-group-uuid (get group-tree-data "auto_open_group_uuid")] + + (println "(empty? group-tree-data) (not (nil? ao-group-uuid)) " (empty? group-tree-data) (not (nil? ao-group-uuid))) + (if (or (empty? group-tree-data) (not (nil? ao-group-uuid))) + {:fx [[:bg-load-open-all-auto-open-dbs [main-db-key]]]} + {})))) + + diff --git a/src/main/onekeepass/frontend/events/common.cljs b/src/main/onekeepass/frontend/events/common.cljs index b322371..be6812b 100644 --- a/src/main/onekeepass/frontend/events/common.cljs +++ b/src/main/onekeepass/frontend/events/common.cljs @@ -226,6 +226,20 @@ ;;:database-name (:database-name meta) })))) +(defn update-db-opened + "Updates the db list and current active db key when a new kdbx database is loaded + The args are the re-frame 'app-db' and KdbxLoaded struct returned by backend API. + Returns the updated app-db + " + [app-db {:keys [db-key database-name file-name key-file-name]}] ;;kdbx-loaded + (let [app-db (if (nil? (:opened-db-list app-db)) (assoc app-db :opened-db-list []) app-db)] + (-> app-db + (update-in [:opened-db-list] conj {:db-key db-key + :database-name database-name + :file-name file-name + :key-file-name key-file-name + :user-action-time (js/Date.now)})))) + (defn active-db-key ;; To be called only in react components as it used 'subscribe' (i.e in React context) ([] @@ -239,10 +253,10 @@ (defn set-active-db-key "Sets the new current active db" - [db-key] + [db-key] (dispatch [:common/change-active-db-complete db-key])) -(defn set-active-db-key-direct +(defn set-active-db-key-direct "Called to set the current db to the given db-key and thus making it active It is assumed that the 'db-key' is already available in the opened db list Returns the updated app-db map @@ -287,6 +301,18 @@ kdb (get app-db kdbx-db-key)] (assoc app-db kdbx-db-key (assoc-in kdb ks v)))) +(defn assoc-in-with-db-key + "Called to associate the value in 'v' to the keys 'ks' location + in the db for the selected db key and then updates the main db + with this new key db + Returns the main db + " + [app-db db-key ks v] + ;;Get db with db_key and update that map with v in ks + ;;Then update the main db + (let [kdb (get app-db db-key)] + (assoc app-db db-key (assoc-in kdb ks v)))) + #_(defn get-in-key-db "Gets the value for the key lists from an active kdbx content" [app-db ks] @@ -296,12 +322,20 @@ (defn get-in-key-db "Gets the value for the key lists from an active kdbx content" ([app-db ks] - ;; First we get the kdbx content map and then supplied keys 'ks' used to get the actual value + ;; First we get the kdbx content map and then supplied keys 'ks' used to get the actual value + ;; ks may be single kw or vec of keywords (get-in app-db (into [(active-db-key app-db)] ks))) - ([app-db ks default] (get-in app-db (into [(active-db-key app-db)] ks) default))) +(defn get-in-with-db-key + "Gets the value for the key lists from an active kdbx content" + ([app-db db-key ks] + ;; ks may be single kw or vec of keywords + (get-in app-db (into [db-key] ks))) + + ([app-db db-key ks default] + (get-in app-db (into [db-key] ks) default))) (defn save-as "Called when user wants to save a modified db to another name" @@ -330,14 +364,16 @@ (reg-event-fx :common/kdbx-database-loading-complete - (fn [{:keys [db]} [_event-id kdbx-loaded]] + (fn [{:keys [db]} [_event-id {:keys [db-key] :as _kdbx-loaded}]] {:fx [[:dispatch [:load-all-tags]] [:dispatch [:group-tree-content/load-groups]] [:dispatch [:entry-category/category-data-load-start (-> db :app-preference :default-entry-category-groupings)]] [:dispatch [:common/load-entry-type-headers]] [:dispatch [:common/message-snackbar-open - (lstr-sm 'dbOpened {:dbFileName (:db-key kdbx-loaded)})]]]})) + (lstr-sm 'dbOpened {:dbFileName db-key})]] + ;; This db may have AutoOpen group + [:dispatch [:auto-open/verify-and-load db-key]]]})) ;; A common refresh all forms after an entry form changes - delete, put back , delete permanent (reg-event-fx @@ -466,7 +502,7 @@ ([] (subscribe [:common/current-db-locked])) ;; Following two fns access the app-db directly - ([app-db] + ([app-db] ;; Current db key is used (boolean (get-in-key-db app-db [:locked]))) ([app-db db-key] @@ -499,7 +535,7 @@ ;; Dispatched from a open-db-form event (reg-event-fx :common/kdbx-database-unlocked - (fn [{:keys [db]} [_event-id _kdbx-loaded]] + (fn [{:keys [db]} [_event-id _kdbx-loaded]] {:db (assoc-in-key-db db [:locked] false) :fx [;; TODO: Combine these reset calls with 'common/kdbx-database-loading-complete' [:dispatch [:load-all-tags]] @@ -1067,8 +1103,8 @@ :common/bg-open-file (fn [[path]] (bg/open-file path - (fn [api-response] - (on-error api-response))))) + (fn [api-response] + (on-error api-response))))) ;;;;;;;;;;;;;;;;;;;;;;;;;; Common Dialog ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/src/main/onekeepass/frontend/events/common_supports.cljs b/src/main/onekeepass/frontend/events/common_supports.cljs index 322d010..c430539 100644 --- a/src/main/onekeepass/frontend/events/common_supports.cljs +++ b/src/main/onekeepass/frontend/events/common_supports.cljs @@ -31,8 +31,12 @@ (if-not (nil? error) (do (if (nil? error-fn) - (dispatch [:common/message-snackbar-error-open error]) - (error-fn error)) + (do + (dispatch [:common/message-snackbar-error-open error]) + (dispatch [:common/progress-message-box-hide])) + (do + (error-fn error) + (dispatch [:common/progress-message-box-hide]))) nil) result)) ([api-response] diff --git a/src/main/onekeepass/frontend/events/entry_form_auto_open.cljs b/src/main/onekeepass/frontend/events/entry_form_auto_open.cljs index eee38d1..68ac8c3 100644 --- a/src/main/onekeepass/frontend/events/entry_form_auto_open.cljs +++ b/src/main/onekeepass/frontend/events/entry_form_auto_open.cljs @@ -1,26 +1,29 @@ (ns onekeepass.frontend.events.entry-form-auto-open (:require - [clojure.string :as str] - [onekeepass.frontend.background :as bg] + [clojure.string :as str] [onekeepass.frontend.constants :as const :refer [IFDEVICE PASSWORD URL USERNAME]] [onekeepass.frontend.events.common :as cmn-events :refer [active-db-key - check-error - on-error]] + check-error]] [onekeepass.frontend.events.entry-form-common :refer [extract-form-field-names-values form-data-kv-data get-form-data place-holder-resolved-value]] + [onekeepass.frontend.background-auto-open :as bg-ao] [re-frame.core :refer [dispatch reg-event-fx reg-fx]])) -(defn entry-form-open-url [url-value] +(defn entry-form-open-url + "Called when user clicks on the lauch icon in the entry form url field" + [url-value] (dispatch [:entry-form-open-url url-value])) + (reg-event-fx :entry-form-open-url (fn [{:keys [_db]} [_event-id url-value]] (cond + ;; The url is expected to start with lowercase at this time (str/starts-with? url-value "kdbx:") {:fx [[:dispatch [:entry-form-auto-open-resolve-properties]]]} @@ -30,6 +33,7 @@ (str/starts-with? url-value "file://") {:fx [[:common/bg-open-file [url-value]]]} + ;; Just add the prefix and open :else {:fx [[:common/bg-open-url [(str "https://" url-value)]]]}))) @@ -41,7 +45,9 @@ (check-error api-response #(dispatch [:entry-form-auto-open-properties-resolve-error %]))] (dispatch [:entry-form-auto-open-properties-resolved ao-keys auto-props-resolved]))) -;; + +;; This event is called to resolve auto open properties before +;; using that info to open a database (reg-event-fx :entry-form-auto-open-resolve-properties (fn [{:keys [db]} [_event-id]] @@ -50,6 +56,7 @@ (if (= entry-type-uuid const/UUID_OF_ENTRY_TYPE_AUTO_OPEN) (let [field-m (extract-form-field-names-values form-data) parsed-fields (:parsed-fields form-data) + ;; Ensure that all place holders in the entry fields are parsed url (place-holder-resolved-value parsed-fields URL (get field-m URL)) key-file-path (place-holder-resolved-value parsed-fields USERNAME (get field-m USERNAME)) auto-props {:source-db-key (active-db-key db) @@ -59,11 +66,14 @@ {:fx [[:bg-resolve-auto-open-properties [auto-props (partial auto-open-properties-dispatch-fn all-auto-open-kvd-keys)]]]}) {})))) +;; Backend api is called to ensure that db file and key file paths +;; are valid (reg-fx :bg-resolve-auto-open-properties (fn [[auto-props dispatch-fn]] - (bg/resolve-auto-open-properties auto-props dispatch-fn))) + (bg-ao/resolve-auto-open-properties auto-props dispatch-fn))) +;; The db file and key file paths are resolved and valid (reg-event-fx :entry-form-auto-open-properties-resolved (fn [{:keys [db]} [_event-id _ao-keys {:keys [url-field-value key-file-path can-open]}]] diff --git a/src/main/onekeepass/frontend/events/open_db_form.cljs b/src/main/onekeepass/frontend/events/open_db_form.cljs index d0ebaba..ce91e58 100644 --- a/src/main/onekeepass/frontend/events/open_db_form.cljs +++ b/src/main/onekeepass/frontend/events/open_db_form.cljs @@ -1,6 +1,5 @@ (ns onekeepass.frontend.events.open-db-form - (:require - [clojure.string :as str] + (:require [re-frame.core :refer [reg-event-db reg-event-fx reg-fx reg-sub dispatch subscribe]] [onekeepass.frontend.events.common :as cmn-events :refer [check-error active-db-key @@ -143,7 +142,12 @@ (fn [db [_event-id]] (init-open-db-vals db))) -(declare on-file-loading) +(declare unlock-response-handler) + +(defn- on-file-loading [api-response] + (let [error-fn (fn [err] (dispatch [:open-db-error err]))] + (when-let [kdbx-loaded (check-error api-response error-fn)] + (dispatch [:open-db-file-loading-done kdbx-loaded])))) (reg-event-fx :open-db-login-credential-entered @@ -153,32 +157,34 @@ (assoc-in [:open-db :error-fields] {}) (assoc-in [:open-db :status] :in-progress)) :fx [(if unlock-request - [ :bg-unlock-kdbx-file [(active-db-key db) pwd key-file-name]] - [ :bg-load-kdbx-file [file-name pwd key-file-name on-file-loading]])]}))) + [:bg-unlock-kdbx-file [(active-db-key db) pwd key-file-name unlock-response-handler]] + [:bg-load-kdbx-file [file-name pwd key-file-name on-file-loading]])]}))) -(reg-event-db +#_(reg-event-db + :open-db-error + (fn [db [_event-id error]] + (-> db (assoc-in [:open-db :error-text] error) + (assoc-in [:open-db :status] :error)))) + +(reg-event-fx :open-db-error - (fn [db [_event-id error]] - (-> db (assoc-in [:open-db :error-text] error) - (assoc-in [:open-db :status] :error)))) + (fn [{:keys [db]} [_event-id error]] + {:db (-> db (assoc-in [:open-db :error-text] error) + (assoc-in [:open-db :status] :error)) + :fx [[:dispatch [:common/progress-message-box-hide]]]})) (reg-event-fx :open-db-file-loading-done (fn [{:keys [db]} [_event-id kdbx-loaded]] ;; will hide dialog - {:db (-> db init-open-db-vals) + {:db (-> db init-open-db-vals) ;; Need to hide any progress msg dialog if shown :fx [[:dispatch [:common/progress-message-box-hide]] [:dispatch [:common/kdbx-database-opened kdbx-loaded]]]})) -(defn- on-file-loading [api-response] - (let [error-fn (fn [err] (dispatch [:open-db-error err]))] - (when-let [kdbx-loaded (check-error api-response error-fn)] - (dispatch [:open-db-file-loading-done kdbx-loaded])))) - ;;IMPORTANT reg-fx handler fn takes single argument. So we need to use vec [file-name pwd] (reg-fx - :bg-load-kdbx-file + :bg-load-kdbx-file (fn [[file-name pwd key-file-name on-file-loading]] (bg/load-kdbx file-name pwd key-file-name on-file-loading))) @@ -188,15 +194,15 @@ {:db (-> db init-open-db-vals) ;; will hide dialog :fx [[:dispatch [:common/kdbx-database-unlocked kdbx-loaded]]]})) -#_(defn- unlock-response-handler [api-response] +(defn- unlock-response-handler [api-response] (when-let [kdbx-loaded (check-error api-response #(dispatch [:open-db-error %]))] (dispatch [:unlock-db-file-loading-done kdbx-loaded]))) (reg-fx - :bg-unlock-kdbx-file - (fn [[db-key pwd key-file-name dispatch-fn]] + :bg-unlock-kdbx-file + (fn [[db-key pwd key-file-name dispatch-fn]] (bg/unlock-kdbx db-key pwd key-file-name dispatch-fn))) (reg-event-fx @@ -222,7 +228,6 @@ (dispatch [:open-db-biometric-login-success]) (dispatch [:open-db-biometric-login-fail])))))))) - (reg-event-fx :open-db-biometric-login-success (fn [{:keys [db]} [_event-id]] @@ -232,12 +237,12 @@ (reg-fx :bg-unlock-kdbx-on-biometric-authentication (fn [[db-key]] - (bg/unlock-kdbx-on-biometric-authentication db-key - (fn [api-response] - (when-let [kdbx-loaded (check-error - api-response - #(dispatch [:open-db-error %]))] - (dispatch [:unlock-db-file-loading-done kdbx-loaded])))))) + (bg/unlock-kdbx-on-biometric-authentication db-key unlock-response-handler + #_(fn [api-response] + (when-let [kdbx-loaded (check-error + api-response + #(dispatch [:open-db-error %]))] + (dispatch [:unlock-db-file-loading-done kdbx-loaded])))))) (reg-event-fx @@ -254,15 +259,12 @@ ;;;;;;;;;;;;;;;;;;;; auto db open ;;;;;;;;;;;;;;;;;;; -(defn- handle-auto-open-response [api-response] +(defn- handle-auto-open-response [api-response] (when-let [kdbx-loaded (check-error api-response)] (dispatch [:open-db-file-loading-done kdbx-loaded]))) -(defn- handle-auto-open-unlock-response [api-response] - (when-let [kdbx-loaded (check-error - api-response - #(dispatch [:open-db-error %]))] - (dispatch [:common/progress-message-box-hide]) +(defn- handle-auto-open-unlock-response [api-response] + (when-let [kdbx-loaded (check-error api-response)] (dispatch [:auto-open-unlock-db-file-loading-done kdbx-loaded]))) (reg-event-fx @@ -296,7 +298,8 @@ ;; by the event handler in ':common/kdbx-database-unlocked' where the lcoked status ;; set to false {:db (cmn-events/set-active-db-key-direct db db-key) - :fx [[:dispatch [:common/kdbx-database-unlocked kdbx-loaded]]]})) + :fx [[:dispatch [:common/progress-message-box-hide]] + [:dispatch [:common/kdbx-database-unlocked kdbx-loaded]]]})) (comment (keys @re-frame.db/app-db) diff --git a/src/main/onekeepass/frontend/translation.cljs b/src/main/onekeepass/frontend/translation.cljs index 36bc664..6532923 100644 --- a/src/main/onekeepass/frontend/translation.cljs +++ b/src/main/onekeepass/frontend/translation.cljs @@ -42,13 +42,18 @@ (defn- convert "Converts the case of the key string to the camelCase key as used in translation.json + The arg 'txt-key' is a string or a symbol IMPORTANT: camel-snake-kebab.core/->camelCase expects a non nil value;Otherwise an error will be thrown resulting UI not showing! " - [txt-key] + [txt-key] + ;; (str nil) => "" + ;; This ensures that non nil value is given to ->camelCase (csk/->camelCase - (if (string? txt-key) txt-key ""))) + (str txt-key)) + #_(csk/->camelCase + (if (string? txt-key) txt-key ""))) (defn lstr-dlg-title "Adds prefix 'dialog.titles' to the key before getting the translation" From f94716ba39edf41430428b49aa77122e6110ccc2 Mon Sep 17 00:00:00 2001 From: jeyasankar Date: Tue, 11 Mar 2025 11:05:53 -0700 Subject: [PATCH 13/15] Entry category grouping preference update is handled; removing UNC prefix for windows path done --- src-tauri/src/auto_open/mod.rs | 3 + src-tauri/src/auto_open/resolver.rs | 93 ++++++--------- .../frontend/entry_form/fields.cljs | 4 +- .../onekeepass/frontend/events/auto_open.cljs | 108 +++++------------- .../frontend/events/entry_category.cljs | 31 ++++- .../frontend/events/entry_form_ex.cljs | 1 + 6 files changed, 96 insertions(+), 144 deletions(-) diff --git a/src-tauri/src/auto_open/mod.rs b/src-tauri/src/auto_open/mod.rs index f07cb70..5ab1fb9 100644 --- a/src-tauri/src/auto_open/mod.rs +++ b/src-tauri/src/auto_open/mod.rs @@ -56,6 +56,9 @@ fn inner_open_all_auto_open_dbs( grouping_kind: &EntryCategoryGrouping, ) { // Get all entries of "AutoOpen" group for this db_key + // Here we are assuming all entries under auto open group are of auto open type + // If there is any entry is found here, then the url parsing will fail as it will not be kdbx:// url + // TODO: exclude non auto open entry type let entry_uuids = kp_service::auto_open_group_entry_uuids(auto_open_db_key).unwrap_or_else(|_| vec![]); diff --git a/src-tauri/src/auto_open/resolver.rs b/src-tauri/src/auto_open/resolver.rs index 5b842f0..09d2946 100644 --- a/src-tauri/src/auto_open/resolver.rs +++ b/src-tauri/src/auto_open/resolver.rs @@ -104,6 +104,28 @@ impl AutoOpenProperties { } } +// https://stackoverflow.com/questions/50322817/how-do-i-remove-the-prefix-from-a-canonical-windows-path +#[cfg(not(target_os = "windows"))] +fn adjust_canonicalization>(p: P) -> String { + p.as_ref().display().to_string() +} + +// While checking auto open on windows, windows path are resolved with prefix \\? +// and because of this recent db list includes this prefixed db keys as distinct from the same +// path without this prefix. removing this prefix ensures single entry +// This may create some issue if we want to use UNC path. In that case we may need to do this pefix removal +// only before using as db-key +#[cfg(target_os = "windows")] +fn adjust_canonicalization>(p: P) -> String { + const VERBATIM_PREFIX: &str = r#"\\?\"#; + let p = p.as_ref().display().to_string(); + if p.starts_with(VERBATIM_PREFIX) { + p[VERBATIM_PREFIX.len()..].to_string() + } else { + p + } +} + fn resolved_path(parent_dir_path: &Path, in_path: &String) -> Result { let (remaining, parsed) = parse_field_value(in_path) .map_err(|e| error::Error::AutoOpenError(format!("Parsing failed with error {}", e)))?; @@ -117,10 +139,16 @@ fn resolved_path(parent_dir_path: &Path, in_path: &String) -> Result { } else { let p = parent_dir_path.join(&parsed.full_path_part); // If the canonicalize path is not found, then this will return an error - p.canonicalize() - .map_err(|e| Error::AutoOpenError(format!("Error: Path {:?} : {}", &p, e)))? - .to_string_lossy() - .to_string() + // p.canonicalize() + // .map_err(|e| Error::AutoOpenError(format!("Error: Path {:?} : {}", &p, e)))? + // .to_string_lossy() + // .to_string() + + let pf = p.canonicalize() + .map_err(|e| Error::AutoOpenError(format!("Error: Path {:?} : {}", &p, e)))?; + + adjust_canonicalization(pf) + }; // let mut p = parent_dir_path.join(&parsed.full_path_part); @@ -227,60 +255,3 @@ mod tests { println!("resolved is {:?}", resolved); } } - -/* -#[test] - fn verify2() { - let cv = "My-MacBook-Pro16-M1.local".to_lowercase(); - let s = "Computer-one, Computer-Two, ! Computer-Six, !Computer-nine,!My-MacBook-Pro16-M1.local"; - let v: Vec = s.split(",").map(|s| s.trim().to_lowercase()).collect(); - println!("v is {:?}", &v); - - let mut exclude = false; - for c in &v { - if c.starts_with("!") { - let v1 = c.strip_prefix("!"); - let v2 = c.strip_prefix("!").is_some_and(|s| s.trim() == &cv); - println!("no ! {:?},{}", &v1, v2); - if v2 { - exclude = true; - break; - } - } else { - if c == &cv { - exclude = false; - break; - } - } - } - - println!("Exclude is {}", &exclude); - } - - #[test] - fn verify1() { - //println!("Host name is {:?}", hostname::get()); - - //println!("Host name 2 is {:?}", gethostname::gethostname().to_string_lossy().to_string()); - - println!( - "Result {:?} ", - super::parse_field_value("kdbx://{DB_DIR}/../Test14.kdbx") - ); - - println!("Result {:?} ", super::parse_field_value("./Test14.kdbx")); - - println!( - "Result {:?} ", - super::parse_field_value("kdbx://../Test14.kdbx") - ); - - // let b = "/Users/jeyasankar/Documents/OneKeePass"; - // let mut p = PathBuf::from(&b); - // p.push("/f1/PasswordsUsesKeyFile2.kdbx"); - // //let s = p.push("f1/PasswordsUsesKeyFile2.kdbx"); - - // println!("s is {:?}", &p); - } - -*/ diff --git a/src/main/onekeepass/frontend/entry_form/fields.cljs b/src/main/onekeepass/frontend/entry_form/fields.cljs index 229a16f..c2a5151 100644 --- a/src/main/onekeepass/frontend/entry_form/fields.cljs +++ b/src/main/onekeepass/frontend/entry_form/fields.cljs @@ -40,11 +40,11 @@ :else value)) -(defn- end-icons [{:keys [key protected visibile edit] :as kv}] +(defn- end-icons [{:keys [key protected visible edit] :as kv}] (let [val (to-value kv)] [:<> (when protected - (if visibile + (if visible [mui-icon-button {:sx {:margin-right "-8px"} :edge "end" :on-click #(form-events/entry-form-field-visibility-toggle key)} diff --git a/src/main/onekeepass/frontend/events/auto_open.cljs b/src/main/onekeepass/frontend/events/auto_open.cljs index 3b71814..2d97ee8 100644 --- a/src/main/onekeepass/frontend/events/auto_open.cljs +++ b/src/main/onekeepass/frontend/events/auto_open.cljs @@ -1,12 +1,8 @@ (ns onekeepass.frontend.events.auto-open (:require - [clojure.string :as str] - [onekeepass.frontend.background :as bg] - - [onekeepass.frontend.events.common :as cmn-events :refer [active-db-key - update-db-opened + [onekeepass.frontend.events.common :as cmn-events :refer [update-db-opened assoc-in-with-db-key - get-in-with-db-key + check-error]] [onekeepass.frontend.constants :as const @@ -15,12 +11,16 @@ [onekeepass.frontend.background-auto-open :as bg-ao] [re-frame.core :refer [dispatch reg-event-fx reg-fx]])) +;; Called when a database is loaded (reg-event-fx :auto-open/verify-and-load (fn [{:keys [_db]} [_event-id main-db-key]] - (bg-ao/auto-open-group-uuid main-db-key (fn [api-response] - (when-some [ao-group-uuid (check-error api-response)] - (dispatch [:load-child-databases main-db-key])))) + ;; Side effect call + (bg-ao/auto-open-group-uuid main-db-key + (fn [api-response] + (when-some [_ao-group-uuid (check-error api-response)] + ;; Load all child databases if we find a AutoOpen group with entries + (dispatch [:load-child-databases main-db-key])))) {})) (reg-event-fx @@ -39,43 +39,9 @@ (dispatch [:common/progress-message-box-hide]) (dispatch [:open-all-auto-open-dbs-done auto-open-dbs-info])))))) -;; (dispatch [:load-all-tags-completed result]) -#_(assoc-in-key-db db - [:tags :all] - (into [] - (concat (:entry-tags result) - (:group-tags result)))) -#_(reg-event-db - :groups-tree-data-update - (fn [db [_event-id v]] - (assoc-in-key-db db [:groups-tree :data] v))) - -;; (reg-event-fx :update-category-data - -#_(let [{:keys [grouping-kind grouped-categories]} entry-categories - sorted-grouped-categories (if (= grouping-kind "AsTags") - (sort-by-tag-name grouped-categories) - grouped-categories) - entry-categories (merge entry-categories {:grouped-categories sorted-grouped-categories})] - {:db (assoc-in-key-db db [:entry-category :data] entry-categories)}) - -;; (assoc-in-key-db db [:entry-type-headers] et-headers-m) - -;; kdbx_loaded: KdbxLoaded, -;; all_tags: AllTags, -;; groups_tree: GroupTree, -;; entry_categories: EntryCategories, -;; entry_type_headers: EntryTypeHeaders, - -;; opened_dbs: Vec, - -;; // failed db keys with error message -;; opening_failed_dbs: HashMap, - -;; error_messages: Vec, - -;; (-> db :app-preference :default-entry-category-groupings) - +;; TODO: +;; to-entry-groupings-kind-kw and sort-by-tag-name are copied from entry-category +;; Need to move a common package (defn to-entry-groupings-kind-kw "Converts the string value of grouping label to an appropriate keyword" [start-view-to-show] @@ -91,6 +57,10 @@ ;; Second fn provides the comparator that uses the keys (sort-by (fn [m] (:title m)) (fn [v1 v2] (compare v1 v2)) grouped-categories)) +;; IMPORTANT +;; All steps are done as in reg-event-fx :common/kdbx-database-loading-complete are done here +;; when we open a kdbx databse. If we add anything that is required on opening a database, we need to include here + (defn open-child-database [app-db {:keys [kdbx-loaded all-tags groups-tree entry-categories entry-type-headers]}] (let [{:keys [db-key]} kdbx-loaded showing-as (to-entry-groupings-kind-kw (-> app-db :app-preference :default-entry-category-groupings)) @@ -99,7 +69,7 @@ (sort-by-tag-name grouped-categories) grouped-categories) entry-categories (merge entry-categories {:grouped-categories sorted-grouped-categories})] - (-> app-db + (-> app-db (update-db-opened kdbx-loaded) (assoc-in-with-db-key db-key [:tags :all] @@ -107,51 +77,29 @@ (concat (:entry-tags all-tags) (:group-tags all-tags)))) (assoc-in-with-db-key db-key [:groups-tree :data] groups-tree) - (assoc-in-with-db-key db-key [:entry-category :showing-groups-as] showing-as) - (assoc-in-with-db-key db-key [:entry-category :data] entry-categories) + (assoc-in-with-db-key db-key [:entry-category :showing-groups-as] showing-as) + (assoc-in-with-db-key db-key [:entry-category :data] entry-categories) (assoc-in-with-db-key db-key [:entry-type-headers] entry-type-headers)))) -(defn open-all-child-databases +(defn open-all-child-databases "Returns the updated app-db" [app-db opened-dbs] (reduce (fn [db db-init-data] (open-child-database db db-init-data)) app-db opened-dbs)) (reg-event-fx :open-all-auto-open-dbs-done - (fn [{:keys [db]} [_event-id {:keys [opened-dbs opening-failed-dbs error-messages] :as auto-open-dbs-info}]] + + (fn [{:keys [db]} [_event-id {:keys [opened-dbs opening-failed-dbs error-messages] :as _auto-open-dbs-info}]] + ;;(println "opening-failed-dbs error-messages " opening-failed-dbs error-messages) + ;; TODO: + ;; Need to take care of 'opening-failed-dbs' and 'error-messages' + ;; and if we find any values there, we need to show those errors (if-not (empty? opened-dbs) - {:db (-> db (open-all-child-databases opened-dbs)) - - } - {}) - #_{:db (-> db (assoc-in [:auto-open-dbs-info] auto-open-dbs-info))})) + {:db (-> db (open-all-child-databases opened-dbs))} + {}))) (comment (-> @re-frame.db/app-db keys) (require '[clojure.pprint :refer [pprint]]) (-> @re-frame.db/app-db (get db-key) keys) (def db-key (:current-db-file-name @re-frame.db/app-db))) - - - -#_(reg-event-fx - :auto-open-load-databases - (fn [{:keys [_db]} [_event-id main-db-key]] - (bg-ao/open-all-auto-open-dbs main-db-key (fn [api-response] - ;; auto-open-dbs-info is map from AutoOpenDbsInfo - (when-some [auto-open-dbs-info (check-error api-response)] - (dispatch [:open-all-auto-open-dbs-done auto-open-dbs-info])))) - {})) - -#_(reg-event-fx - :auto-open/load-child-databases - (fn [{:keys [db]} [_event-id main-db-key]] - (let [group-tree-data (get-in-with-db-key db main-db-key [:groups-tree :data]) - ao-group-uuid (get group-tree-data "auto_open_group_uuid")] - - (println "(empty? group-tree-data) (not (nil? ao-group-uuid)) " (empty? group-tree-data) (not (nil? ao-group-uuid))) - (if (or (empty? group-tree-data) (not (nil? ao-group-uuid))) - {:fx [[:bg-load-open-all-auto-open-dbs [main-db-key]]]} - {})))) - - diff --git a/src/main/onekeepass/frontend/events/entry_category.cljs b/src/main/onekeepass/frontend/events/entry_category.cljs index 6efa4dd..59412dd 100644 --- a/src/main/onekeepass/frontend/events/entry_category.cljs +++ b/src/main/onekeepass/frontend/events/entry_category.cljs @@ -10,6 +10,7 @@ :refer [active-db-key assoc-in-key-db check-error + on-error get-in-key-db]] [re-frame.core :refer [dispatch reg-event-db reg-event-fx reg-fx reg-sub subscribe]])) @@ -104,6 +105,22 @@ (= start-view-to-show GROUPING_LABEL_TAGS) :tag :else :type)) +(defn- grouping-kind->pref-entry-category-groupings + "Converts the show-as kw to a string that is used in app preference settings" + [kw-kind] + (cond + (= kw-kind :type) + GROUPING_LABEL_TYPES + + (= kw-kind :tag) + GROUPING_LABEL_TAGS + + (= kw-kind :category) + GROUPING_LABEL_CATEGORIES + + (= kw-kind :group) + GROUPING_LABEL_GROUPS)) + (defn is-current-detail-general? "Checks whether the passed arg 'category-detail' map is from :general-categories or from :grouped-categories (for :type or :category or :tag)" @@ -128,10 +145,22 @@ [:dispatch [:selected-category-info nil]] [:dispatch [:entry-list/clear-entry-items]] [:dispatch [:entry-form-ex/show-welcome]] - [:dispatch [:load-combined-category-data kind]]]] + [:dispatch [:load-combined-category-data kind]] + [:bg-entry-category-groupings-preference [kind]] + ]] ;; here cmn-actions is a vec of vec {:fx cmn-actions}))) +(reg-fx + :bg-entry-category-groupings-preference + (fn [[showin-kind-kw]] + (bg/update-preference {:default-entry-category-groupings (grouping-kind->pref-entry-category-groupings showin-kind-kw)} + (fn [api-reponse] + (when-not (on-error api-reponse) + ;; Reloads the whole app preference + ;; This ensures the pass phrase option in preference data is the updated one + (dispatch [:common/load-app-preference])))))) + ;; kind may be :type, :tag, :category or :group and it represents the bottom view only (reg-event-db :show-group-as diff --git a/src/main/onekeepass/frontend/events/entry_form_ex.cljs b/src/main/onekeepass/frontend/events/entry_form_ex.cljs index 1a98071..364de24 100644 --- a/src/main/onekeepass/frontend/events/entry_form_ex.cljs +++ b/src/main/onekeepass/frontend/events/entry_form_ex.cljs @@ -317,6 +317,7 @@ (assoc-in-key-db [entry-form-key :edit] false) (init-expiry-duration-selection entry-data) (assoc-in-key-db [entry-form-key :showing] :selected) + (assoc-in-key-db [entry-form-key :visibility-list] nil) ;; otp-fields is map with otp field name as key and token info (map) as value ;; This map is updated periodically when polling is started (assoc-in-key-db [entry-form-key :otp-fields] otp-fields))}))) From 7d4f0f8ae7e612ec9b14c82530c5d97365e347cd Mon Sep 17 00:00:00 2001 From: jeyasankar Date: Tue, 11 Mar 2025 11:27:24 -0700 Subject: [PATCH 14/15] Updated core api version --- src-tauri/Cargo.lock | 3 ++- src-tauri/Cargo.toml | 4 ++-- src-tauri/src/auto_open/mod.rs | 9 +++++++-- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 5f4fee6..016cdd3 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "addr2line" @@ -3080,6 +3080,7 @@ checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "onekeepass-core" version = "0.17.0" +source = "git+https://github.com/OneKeePass/onekeepass-core.git?tag=v0.17.0#4652301734d535bd6160a4a41bc5cdf69cb9fd1a" dependencies = [ "aes 0.7.5", "aes-gcm", diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index d8e1a1a..a71dc25 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -39,10 +39,10 @@ tokio = { version = "1", features = [ "time" ] } tauri = { version = "1.8.1", features = ["clipboard-all", "dialog-all", "global-shortcut-all", "path-all", "process-exit", "shell-all"] } ## using from the local crate during development -onekeepass-core = {path = "../../onekeepass-core", version = "0.17.0"} +## onekeepass-core = {path = "../../onekeepass-core", version = "0.17.0"} ## Need to use the git ref for release -## onekeepass-core = {git = "https://github.com/OneKeePass/onekeepass-core.git" , tag="v0.16.0" } +onekeepass-core = {git = "https://github.com/OneKeePass/onekeepass-core.git" , tag="v0.17.0" } [build-dependencies] tauri-build = { version = "1.5.5", features = [] } diff --git a/src-tauri/src/auto_open/mod.rs b/src-tauri/src/auto_open/mod.rs index 5ab1fb9..ec8968e 100644 --- a/src-tauri/src/auto_open/mod.rs +++ b/src-tauri/src/auto_open/mod.rs @@ -82,6 +82,8 @@ fn inner_open_all_auto_open_dbs( // unwrap is fine as we have checked for error let kvs = kvs_result.unwrap(); + debug!("Going to resolve for the entry uuid {}", &entry_uuid); + // Prepare props to resolve let auto_open_properties = AutoOpenProperties { source_db_key: auto_open_db_key.to_string(), @@ -97,6 +99,7 @@ fn inner_open_all_auto_open_dbs( if let Err(e) = ao_val { // As there are errors in resolving, we skip this entry uuid auto_open_dbs_info.error_messages.push(e.to_string()); + debug!("The auto_open_properties.resolve call failed with error: {}",e); continue; } // unwrap is fine as we have checked for error @@ -145,10 +148,12 @@ fn inner_open_all_auto_open_dbs( } } } else { - auto_open_dbs_info.error_messages.push(format!( + let msg = format!( "Cound not form a valid url from {:?}", kvs.get(kp_service::entry_keyvalue_key::USER_NAME).cloned() - )); + ); + debug!("{}",&msg); + auto_open_dbs_info.error_messages.push(msg); } } } From 7a15d360fb6221e29c43c7c625e9000aad448fab Mon Sep 17 00:00:00 2001 From: jeyasankar Date: Tue, 11 Mar 2025 12:27:07 -0700 Subject: [PATCH 15/15] Updated changelog doc --- CHANGELOG.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 913d7eb..6662eb7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,20 @@ +### 0.15.0 +- Automatic Database Opening featurure to open one or more databases automatically when you open a single database. For this, entries are to be created using the entry template 'Auto Database Open' in a group 'AutoOpen'. See FAQ how to use this feature + +- Added Diceware Passphrase generator with multiple words list support + +- Using standard place holder variables in entry field values are now supported + +- Cloning an entry now supports replacing the username and password with references + +- Additional translations of texts + + - German - Thanks [imar-io](https://github.com/imar-io) + + - Chinese - Thanks [CSLukkun](https://github.com/CSLukkun) + +- Upgraded backend tauri and frontend mui packages + ### 0.14.0 - Added cloning an entry - Groups can be sorted based on its name