From 37b44ddb2ed42de19b3a3e54bd1f9f2bf7671b70 Mon Sep 17 00:00:00 2001 From: Joseph Montanaro Date: Wed, 26 Jun 2024 11:10:50 -0400 Subject: [PATCH] start refactoring for default credentials --- index.html | 2 +- package-lock.json | 222 ++++++++++----- package.json | 2 +- .../20240617142724_credential_split.sql | 5 +- src-tauri/src/credentials/aws.rs | 267 +++++++++++------- .../credentials/fixtures/aws_credentials.sql | 6 +- src-tauri/src/credentials/mod.rs | 187 ++++++++++-- src-tauri/src/ipc.rs | 8 +- src-tauri/src/state.rs | 24 +- src/App.svelte | 58 ++-- src/lib/state.js | 6 +- src/ui/ErrorAlert.svelte | 10 +- src/ui/Icon.svelte | 2 +- src/ui/Link.svelte | 1 + src/views/Approve.svelte | 144 +++------- src/views/EnterCredentials.svelte | 94 ------ src/views/Home.svelte | 51 ++-- src/views/Settings.svelte | 127 ++++----- src/views/ShowResponse.svelte | 38 --- src/views/Unlock.svelte | 67 ++--- tailwind.config.js | 19 ++ 21 files changed, 708 insertions(+), 632 deletions(-) delete mode 100644 src/views/EnterCredentials.svelte delete mode 100644 src/views/ShowResponse.svelte diff --git a/index.html b/index.html index 3f549eb..0001267 100644 --- a/index.html +++ b/index.html @@ -1,5 +1,5 @@ - + diff --git a/package-lock.json b/package-lock.json index 1156163..40f95f4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,17 +1,17 @@ { "name": "creddy", - "version": "0.4.7", + "version": "0.4.9", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "creddy", - "version": "0.4.7", + "version": "0.4.9", "dependencies": { "@tauri-apps/api": "^2.0.0-beta.13", "@tauri-apps/plugin-dialog": "^2.0.0-beta.5", "@tauri-apps/plugin-os": "^2.0.0-beta.5", - "daisyui": "^2.51.5" + "daisyui": "^4.12.8" }, "devDependencies": { "@sveltejs/vite-plugin-svelte": "^1.0.1", @@ -27,6 +27,7 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "dev": true, "engines": { "node": ">=10" }, @@ -70,6 +71,7 @@ "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", @@ -86,6 +88,7 @@ "version": "0.3.5", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dev": true, "dependencies": { "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", @@ -99,6 +102,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, "engines": { "node": ">=6.0.0" } @@ -107,6 +111,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "dev": true, "engines": { "node": ">=6.0.0" } @@ -114,12 +119,14 @@ "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==" + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.25", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" @@ -129,6 +136,7 @@ "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" @@ -141,6 +149,7 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, "engines": { "node": ">= 8" } @@ -149,6 +158,7 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" @@ -161,6 +171,7 @@ "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, "optional": true, "engines": { "node": ">=14" @@ -409,6 +420,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, "engines": { "node": ">=12" }, @@ -420,6 +432,7 @@ "version": "6.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, "engines": { "node": ">=12" }, @@ -430,12 +443,14 @@ "node_modules/any-promise": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==" + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "dev": true }, "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, "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" @@ -447,12 +462,14 @@ "node_modules/arg": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", - "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==" + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", + "dev": true }, "node_modules/autoprefixer": { "version": "10.4.19", "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.19.tgz", "integrity": "sha512-BaENR2+zBZ8xXhM4pUaKUxlVdxZ0EZhjvbopwnXmxRUfqDmwSpC2lAi/QXvx7NRdPCo1WKEcEF6mV64si1z4Ew==", + "dev": true, "funding": [ { "type": "opencollective", @@ -488,12 +505,14 @@ "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==" + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true }, "node_modules/binary-extensions": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, "engines": { "node": ">=8" }, @@ -505,6 +524,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, "dependencies": { "balanced-match": "^1.0.0" } @@ -513,6 +533,7 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, "dependencies": { "fill-range": "^7.1.1" }, @@ -524,6 +545,7 @@ "version": "4.23.0", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz", "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==", + "dev": true, "funding": [ { "type": "opencollective", @@ -563,6 +585,7 @@ "version": "1.0.30001625", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001625.tgz", "integrity": "sha512-4KE9N2gcRH+HQhpeiRZXd+1niLB/XNLAhSy4z7fI8EzcbcPoAqjNInxVHTiTwWfTIV4w096XG8OtCOCQQKPv3w==", + "dev": true, "funding": [ { "type": "opencollective", @@ -582,6 +605,7 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", @@ -605,6 +629,7 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, "dependencies": { "is-glob": "^4.0.1" }, @@ -612,22 +637,11 @@ "node": ">= 6" } }, - "node_modules/color": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", - "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", - "dependencies": { - "color-convert": "^2.0.1", - "color-string": "^1.9.0" - }, - "engines": { - "node": ">=12.5.0" - } - }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, "dependencies": { "color-name": "~1.1.4" }, @@ -638,21 +652,14 @@ "node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/color-string": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", - "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", - "dependencies": { - "color-name": "^1.0.0", - "simple-swizzle": "^0.2.2" - } + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true }, "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, "engines": { "node": ">= 6" } @@ -661,6 +668,7 @@ "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -690,23 +698,30 @@ "node": ">=4" } }, + "node_modules/culori": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/culori/-/culori-3.3.0.tgz", + "integrity": "sha512-pHJg+jbuFsCjz9iclQBqyL3B2HLCBF71BwVNujUYEvCeQMvV97R59MNK3R2+jgJ3a1fcZgI9B3vYgz8lzr/BFQ==", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, "node_modules/daisyui": { - "version": "2.52.0", - "resolved": "https://registry.npmjs.org/daisyui/-/daisyui-2.52.0.tgz", - "integrity": "sha512-LQTA5/IVXAJHBMFoeaEMfd7/akAFPPcdQPR3O9fzzcFiczneJFM73CFPnScmW2sOgn/D83cvkP854ep2T9OfTg==", + "version": "4.12.8", + "resolved": "https://registry.npmjs.org/daisyui/-/daisyui-4.12.8.tgz", + "integrity": "sha512-FDdh0z9BsWMI0VeUSwZy6rwp9frEuUgd83SCPOaCYV3iULPzcgTEQT3IlcAbMCrsriu2ziDYZfGOUwPYHkHrfw==", "dependencies": { - "color": "^4.2", - "css-selector-tokenizer": "^0.8.0", - "postcss-js": "^4.0.0", - "tailwindcss": "^3" + "css-selector-tokenizer": "^0.8", + "culori": "^3", + "picocolors": "^1", + "postcss-js": "^4" + }, + "engines": { + "node": ">=16.9.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/daisyui" - }, - "peerDependencies": { - "autoprefixer": "^10.0.2", - "postcss": "^8.1.6" } }, "node_modules/debug": { @@ -738,27 +753,32 @@ "node_modules/didyoumean": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", - "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==" + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", + "dev": true }, "node_modules/dlv": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", - "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==" + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", + "dev": true }, "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true }, "node_modules/electron-to-chromium": { "version": "1.4.787", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.787.tgz", - "integrity": "sha512-d0EFmtLPjctczO3LogReyM2pbBiiZbnsKnGF+cdZhsYzHm/A0GV7W94kqzLD8SN4O3f3iHlgLUChqghgyznvCQ==" + "integrity": "sha512-d0EFmtLPjctczO3LogReyM2pbBiiZbnsKnGF+cdZhsYzHm/A0GV7W94kqzLD8SN4O3f3iHlgLUChqghgyznvCQ==", + "dev": true }, "node_modules/emoji-regex": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true }, "node_modules/esbuild": { "version": "0.15.18", @@ -1121,6 +1141,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "dev": true, "engines": { "node": ">=6" } @@ -1129,6 +1150,7 @@ "version": "3.3.2", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", @@ -1144,6 +1166,7 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, "dependencies": { "is-glob": "^4.0.1" }, @@ -1160,6 +1183,7 @@ "version": "1.17.1", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dev": true, "dependencies": { "reusify": "^1.0.4" } @@ -1168,6 +1192,7 @@ "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, "dependencies": { "to-regex-range": "^5.0.1" }, @@ -1179,6 +1204,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", + "dev": true, "dependencies": { "cross-spawn": "^7.0.0", "signal-exit": "^4.0.1" @@ -1194,6 +1220,7 @@ "version": "4.3.7", "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", + "dev": true, "engines": { "node": "*" }, @@ -1206,6 +1233,7 @@ "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, "hasInstallScript": true, "optional": true, "os": [ @@ -1219,6 +1247,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -1227,6 +1256,7 @@ "version": "10.4.1", "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.1.tgz", "integrity": "sha512-2jelhlq3E4ho74ZyVLN03oKdAZVUa6UDZzFLVH1H7dnoax+y9qyaq8zBkfDIggjniU19z0wU18y16jMB2eyVIw==", + "dev": true, "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", @@ -1248,6 +1278,7 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, "dependencies": { "is-glob": "^4.0.3" }, @@ -1259,6 +1290,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, "dependencies": { "function-bind": "^1.1.2" }, @@ -1266,15 +1298,11 @@ "node": ">= 0.4" } }, - "node_modules/is-arrayish": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", - "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" - }, "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, "dependencies": { "binary-extensions": "^2.0.0" }, @@ -1286,6 +1314,7 @@ "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, "dependencies": { "hasown": "^2.0.0" }, @@ -1297,6 +1326,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, "engines": { "node": ">=0.10.0" } @@ -1305,6 +1335,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, "engines": { "node": ">=8" } @@ -1313,6 +1344,7 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, "dependencies": { "is-extglob": "^2.1.1" }, @@ -1324,6 +1356,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, "engines": { "node": ">=0.12.0" } @@ -1331,12 +1364,14 @@ "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true }, "node_modules/jackspeak": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.1.2.tgz", "integrity": "sha512-kWmLKn2tRtfYMF/BakihVVRzBKOxz4gJMiL2Rj91WnAB5TPZumSH99R/Yf1qE1u4uRimvCSJfm6hnxohXeEXjQ==", + "dev": true, "dependencies": { "@isaacs/cliui": "^8.0.2" }, @@ -1354,6 +1389,7 @@ "version": "1.21.0", "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz", "integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==", + "dev": true, "bin": { "jiti": "bin/jiti.js" } @@ -1371,6 +1407,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", + "dev": true, "engines": { "node": ">=10" } @@ -1378,12 +1415,14 @@ "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true }, "node_modules/lru-cache": { "version": "10.2.2", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz", "integrity": "sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==", + "dev": true, "engines": { "node": "14 || >=16.14" } @@ -1404,6 +1443,7 @@ "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, "engines": { "node": ">= 8" } @@ -1412,6 +1452,7 @@ "version": "4.0.7", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", + "dev": true, "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" @@ -1424,6 +1465,7 @@ "version": "9.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "dev": true, "dependencies": { "brace-expansion": "^2.0.1" }, @@ -1438,6 +1480,7 @@ "version": "7.1.2", "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, "engines": { "node": ">=16 || 14 >=14.17" } @@ -1452,6 +1495,7 @@ "version": "2.7.0", "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dev": true, "dependencies": { "any-promise": "^1.0.0", "object-assign": "^4.0.1", @@ -1478,12 +1522,14 @@ "node_modules/node-releases": { "version": "2.0.14", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", - "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==" + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", + "dev": true }, "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, "engines": { "node": ">=0.10.0" } @@ -1492,6 +1538,7 @@ "version": "0.1.2", "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "dev": true, "engines": { "node": ">=0.10.0" } @@ -1500,6 +1547,7 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, "engines": { "node": ">=0.10.0" } @@ -1508,6 +1556,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "dev": true, "engines": { "node": ">= 6" } @@ -1516,6 +1565,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, "engines": { "node": ">=8" } @@ -1523,12 +1573,14 @@ "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==" + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true }, "node_modules/path-scurry": { "version": "1.11.1", "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" @@ -1549,6 +1601,7 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, "engines": { "node": ">=8.6" }, @@ -1560,6 +1613,7 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true, "engines": { "node": ">=0.10.0" } @@ -1568,6 +1622,7 @@ "version": "4.0.6", "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", + "dev": true, "engines": { "node": ">= 6" } @@ -1603,6 +1658,7 @@ "version": "15.1.0", "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", + "dev": true, "dependencies": { "postcss-value-parser": "^4.0.0", "read-cache": "^1.0.0", @@ -1637,6 +1693,7 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz", "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==", + "dev": true, "funding": [ { "type": "opencollective", @@ -1671,6 +1728,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.1.tgz", "integrity": "sha512-O18pf7nyvHTckunPWCV1XUNXU1piu01y2b7ATJ0ppkUkk8ocqVWBrYjJBCwHDjD/ZWcfyrA0P4gKhzWGi5EINQ==", + "dev": true, "engines": { "node": ">=14" }, @@ -1682,6 +1740,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.1.tgz", "integrity": "sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==", + "dev": true, "dependencies": { "postcss-selector-parser": "^6.0.11" }, @@ -1700,6 +1759,7 @@ "version": "6.1.0", "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.0.tgz", "integrity": "sha512-UMz42UD0UY0EApS0ZL9o1XnLhSTtvvvLe5Dc2H2O56fvRZi+KulDyf5ctDhhtYJBGKStV2FL1fy6253cmLgqVQ==", + "dev": true, "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -1711,12 +1771,14 @@ "node_modules/postcss-value-parser": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, "funding": [ { "type": "github", @@ -1736,6 +1798,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "dev": true, "dependencies": { "pify": "^2.3.0" } @@ -1744,6 +1807,7 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, "dependencies": { "picomatch": "^2.2.1" }, @@ -1755,6 +1819,7 @@ "version": "1.22.8", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dev": true, "dependencies": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", @@ -1771,6 +1836,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, "engines": { "iojs": ">=1.0.0", "node": ">=0.10.0" @@ -1795,6 +1861,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, "funding": [ { "type": "github", @@ -1817,6 +1884,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, "dependencies": { "shebang-regex": "^3.0.0" }, @@ -1828,6 +1896,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, "engines": { "node": ">=8" } @@ -1836,6 +1905,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, "engines": { "node": ">=14" }, @@ -1843,14 +1913,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/simple-swizzle": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", - "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", - "dependencies": { - "is-arrayish": "^0.3.1" - } - }, "node_modules/source-map-js": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", @@ -1870,6 +1932,7 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", @@ -1887,6 +1950,7 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -1900,6 +1964,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, "engines": { "node": ">=8" } @@ -1907,12 +1972,14 @@ "node_modules/string-width-cjs/node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true }, "node_modules/string-width-cjs/node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -1924,6 +1991,7 @@ "version": "7.1.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, "dependencies": { "ansi-regex": "^6.0.1" }, @@ -1939,6 +2007,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -1950,6 +2019,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, "engines": { "node": ">=8" } @@ -1958,6 +2028,7 @@ "version": "3.35.0", "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==", + "dev": true, "dependencies": { "@jridgewell/gen-mapping": "^0.3.2", "commander": "^4.0.0", @@ -1979,6 +2050,7 @@ "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, "engines": { "node": ">= 0.4" }, @@ -2011,6 +2083,7 @@ "version": "3.4.3", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.3.tgz", "integrity": "sha512-U7sxQk/n397Bmx4JHbJx/iSOOv5G+II3f1kpLpY2QeUv5DcPdcTsYLlusZfq1NthHS1c1cZoyFmmkex1rzke0A==", + "dev": true, "dependencies": { "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", @@ -2047,6 +2120,7 @@ "version": "3.3.1", "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dev": true, "dependencies": { "any-promise": "^1.0.0" } @@ -2055,6 +2129,7 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "dev": true, "dependencies": { "thenify": ">= 3.1.0 < 4" }, @@ -2066,6 +2141,7 @@ "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, "dependencies": { "is-number": "^7.0.0" }, @@ -2076,12 +2152,14 @@ "node_modules/ts-interface-checker": { "version": "0.1.13", "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", - "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==" + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", + "dev": true }, "node_modules/update-browserslist-db": { "version": "1.0.16", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.16.tgz", "integrity": "sha512-KVbTxlBYlckhF5wgfyZXTWnMn7MMZjMu9XG8bPlliUOP9ThaF4QnhP8qrjrH7DRzHfSk0oQv1wToW+iA5GajEQ==", + "dev": true, "funding": [ { "type": "opencollective", @@ -2110,7 +2188,8 @@ "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true }, "node_modules/vite": { "version": "3.2.10", @@ -2179,6 +2258,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, "dependencies": { "isexe": "^2.0.0" }, @@ -2193,6 +2273,7 @@ "version": "8.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", @@ -2210,6 +2291,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -2226,6 +2308,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, "engines": { "node": ">=8" } @@ -2234,6 +2317,7 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -2247,12 +2331,14 @@ "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true }, "node_modules/wrap-ansi-cjs/node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -2266,6 +2352,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -2277,6 +2364,7 @@ "version": "2.4.2", "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.2.tgz", "integrity": "sha512-B3VqDZ+JAg1nZpaEmWtTXUlBneoGx6CPM9b0TENK6aoSu5t73dItudwdgmi6tHlIZZId4dZ9skcAQ2UbcyAeVA==", + "dev": true, "bin": { "yaml": "bin.mjs" }, diff --git a/package.json b/package.json index 53c8c83..6ba20aa 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,6 @@ "@tauri-apps/api": "^2.0.0-beta.13", "@tauri-apps/plugin-dialog": "^2.0.0-beta.5", "@tauri-apps/plugin-os": "^2.0.0-beta.5", - "daisyui": "^2.51.5" + "daisyui": "^4.12.8" } } diff --git a/src-tauri/migrations/20240617142724_credential_split.sql b/src-tauri/migrations/20240617142724_credential_split.sql index cc86116..b38eb17 100644 --- a/src-tauri/migrations/20240617142724_credential_split.sql +++ b/src-tauri/migrations/20240617142724_credential_split.sql @@ -42,12 +42,13 @@ CREATE TABLE credentials ( id BLOB UNIQUE NOT NULL, name TEXT UNIQUE NOT NULL, type TEXT NOT NULL, + is_default BOOLEAN NOT NULL, created_at INTEGER NOT NULL ); -- populate with basic data from existing AWS credential -INSERT INTO credentials (id, name, type, created_at) -SELECT id, 'default', 'aws', created_at FROM aws_tmp; +INSERT INTO credentials (id, name, type, is_default, created_at) +SELECT id, 'default', 'aws', 1, created_at FROM aws_tmp; -- new AWS-specific table CREATE TABLE aws_credentials ( diff --git a/src-tauri/src/credentials/aws.rs b/src-tauri/src/credentials/aws.rs index f343e65..8303e19 100644 --- a/src-tauri/src/credentials/aws.rs +++ b/src-tauri/src/credentials/aws.rs @@ -12,19 +12,27 @@ use serde::{ }; use serde::de::{self, Visitor}; use sqlx::{ - SqlitePool, + FromRow, + Sqlite, + Transaction, types::Uuid, }; -use sqlx::error::{ - Error as SqlxError, -}; -use tokio_stream::StreamExt; -use super::{Credential, Crypto, SaveCredential, PersistentCredential}; +use super::{Crypto, PersistentCredential}; use crate::errors::*; +#[derive(Debug, Clone, FromRow)] +pub struct AwsRow { + #[allow(dead_code)] + id: Uuid, + access_key_id: String, + secret_key_enc: Vec, + nonce: Vec, +} + + #[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "PascalCase")] pub struct AwsBaseCredential { @@ -42,85 +50,123 @@ impl AwsBaseCredential { } impl PersistentCredential for AwsBaseCredential { - async fn save(&self, id: &Uuid, name: &str, crypto: &Crypto, pool: &SqlitePool) -> Result<(), SaveCredentialsError> { + type Row = AwsRow; + + fn type_name() -> &'static str { "aws" } + + fn from_row(row: AwsRow, crypto: &Crypto) -> Result { + let nonce = XNonce::clone_from_slice(&row.nonce); + let secret_key_bytes = crypto.decrypt(&nonce, &row.secret_key_enc)?; + let secret_key = String::from_utf8(secret_key_bytes) + .map_err(|_| LoadCredentialsError::InvalidData)?; + + Ok(Self::new(row.access_key_id, secret_key)) + } + + async fn save_details(&self, id: &Uuid, crypto: &Crypto, txn: &mut Transaction<'_, Sqlite>) -> Result<(), SaveCredentialsError> { let (nonce, ciphertext) = crypto.encrypt(self.secret_access_key.as_bytes())?; let nonce_bytes = &nonce.as_slice(); - let res = sqlx::query!( - "INSERT INTO credentials (id, name, type, created_at) - VALUES (?, ?, 'aws', strftime('%s')) - ON CONFLICT(id) DO UPDATE SET - name = excluded.name, - type = excluded.type, - created_at = excluded.created_at; - - INSERT OR REPLACE INTO aws_credentials ( + + sqlx::query!( + "INSERT OR REPLACE INTO aws_credentials ( id, access_key_id, secret_key_enc, nonce ) VALUES (?, ?, ?, ?);", - id, - name, - id, // for the second query - self.access_key_id, - ciphertext, - nonce_bytes, - ).execute(pool).await; + id, self.access_key_id, ciphertext, nonce_bytes, + ).execute(&mut **txn).await?; - match res { - Err(SqlxError::Database(e)) if e.code().as_deref() == Some("2067") => Err(SaveCredentialsError::Duplicate), - Err(e) => Err(SaveCredentialsError::DbError(e)), - Ok(_) => Ok(()) - } + Ok(()) } - async fn load(name: &str, crypto: &Crypto, pool: &SqlitePool) -> Result { - let row = sqlx::query!( - "SELECT c.name, a.access_key_id, a.secret_key_enc, a.nonce - FROM credentials c JOIN aws_credentials a ON a.id = c.id - WHERE c.name = ?", - name - ).fetch_optional(pool) - .await? - .ok_or(LoadCredentialsError::NoCredentials)?; + // async fn save(&self, record: CredentialRecord, &Crypto, pool: &SqlitePool) -> Result<(), CredentialRecordsError> { + // let (nonce, ciphertext) = crypto.encrypt(self.secret_access_key.as_bytes())?; + // let nonce_bytes = &nonce.as_slice(); - let nonce = XNonce::clone_from_slice(&row.nonce); - let secret_key_bytes = crypto.decrypt(&nonce, &row.secret_key_enc)?; - let secret_key = String::from_utf8(secret_key_bytes) - .map_err(|_| LoadCredentialsError::InvalidData)?; + // let res = sqlx::query!( + // "INSERT INTO credentials (id, name, type, created_at) + // VALUES (?, ?, 'aws', strftime('%s')) + // ON CONFLICT(id) DO UPDATE SET + // name = excluded.name, + // type = excluded.type, + // created_at = excluded.created_at; + + // INSERT OR REPLACE INTO aws_credentials ( + // id, + // access_key_id, + // secret_key_enc, + // nonce + // ) + // VALUES (?, ?, ?, ?);", + // id, + // name, + // id, // for the second query + // self.access_key_id, + // ciphertext, + // nonce_bytes, + // ).execute(pool).await; - Ok(AwsBaseCredential::new(row.access_key_id, secret_key)) - } + // match res { + // Err(SqlxError::Database(e)) if e.code().as_deref() == Some("2067") => Err(CredentialRecordsError::Duplicate), + // Err(e) => Err(SaveCredentialsError::DbError(e)), + // Ok(_) => Ok(()) + // } + // } - async fn list(crypto: &Crypto, pool: &SqlitePool) -> Result, LoadCredentialsError> { - let mut rows = sqlx::query!( - "SELECT c.id, c.name, a.access_key_id, a.secret_key_enc, a.nonce - FROM credentials c JOIN aws_credentials a ON a.id = c.id" - ).fetch(pool); + // async fn load(name: &str, crypto: &Crypto, pool: &SqlitePool) -> Result { + // let record: AwsRecord = sqlx::query_as( + // "SELECT c.id, c.name, c.is_default, a.access_key_id, a.secret_key_enc, a.nonce + // FROM credentials c JOIN aws_credentials a ON a.id = c.id + // WHERE c.name = ?" + // ).bind(name) + // .fetch_optional(pool) + // .await? + // .ok_or(LoadCredentialsError::NoCredentials)?; - let mut creds = Vec::new(); + // let key = record.decrypt_key(crypto)?; + // let credential = AwsBaseCredential::new(record.access_key_id, key); + // Ok(credential) + // } - while let Some(row) = rows.try_next().await? { - let nonce = XNonce::clone_from_slice(&row.nonce); - let secret_key_bytes = crypto.decrypt(&nonce, &row.secret_key_enc)?; - let secret_key = String::from_utf8(secret_key_bytes) - .map_err(|_| LoadCredentialsError::InvalidData)?; - let aws = AwsBaseCredential::new(row.access_key_id, secret_key); + // async fn load_default(crypto: &Crypto, pool: &SqlitePool) -> Result { + // let record: AwsRecord = sqlx::query_as( + // "SELECT c.id, c.name, c.is_default, a.access_key_id, a.secret_key_enc, a.nonce + // FROM credentials c JOIN aws_credentials a ON a.id = c.id + // WHERE c.type = 'aws' AND c.is_default = 1" + // ).fetch_optional(pool) + // .await? + // .ok_or(LoadCredentialsError::NoCredentials)?; - let id = Uuid::from_slice(&row.id) - .map_err(|_| LoadCredentialsError::InvalidData)?; + // let key = record.decrypt_key(crypto)?; + // let credential = AwsBaseCredential::new(record.access_key_id, key); + // Ok(credential) + // } - let cred = SaveCredential { - id, - name: row.name, - credential: Credential::AwsBase(aws), - }; - creds.push(cred); - } + // async fn list(crypto: &Crypto, pool: &SqlitePool) -> Result, LoadCredentialsError> { + // let mut rows = sqlx::query_as::<_, AwsRecord>( + // "SELECT c.id, c.name, c.is_default, a.access_key_id, a.secret_key_enc, a.nonce + // FROM credentials c JOIN aws_credentials a ON a.id = c.id" + // ).fetch(pool); - Ok(creds) - } + // let mut creds = Vec::new(); + + // while let Some(record) = rows.try_next().await? { + // let key = record.decrypt_key(crypto)?; + // let aws = AwsBaseCredential::new(record.access_key_id, key); + + // let cred = SaveCredential { + // id: record.id, + // name: record.name, + // is_default: record.is_default, + // credential: Credential::AwsBase(aws), + // }; + // creds.push(cred); + // } + + // Ok(creds) + // } } @@ -223,6 +269,7 @@ where S: Serializer #[cfg(test)] mod tests { use super::*; + use sqlx::SqlitePool; fn test_creds() -> AwsBaseCredential { @@ -256,7 +303,8 @@ mod tests { #[sqlx::test] async fn test_save(pool: SqlitePool) { let crypt = Crypto::random(); - test_creds().save(&test_uuid_random(), "test", &crypt, &pool).await + let mut txn = pool.begin().await.unwrap(); + test_creds().save_details(&test_uuid_random(), &crypt, &mut txn).await .expect("Failed to save AWS credentials"); } @@ -267,11 +315,12 @@ mod tests { let creds = test_creds_2(); // overwite original creds with different test data - creds.save(&test_uuid(), "test", &crypt, &pool).await + let mut txn = pool.begin().await.unwrap(); + creds.save_details(&test_uuid(), &crypt, &mut txn).await .expect("Failed to update AWS credentials"); // make sure update went through - let loaded = AwsBaseCredential::load("test", &crypt, &pool).await.unwrap(); + let loaded = AwsBaseCredential::load(&test_uuid(), &crypt, &pool).await.unwrap(); assert_eq!(creds, loaded); } @@ -281,7 +330,8 @@ mod tests { let crypt = Crypto::random(); let id = test_uuid_random(); - let resp = test_creds().save(&id, "test", &crypt, &pool).await; + let mut txn = pool.begin().await.unwrap(); + let resp = test_creds().save_details(&id, &crypt, &mut txn).await; if !matches!(resp, Err(SaveCredentialsError::Duplicate)) { panic!("Attempt to create duplicate entry returned {resp:?}") @@ -292,7 +342,15 @@ mod tests { #[sqlx::test(fixtures("aws_credentials"))] async fn test_load(pool: SqlitePool) { let crypt = Crypto::fixed(); - let loaded = AwsBaseCredential::load("test", &crypt, &pool).await.unwrap(); + let loaded = AwsBaseCredential::load(&test_uuid(), &crypt, &pool).await.unwrap(); + assert_eq!(test_creds(), loaded); + } + + + #[sqlx::test(fixtures("aws_credentials"))] + async fn test_load_by_name(pool: SqlitePool) { + let crypt = Crypto::fixed(); + let loaded = AwsBaseCredential::load_by_name("test", &crypt, &pool).await.unwrap(); assert_eq!(test_creds(), loaded); } @@ -301,45 +359,48 @@ mod tests { async fn test_save_load(pool: SqlitePool) { let crypt = Crypto::random(); let creds = test_creds(); - creds.save(&test_uuid_random(), "test", &crypt, &pool).await.unwrap(); - let loaded = AwsBaseCredential::load("test", &crypt, &pool).await.unwrap(); + let id = test_uuid_random(); + + let mut txn = pool.begin().await.unwrap(); + creds.save_details(&id, &crypt, &mut txn).await.unwrap(); + let loaded = AwsBaseCredential::load(&id, &crypt, &pool).await.unwrap(); assert_eq!(creds, loaded); } - #[sqlx::test(fixtures("aws_credentials"))] - async fn test_list(pool: SqlitePool) { - let crypt = Crypto::fixed(); - let list = AwsBaseCredential::list(&crypt, &pool).await - .expect("Failed to list AWS credentials"); + // #[sqlx::test(fixtures("aws_credentials"))] + // async fn test_list(pool: SqlitePool) { + // let crypt = Crypto::fixed(); + // let list = AwsBaseCredential::list(&crypt, &pool).await + // .expect("Failed to list AWS credentials"); - let first = SaveCredential { - id: test_uuid(), - name: "test".into(), - credential: Credential::AwsBase(test_creds()), - }; - assert_eq!(&first, &list[0]); + // let first = SaveCredential { + // id: test_uuid(), + // name: "test".into(), + // credential: Credential::AwsBase(test_creds()), + // }; + // assert_eq!(&first, &list[0]); - let second = SaveCredential { - id: test_uuid_2(), - name: "test2".into(), - credential: Credential::AwsBase(test_creds_2()), - }; - assert_eq!(&second, &list[1]); - } + // let second = SaveCredential { + // id: test_uuid_2(), + // name: "test2".into(), + // credential: Credential::AwsBase(test_creds_2()), + // }; + // assert_eq!(&second, &list[1]); + // } - #[sqlx::test(fixtures("aws_credentials"))] - async fn test_rekey(pool: SqlitePool) { - let old_crypt = Crypto::fixed(); - let orig = AwsBaseCredential::list(&old_crypt, &pool).await.unwrap(); + // #[sqlx::test(fixtures("aws_credentials"))] + // async fn test_rekey(pool: SqlitePool) { + // let old_crypt = Crypto::fixed(); + // let orig = AwsBaseCredential::list(&old_crypt, &pool).await.unwrap(); - let new_crypt = Crypto::random(); - AwsBaseCredential::rekey(&old_crypt, &new_crypt, &pool).await - .expect("Failed to re-key AWS credentials"); + // let new_crypt = Crypto::random(); + // AwsBaseCredential::rekey(&old_crypt, &new_crypt, &pool).await + // .expect("Failed to re-key AWS credentials"); - let rekeyed = AwsBaseCredential::list(&new_crypt, &pool).await.unwrap(); - for (before, after) in orig.iter().zip(rekeyed.iter()) { - assert_eq!(before, after); - } - } + // let rekeyed = AwsBaseCredential::list(&new_crypt, &pool).await.unwrap(); + // for (before, after) in orig.iter().zip(rekeyed.iter()) { + // assert_eq!(before, after); + // } + // } } diff --git a/src-tauri/src/credentials/fixtures/aws_credentials.sql b/src-tauri/src/credentials/fixtures/aws_credentials.sql index 2cb0672..3c6f7b4 100644 --- a/src-tauri/src/credentials/fixtures/aws_credentials.sql +++ b/src-tauri/src/credentials/fixtures/aws_credentials.sql @@ -1,7 +1,7 @@ -INSERT INTO credentials (id, name, type, created_at) +INSERT INTO credentials (id, name, type, is_default, created_at) VALUES - (X'00000000000000000000000000000000', 'test', 'aws', strftime('%s')), - (X'ffffffffffffffffffffffffffffffff', 'test2', 'aws', strftime('%s')); + (X'00000000000000000000000000000000', 'test', 'aws', strftime('%s'), 1), + (X'ffffffffffffffffffffffffffffffff', 'test2', 'aws', strftime('%s'), 0); INSERT INTO aws_credentials (id, access_key_id, secret_key_enc, nonce) VALUES diff --git a/src-tauri/src/credentials/mod.rs b/src-tauri/src/credentials/mod.rs index 9db47bd..5ab8a7d 100644 --- a/src-tauri/src/credentials/mod.rs +++ b/src-tauri/src/credentials/mod.rs @@ -24,8 +24,15 @@ use serde::{ Deserializer, }; use serde::de::{self, Visitor}; -use sqlx::SqlitePool; -use sqlx::types::Uuid; +use sqlx::{ + Error as SqlxError, + FromRow, + Sqlite, + SqlitePool, + sqlite::SqliteRow, + Transaction, + types::Uuid, +}; use crate::errors::*; use crate::kv; @@ -35,6 +42,7 @@ pub use aws::{AwsBaseCredential, AwsSessionCredential}; #[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] +#[serde(tag = "type")] pub enum Credential { AwsBase(AwsBaseCredential), AwsSession(AwsSessionCredential), @@ -43,27 +51,74 @@ pub enum Credential { // we need a special type for listing structs because #[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] -pub struct SaveCredential { +pub struct CredentialRecord { #[serde(serialize_with = "serialize_uuid")] #[serde(deserialize_with = "deserialize_uuid")] id: Uuid, // UUID so it can be generated on the frontend name: String, // user-facing identifier so it can be changed + is_default: bool, credential: Credential, } -impl SaveCredential { - pub async fn save(&self, crypt: &Crypto, pool: &SqlitePool) -> Result<(), SaveCredentialsError> { - let cred = match &self.credential { - Credential::AwsBase(b) => b, - Credential::AwsSession(_) => return Err(SaveCredentialsError::NotPersistent), +impl CredentialRecord { + pub async fn save(&self, crypto: &Crypto, pool: &SqlitePool) -> Result<(), SaveCredentialsError> { + let type_name = match &self.credential { + Credential::AwsBase(_) => AwsBaseCredential::type_name(), + _ => return Err(SaveCredentialsError::NotPersistent), }; - cred.save(&self.id, &self.name, crypt, pool).await + // if the credential being saved is default, make sure it's the only default of its type + let mut txn = pool.begin().await?; + if self.is_default { + sqlx::query!( + "UPDATE credentials SET is_default = 0 WHERE type = ?", + type_name + ).execute(&mut *txn).await?; + } + + // save to parent credentials table + let res = sqlx::query!( + "INSERT INTO credentials (id, name, type, is_default) + VALUES (?, ?, ?, ?) + ON CONFLICT DO UPDATE SET + name = excluded.name, + type = excluded.type, + is_default = excluded.is_default", + self.id, self.name, type_name, self.is_default + ).execute(&mut *txn).await; + + // if id is unique, but name is not, we will get an error + // (if id is not unique, this becomes an upsert due to ON CONFLICT clause) + match res { + Err(SqlxError::Database(e)) if e.is_unique_violation() => Err(SaveCredentialsError::Duplicate), + Err(e) => Err(SaveCredentialsError::DbError(e)), + Ok(_) => Ok(()) + }?; + + // save credential details to child table + match &self.credential { + Credential::AwsBase(b) => b.save_details(&self.id, crypto, &mut txn).await, + _ => Err(SaveCredentialsError::NotPersistent), + }?; + + // make it real + txn.commit().await?; + Ok(()) + } + + #[allow(unused_variables)] + pub async fn list(crypto: &Crypto, pool: &SqlitePool) -> Result, LoadCredentialsError> { + todo!() + } + + #[allow(unused_variables)] + pub async fn rekey(old: &Crypto, new: &Crypto, pool: &SqlitePool) -> Result<(), SaveCredentialsError> { + todo!() } } fn serialize_uuid(u: &Uuid, s: S) -> Result { - let mut buf = Vec::new(); + let mut buf = Uuid::encode_buffer(); s.serialize_str(u.as_hyphenated().encode_lower(&mut buf)) } @@ -88,15 +143,57 @@ fn deserialize_uuid<'de, D: Deserializer<'de>>(ds: D) -> Result pub trait PersistentCredential: for<'a> Deserialize<'a> + Sized { - async fn load(name: &str, crypt: &Crypto, pool: &SqlitePool) -> Result; - async fn list(crypt: &Crypto, pool: &SqlitePool) -> Result, LoadCredentialsError>; - async fn save(&self, id: &Uuid, name: &str, crypt: &Crypto, pool: &SqlitePool) -> Result<(), SaveCredentialsError>; + type Row: Send + Unpin + for<'r> FromRow<'r, SqliteRow>; - async fn rekey(old: &Crypto, new: &Crypto, pool: &SqlitePool) -> Result<(), SaveCredentialsError> { - for cred in Self::list(old, pool).await? { - cred.save(new, pool).await?; - } - Ok(()) + fn type_name() -> &'static str; + fn from_row(row: Self::Row, crypto: &Crypto) -> Result; + // save_details needs to be implemented per-type because we don't know the number of parameters in advance + async fn save_details(&self, id: &Uuid, crypto: &Crypto, txn: &mut Transaction<'_, Sqlite>) -> Result<(), SaveCredentialsError>; + + fn table_name() -> String { + format!("{}_credentials", Self::type_name()) + } + + async fn load(id: &Uuid, crypto: &Crypto, pool: &SqlitePool) -> Result { + let q = format!("SELECT * FROM {} WHERE id = ?", Self::table_name()); + let row: Self::Row = sqlx::query_as(&q) + .bind(id) + .fetch_optional(pool) + .await? + .ok_or(LoadCredentialsError::NoCredentials)?; + + Self::from_row(row, crypto) + } + + async fn load_by_name(name: &str, crypto: &Crypto, pool: &SqlitePool) -> Result { + let q = format!( + "SELECT * FROM {} WHERE id = (SELECT id FROM credentials WHERE name = ?)", + Self::table_name(), + ); + let row: Self::Row = sqlx::query_as(&q) + .bind(name) + .fetch_optional(pool) + .await? + .ok_or(LoadCredentialsError::NoCredentials)?; + + Self::from_row(row, crypto) + } + + async fn load_default(crypto: &Crypto, pool: &SqlitePool) -> Result { + let q = format!( + "SELECT details.* + FROM {} details + JOIN credentials c + ON c.id = details.id + AND c.is_default = 1", + Self::table_name(), + ); + let row: Self::Row = sqlx::query_as(&q) + .fetch_optional(pool) + .await? + .ok_or(LoadCredentialsError::NoCredentials)?; + + Self::from_row(row, crypto) } } @@ -300,14 +397,48 @@ impl Debug for Crypto { } -// #[cfg(test)] -// mod tests { -// use super::*; +#[cfg(test)] +mod tests { + use super::*; -// #[sqlx::test(fixtures("uuid_test"))] -// async fn save_uuid(pool: SqlitePool) { -// let u = Uuid::try_parse("7140b90c-bfbd-4394-9008-01b94f94ecf8").unwrap(); -// sqlx::query!("INSERT INTO uuids (uuid) VALUES (?)", u).execute(pool).unwrap(); -// panic!("done, go check db"); -// } -// } + + #[derive(Debug, Eq, PartialEq, Serialize, Deserialize)] + struct UuidWrapper { + #[serde(serialize_with = "serialize_uuid")] + #[serde(deserialize_with = "deserialize_uuid")] + id: Uuid, + } + + #[test] + fn test_serialize_uuid() { + let u = UuidWrapper { + id: Uuid::try_parse("693f84d2-4c1b-41e5-8483-cbe178324e04").unwrap() + }; + let computed = serde_json::to_string(&u).unwrap(); + assert_eq!( + "{\"id\":\"693f84d2-4c1b-41e5-8483-cbe178324e04\"}", + &computed, + ); + } + + #[test] + fn test_deserialize_uuid() { + let s = "{\"id\":\"045bd359-8630-4b76-9b7d-e4a86ed2222c\"}"; + let computed = serde_json::from_str(s).unwrap(); + let expected = UuidWrapper { + id: Uuid::try_parse("045bd359-8630-4b76-9b7d-e4a86ed2222c").unwrap(), + }; + assert_eq!(expected, computed); + } + + #[test] + fn test_serialize_deserialize_uuid() { + let buf = Crypto::salt(); + let expected = UuidWrapper{ + id: Uuid::from_slice(&buf[..16]).unwrap() + }; + let serialized = serde_json::to_string(&expected).unwrap(); + let computed = serde_json::from_str(&serialized).unwrap(); + assert_eq!(expected, computed) + } +} diff --git a/src-tauri/src/ipc.rs b/src-tauri/src/ipc.rs index 0783fb0..f42f4f2 100644 --- a/src-tauri/src/ipc.rs +++ b/src-tauri/src/ipc.rs @@ -5,7 +5,7 @@ use tauri::State; use crate::config::AppConfig; use crate::credentials::{ AppSession, - SaveCredential + CredentialRecord }; use crate::errors::*; use crate::clientinfo::Client; @@ -107,10 +107,10 @@ pub async fn signal_activity(app_state: State<'_, AppState>) -> Result<(), ()> { #[tauri::command] pub async fn save_credential( - cred: SaveCredential, + record: CredentialRecord, app_state: State<'_, AppState> ) -> Result<(), SaveCredentialsError> { - app_state.save_credential(cred).await + app_state.save_credential(record).await } @@ -123,7 +123,7 @@ pub async fn delete_credential(id: &str, app_state: State<'_, AppState>) -> Resu #[tauri::command] -pub async fn list_credentials(app_state: State<'_, AppState>) -> Result, GetCredentialsError> { +pub async fn list_credentials(app_state: State<'_, AppState>) -> Result, GetCredentialsError> { app_state.list_credentials().await } diff --git a/src-tauri/src/state.rs b/src-tauri/src/state.rs index aae59d5..3a9e878 100644 --- a/src-tauri/src/state.rs +++ b/src-tauri/src/state.rs @@ -21,7 +21,7 @@ use crate::credentials::{ use crate::{config, config::AppConfig}; use crate::credentials::{ AwsBaseCredential, - SaveCredential, + CredentialRecord, PersistentCredential }; use crate::ipc::{self, RequestResponse}; @@ -142,10 +142,10 @@ impl AppState { } } - pub async fn save_credential(&self, cred: SaveCredential) -> Result<(), SaveCredentialsError> { + pub async fn save_credential(&self, record: CredentialRecord) -> Result<(), SaveCredentialsError> { let session = self.app_session.read().await; let crypto = session.try_get_crypto()?; - cred.save(crypto, &self.pool).await + record.save(crypto, &self.pool).await } pub async fn delete_credential(&self, id: &Uuid) -> Result<(), SaveCredentialsError> { @@ -155,12 +155,11 @@ impl AppState { Ok(()) } - pub async fn list_credentials(&self) -> Result, GetCredentialsError> { + pub async fn list_credentials(&self) -> Result, GetCredentialsError> { let session = self.app_session.read().await; let crypto = session.try_get_crypto()?; - let creds = AwsBaseCredential::list(crypto, &self.pool).await?; - // eventual extend this vec with other credential types - Ok(creds) + let list = CredentialRecord::list(crypto, &self.pool).await?; + Ok(list) } pub async fn set_passphrase(&self, passphrase: &str) -> Result<(), SaveCredentialsError> { @@ -171,7 +170,7 @@ impl AppState { let new_session = AppSession::new(passphrase)?; if let AppSession::Unlocked {salt: _, ref crypto} = *cur_session { - AwsBaseCredential::rekey( + CredentialRecord::rekey( crypto, new_session.try_get_crypto().expect("AppSession::new() should always return Unlocked"), &self.pool, @@ -258,7 +257,7 @@ impl AppState { pub async fn get_aws_base(&self, name: &str) -> Result { let app_session = self.app_session.read().await; let crypto = app_session.try_get_crypto()?; - let creds = AwsBaseCredential::load(name, crypto, &self.pool).await?; + let creds = AwsBaseCredential::load_by_name(name, crypto, &self.pool).await?; Ok(creds) } @@ -345,12 +344,7 @@ mod tests { state.delete_credential(&id).await.unwrap(); // ensure delete-cascade went through correctly - let res = AwsBaseCredential::load( - "test", - &Crypto::fixed(), - &state.pool, - ).await; - + let res = AwsBaseCredential::load(&id, &Crypto::fixed(), &state.pool).await; assert!(matches!(res, Err(LoadCredentialsError::NoCredentials))); } } diff --git a/src/App.svelte b/src/App.svelte index f86b74a..f87e364 100644 --- a/src/App.svelte +++ b/src/App.svelte @@ -7,15 +7,22 @@ import { getVersion } from '@tauri-apps/api/app'; import { appState, acceptRequest, cleanupRequest } from './lib/state.js'; import { views, currentView, navigate } from './lib/routing.js'; +import Approve from './views/Approve.svelte'; +import CreatePassphrase from './views/CreatePassphrase.svelte'; +import Unlock from './views/Unlock.svelte'; -$views = import.meta.glob('./views/*.svelte', {eager: true}); -navigate('Home'); - +// set up app state invoke('get_config').then(config => $appState.config = config); -invoke('get_session_status').then(status => $appState.credentialStatus = status); +invoke('get_session_status').then(status => $appState.sessionStatus = status); getVersion().then(version => $appState.appVersion = version); +invoke('get_setup_errors') + .then(errs => { + $appState.setupErrors = errs.map(e => ({msg: e, show: true})); + }); -listen('credentials-request', (tauriEvent) => { + +// set up event handlers +listen('credential-request', (tauriEvent) => { $appState.pendingRequests.put(tauriEvent.payload); }); @@ -29,29 +36,17 @@ listen('request-cancelled', (tauriEvent) => { } }); -listen('launch-terminal-request', async (tauriEvent) => { - if ($appState.currentRequest === null) { - let status = await invoke('get_session_status'); - if (status === 'locked') { - navigate('Unlock'); - } - else if (status === 'empty') { - navigate('EnterCredentials'); - } - // else, session is unlocked, so do nothing - // (although we shouldn't even get the event in that case) - } -}); - listen('locked', () => { - $appState.credentialStatus = 'locked'; + $appState.sessionStatus = 'locked'; }); -invoke('get_setup_errors') - .then(errs => { - $appState.setupErrors = errs.map(e => ({msg: e, show: true})); - }); +// set up navigation +$views = import.meta.glob('./views/*.svelte', {eager: true}); +navigate('Home'); + + +// ready to rock and roll acceptRequest(); @@ -61,4 +56,17 @@ acceptRequest(); on:keydown={() => invoke('signal_activity')} /> - + +{#if $appState.sessionStatus === 'empty'} + + +{:else if $appState.currentRequest !== null} + + +{:else if $appState.sessionStatus === 'locked'} + + +{:else} + + +{/if} diff --git a/src/lib/state.js b/src/lib/state.js index bf13354..c2408b2 100644 --- a/src/lib/state.js +++ b/src/lib/state.js @@ -7,7 +7,7 @@ import { navigate, currentView, previousView } from './routing.js'; export let appState = writable({ currentRequest: null, pendingRequests: queue(), - credentialStatus: 'locked', + sessionStatus: 'locked', setupErrors: [], appVersion: '', }); @@ -25,11 +25,11 @@ export async function acceptRequest() { export function cleanupRequest() { + currentView.set(get(previousView)); + previousView.set(null); appState.update($appState => { $appState.currentRequest = null; return $appState; }); - currentView.set(get(previousView)); - previousView.set(null); acceptRequest(); } diff --git a/src/ui/ErrorAlert.svelte b/src/ui/ErrorAlert.svelte index 6c9e410..38e99ae 100644 --- a/src/ui/ErrorAlert.svelte +++ b/src/ui/ErrorAlert.svelte @@ -52,12 +52,10 @@
-
- - - - -
+ + + + {#if $$slots.buttons}
diff --git a/src/ui/Icon.svelte b/src/ui/Icon.svelte index e6c5cbb..0409835 100644 --- a/src/ui/Icon.svelte +++ b/src/ui/Icon.svelte @@ -5,7 +5,7 @@ let classes = ""; export {classes as class}; - let svg = ICONS[`./icons/${name}.svelte`].default; + $: svg = ICONS[`./icons/${name}.svelte`].default; \ No newline at end of file diff --git a/src/ui/Link.svelte b/src/ui/Link.svelte index c8a85af..251ff75 100644 --- a/src/ui/Link.svelte +++ b/src/ui/Link.svelte @@ -31,6 +31,7 @@ && shift === event.shiftKey ) { click(); + event.preventDefault(); } } diff --git a/src/views/Approve.svelte b/src/views/Approve.svelte index 5c7a401..c6e9027 100644 --- a/src/views/Approve.svelte +++ b/src/views/Approve.svelte @@ -1,24 +1,23 @@ - -{#if error || !$appState.currentRequest?.response} +{#if success} + + +{:else if !$appState.currentRequest?.response || error} +
{#if error} {error.msg} - + {/if} - {#if $appState.currentRequest?.base} -
-
- - - WARNING: This application is requesting your base AWS credentials. - These credentials are less secure than session credentials, since they don't expire automatically. - -
-
- {/if} - -
-

{appName ? `"${appName}"` : 'An appplication'} would like to access your AWS credentials.

- -
-
Path:
- {@html client.exe ? breakPath(client.exe) : 'Unknown'} -
PID:
- {client.pid} -
-
- -
- - {#if !$appState.currentRequest?.base} -

- Approve with session credentials -

- approve(false)} hotkey="Enter" shift={true}> - - - {/if} - -

- - {#if $appState.currentRequest?.base} - Approve - {:else} - Approve with base credentials - {/if} - -

- approve(true)} hotkey="Enter" shift={true} ctrl={true}> - - - -

- Deny -

- - - -
+
+{:else if $appState.sessionStatus === 'locked'} + + +{:else} + + + Something is wrong. This message should never show up during normal operation. + {/if} diff --git a/src/views/EnterCredentials.svelte b/src/views/EnterCredentials.svelte deleted file mode 100644 index 0e6b63c..0000000 --- a/src/views/EnterCredentials.svelte +++ /dev/null @@ -1,94 +0,0 @@ - - - - -
-

Enter your credentials

- - {#if errorMsg} - {errorMsg} - {/if} - - - - - - - - - - -
diff --git a/src/views/Home.svelte b/src/views/Home.svelte index 9ac67d6..885b5d3 100644 --- a/src/views/Home.svelte +++ b/src/views/Home.svelte @@ -8,13 +8,21 @@ import Icon from '../ui/Icon.svelte'; import Link from '../ui/Link.svelte'; - import vaultDoorSvg from '../assets/vault_door.svg?raw'; let launchBase = false; function launchTerminal() { invoke('launch_terminal', {base: launchBase}); launchBase = false; } + + async function lock() { + try { + await invoke('lock'); + } + catch (e) { + console.log(e); + } + } @@ -24,30 +32,23 @@
- {@html vaultDoorSvg} - {#if $appState.credentialStatus === 'locked'} - -

Creddy is locked

- - - - - {:else if $appState.credentialStatus === 'unlocked'} -

Waiting for requests

- - - - {:else if $appState.credentialStatus === 'empty'} -

No credentials found

- - - - {/if} +

Waiting for requests

+ + + + + + + + +
diff --git a/src/views/Settings.svelte b/src/views/Settings.svelte index 486ee46..e8cfcc0 100644 --- a/src/views/Settings.svelte +++ b/src/views/Settings.svelte @@ -38,77 +38,78 @@

Settings

-
- - - - Start Creddy when you log in to your computer. - - - - - - Minimize to the system tray at startup. - - - - - - How long to wait after a request is approved/denied before minimizing - the window to tray. Only applicable if the window was minimized - to tray before the request was received. - - - - - - Automatically lock Creddy after a period of inactivity. - - - - {#if config.auto_lock} - +
+
+ + - How long to wait before automatically locking. + Start Creddy when you log in to your computer. - - {/if} + - - - - - - Update or re-enter your encrypted credentials. - - + + + Minimize to the system tray at startup. + + - - - Choose your preferred terminal emulator (e.g. gnome-terminal or wt.exe.) May be an absolute path or an executable discoverable on $PATH. - - - + + + How long to wait after a request is approved/denied before minimizing + the window to tray. Only applicable if the window was minimized + to tray before the request was received. + + - -
-

Click on a keybinding to modify it. Use the checkbox to enable or disable a keybinding entirely.

+ + + Automatically lock Creddy after a period of inactivity. + + -
- - + {#if config.auto_lock} + + + How long to wait before automatically locking. + + + {/if} + + + + + + + Update or re-enter your encrypted credentials. + + + + + + Choose your preferred terminal emulator (e.g. gnome-terminal or wt.exe.) May be an absolute path or an executable discoverable on $PATH. + + + + + +
+

Click on a keybinding to modify it. Use the checkbox to enable or disable a keybinding entirely.

+ +
+ + +
-
- + -

- Creddy {$appState.appVersion} -

-
+

+ Creddy {$appState.appVersion} +

+
+
{#if error}
diff --git a/src/views/ShowResponse.svelte b/src/views/ShowResponse.svelte deleted file mode 100644 index 321c8aa..0000000 --- a/src/views/ShowResponse.svelte +++ /dev/null @@ -1,38 +0,0 @@ - - - -
- {#if $appState.currentRequest.response.approval === 'Approved'} - - - - {:else} - - - - {/if} - -
- {$appState.currentRequest.response.approval}! -
-
diff --git a/src/views/Unlock.svelte b/src/views/Unlock.svelte index a4c39f1..9f887ea 100644 --- a/src/views/Unlock.svelte +++ b/src/views/Unlock.svelte @@ -1,39 +1,32 @@ +
+

Creddy is locked

+
+
-

Enter your passphrase

+
+ {@html vaultDoorSvg} +
- {#if errorMsg} - {errorMsg} - {/if} + - - - -
diff --git a/tailwind.config.js b/tailwind.config.js index d62e3df..85ced0f 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -10,4 +10,23 @@ module.exports = { plugins: [ require('daisyui'), ], + daisyui: { + themes: [ + { + creddy: { + "primary": "#115e59", + "secondary": "#8b5cf6", + "accent": "#0ea5e9", + "neutral": "#2f292c", + "base-100": "#252e3a", + "info": "#3aa8ff", + "success": "#52bf73", + "warning": "#d97706", + "error": "#f87171", + }, + }, + "dark", + "light" + ] + }, }