Compare commits
15 Commits
v0.2.0
...
c98a065587
Author | SHA1 | Date | |
---|---|---|---|
c98a065587 | |||
e46c3d2b4d | |||
e7e0f9d33e | |||
a51b20add7 | |||
890f715388 | |||
89bc74e644 | |||
60c24e3ee4 | |||
486001b584 | |||
52c949e396 | |||
d7c5c2f37b | |||
ae5b8f31db | |||
c260e37e78 | |||
7501253970 | |||
5b9c711008 | |||
ddd1005067 |
9
doc/cryptography.md
Normal file
9
doc/cryptography.md
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
My original plan was to use [libsodium](https://doc.libsodium.org/) to handle encryption. However, the Rust bindings for libsodium are no longer actively maintained, which left me uncomfortable with using it. Instead, I switched to the [RustCrypto](https://github.com/RustCrypto) implementations of the same (or nearly the same) cryptographic primitives provided by libsodium.
|
||||||
|
|
||||||
|
Creddy makes use of two cryptographic primitives: A key-derivation function, which is currently `argon2id`, and a symmetric encryption algorithm, currently `XChaCha20Poly1305`.
|
||||||
|
* I chose `argon2id` because it's what libsodium uses, and because its difficulty parameters admit of very granular tuning.
|
||||||
|
* I chose `XChaCha20Poly1305` because it's _almost_ what libsodium uses - libsodium uses `XSalsa20Poly1305`, and it's my undersatnding that `XChaCha20Poly1305` is an evolution of the former. In both cases I use the eXtended variants, which make use of longer (24-byte) nonces than the non-X variants. This appealed to me because I wanted to be able to randomly generate a nonce every time I needed one, and I have seen [recommendations](https://latacora.micro.blog/2018/04/03/cryptographic-right-answers.html) that the 12-byte nonces used by the non-X variants are _juuust_ a touch small for that to be truly worry-free. The RustCrypto implementation of `XChaCha20Poly1305` has also been subject to a security audit, which is nice.
|
||||||
|
|
||||||
|
I tuned the `argon2id` parameters so that key-derivation would take ~800ms on my Ryzen 1600X. This is probably overkill, but I don't intend for key-derivation to be a frequent occurrence - no more than once a day, under normal circumstances. Taking in the neighborhood of 1 second seemed about the longest I could reasonably go.
|
||||||
|
|
||||||
|
**DISCLAIMER**: I am not a professional cryptographer, merely an interested amateur. While I've tried to be as careful as possible with selecting and making use of the cryptographic building blocks I've chosen here, there is always the possibility that I've screwed something up. If anyone would like to sponsor an _actual_ security review of Creddy by people who _actually_ know what they're doing instead of just what they've read on the internet, please let me know.
|
540
package-lock.json
generated
540
package-lock.json
generated
@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "creddy",
|
"name": "creddy",
|
||||||
"version": "0.1.0",
|
"version": "0.2.2",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "creddy",
|
"name": "creddy",
|
||||||
"version": "0.1.0",
|
"version": "0.2.2",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tauri-apps/api": "^1.0.2",
|
"@tauri-apps/api": "^1.0.2",
|
||||||
"daisyui": "^2.51.5"
|
"daisyui": "^2.51.5"
|
||||||
@ -21,6 +21,17 @@
|
|||||||
"vite": "^3.0.7"
|
"vite": "^3.0.7"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@alloc/quick-lru": {
|
||||||
|
"version": "5.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz",
|
||||||
|
"integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@esbuild/android-arm": {
|
"node_modules/@esbuild/android-arm": {
|
||||||
"version": "0.15.18",
|
"version": "0.15.18",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.18.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.18.tgz",
|
||||||
@ -155,9 +166,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tauri-apps/api": {
|
"node_modules/@tauri-apps/api": {
|
||||||
"version": "1.2.0",
|
"version": "1.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@tauri-apps/api/-/api-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/@tauri-apps/api/-/api-1.4.0.tgz",
|
||||||
"integrity": "sha512-lsI54KI6HGf7VImuf/T9pnoejfgkNoXveP14pVV7XarrQ46rOejIVJLFqHI9sRReJMGdh2YuCoI3cc/yCWCsrw==",
|
"integrity": "sha512-Jd6HPoTM1PZSFIzq7FB8VmMu3qSSyo/3lSwLpoapW+lQ41CL5Dow2KryLg+gyazA/58DRWI9vu/XpEeHK4uMdw==",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 14.6.0",
|
"node": ">= 14.6.0",
|
||||||
"npm": ">= 6.6.0",
|
"npm": ">= 6.6.0",
|
||||||
@ -169,9 +180,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tauri-apps/cli": {
|
"node_modules/@tauri-apps/cli": {
|
||||||
"version": "1.2.3",
|
"version": "1.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli/-/cli-1.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/@tauri-apps/cli/-/cli-1.4.0.tgz",
|
||||||
"integrity": "sha512-erxtXuPhMEGJPBtnhPILD4AjuT81GZsraqpFvXAmEJZ2p8P6t7MVBifCL8LznRknznM3jn90D3M8RNBP3wcXTw==",
|
"integrity": "sha512-VXYr2i2iVFl98etQSQsqLzXgX96bnWiNZd1YADgatqwy/qecbd6Kl5ZAPB5R4ynsgE8A1gU7Fbzh7dCEQYFfmA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"tauri": "tauri.js"
|
"tauri": "tauri.js"
|
||||||
@ -184,21 +195,22 @@
|
|||||||
"url": "https://opencollective.com/tauri"
|
"url": "https://opencollective.com/tauri"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@tauri-apps/cli-darwin-arm64": "1.2.3",
|
"@tauri-apps/cli-darwin-arm64": "1.4.0",
|
||||||
"@tauri-apps/cli-darwin-x64": "1.2.3",
|
"@tauri-apps/cli-darwin-x64": "1.4.0",
|
||||||
"@tauri-apps/cli-linux-arm-gnueabihf": "1.2.3",
|
"@tauri-apps/cli-linux-arm-gnueabihf": "1.4.0",
|
||||||
"@tauri-apps/cli-linux-arm64-gnu": "1.2.3",
|
"@tauri-apps/cli-linux-arm64-gnu": "1.4.0",
|
||||||
"@tauri-apps/cli-linux-arm64-musl": "1.2.3",
|
"@tauri-apps/cli-linux-arm64-musl": "1.4.0",
|
||||||
"@tauri-apps/cli-linux-x64-gnu": "1.2.3",
|
"@tauri-apps/cli-linux-x64-gnu": "1.4.0",
|
||||||
"@tauri-apps/cli-linux-x64-musl": "1.2.3",
|
"@tauri-apps/cli-linux-x64-musl": "1.4.0",
|
||||||
"@tauri-apps/cli-win32-ia32-msvc": "1.2.3",
|
"@tauri-apps/cli-win32-arm64-msvc": "1.4.0",
|
||||||
"@tauri-apps/cli-win32-x64-msvc": "1.2.3"
|
"@tauri-apps/cli-win32-ia32-msvc": "1.4.0",
|
||||||
|
"@tauri-apps/cli-win32-x64-msvc": "1.4.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tauri-apps/cli-darwin-arm64": {
|
"node_modules/@tauri-apps/cli-darwin-arm64": {
|
||||||
"version": "1.2.3",
|
"version": "1.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-1.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-1.4.0.tgz",
|
||||||
"integrity": "sha512-phJN3fN8FtZZwqXg08bcxfq1+X1JSDglLvRxOxB7VWPq+O5SuB8uLyssjJsu+PIhyZZnIhTGdjhzLSFhSXfLsw==",
|
"integrity": "sha512-nA/ml0SfUt6/CYLVbHmT500Y+ijqsuv5+s9EBnVXYSLVg9kbPUZJJHluEYK+xKuOj6xzyuT/+rZFMRapmJD3jQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@ -212,9 +224,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tauri-apps/cli-darwin-x64": {
|
"node_modules/@tauri-apps/cli-darwin-x64": {
|
||||||
"version": "1.2.3",
|
"version": "1.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-1.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-1.4.0.tgz",
|
||||||
"integrity": "sha512-jFZ/y6z8z6v4yliIbXKBXA7BJgtZVMsITmEXSuD6s5+eCOpDhQxbRkr6CA+FFfr+/r96rWSDSgDenDQuSvPAKw==",
|
"integrity": "sha512-ov/F6Zr+dg9B0PtRu65stFo2G0ow2TUlneqYYrkj+vA3n+moWDHfVty0raDjMLQbQt3rv3uayFMXGPMgble9OA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@ -228,9 +240,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tauri-apps/cli-linux-arm-gnueabihf": {
|
"node_modules/@tauri-apps/cli-linux-arm-gnueabihf": {
|
||||||
"version": "1.2.3",
|
"version": "1.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-1.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-1.4.0.tgz",
|
||||||
"integrity": "sha512-C7h5vqAwXzY0kRGSU00Fj8PudiDWFCiQqqUNI1N+fhCILrzWZB9TPBwdx33ZfXKt/U4+emdIoo/N34v3TiAOmQ==",
|
"integrity": "sha512-zwjbiMncycXDV7doovymyKD7sCg53ouAmfgpUqEBOTY3vgBi9TwijyPhJOqoG5vUVWhouNBC08akGmE4dja15g==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm"
|
"arm"
|
||||||
],
|
],
|
||||||
@ -244,9 +256,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tauri-apps/cli-linux-arm64-gnu": {
|
"node_modules/@tauri-apps/cli-linux-arm64-gnu": {
|
||||||
"version": "1.2.3",
|
"version": "1.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-1.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-1.4.0.tgz",
|
||||||
"integrity": "sha512-buf1c8sdkuUzVDkGPQpyUdAIIdn5r0UgXU6+H5fGPq/Xzt5K69JzXaeo6fHsZEZghbV0hOK+taKV4J0m30UUMQ==",
|
"integrity": "sha512-5MCBcziqXC72mMXnkZU68mutXIR6zavDxopArE2gQtK841IlE06bIgtLi0kUUhlFJk2nhPRgiDgdLbrPlyt7fw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@ -260,9 +272,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tauri-apps/cli-linux-arm64-musl": {
|
"node_modules/@tauri-apps/cli-linux-arm64-musl": {
|
||||||
"version": "1.2.3",
|
"version": "1.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-1.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-1.4.0.tgz",
|
||||||
"integrity": "sha512-x88wPS9W5xAyk392vc4uNHcKBBvCp0wf4H9JFMF9OBwB7vfd59LbQCFcPSu8f0BI7bPrOsyHqspWHuFL8ojQEA==",
|
"integrity": "sha512-7J3pRB6n6uNYgIfCeKt2Oz8J7oSaz2s8GGFRRH2HPxuTHrBNCinzVYm68UhVpJrL3bnGkU0ziVZLsW/iaOGfUg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@ -276,9 +288,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tauri-apps/cli-linux-x64-gnu": {
|
"node_modules/@tauri-apps/cli-linux-x64-gnu": {
|
||||||
"version": "1.2.3",
|
"version": "1.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-1.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-1.4.0.tgz",
|
||||||
"integrity": "sha512-ZMz1jxEVe0B4/7NJnlPHmwmSIuwiD6ViXKs8F+OWWz2Y4jn5TGxWKFg7DLx5OwQTRvEIZxxT7lXHi5CuTNAxKg==",
|
"integrity": "sha512-Zh5gfAJxOv5AVWxcwuueaQ2vIAhlg0d6nZui6nMyfIJ8dbf3aZQ5ZzP38sYow5h/fbvgL+3GSQxZRBIa3c2E1w==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@ -292,9 +304,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tauri-apps/cli-linux-x64-musl": {
|
"node_modules/@tauri-apps/cli-linux-x64-musl": {
|
||||||
"version": "1.2.3",
|
"version": "1.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-1.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-1.4.0.tgz",
|
||||||
"integrity": "sha512-B/az59EjJhdbZDzawEVox0LQu2ZHCZlk8rJf85AMIktIUoAZPFbwyiUv7/zjzA/sY6Nb58OSJgaPL2/IBy7E0A==",
|
"integrity": "sha512-OLAYoICU3FaYiTdBsI+lQTKnDHeMmFMXIApN0M+xGiOkoIOQcV9CConMPjgmJQ867+NHRNgUGlvBEAh9CiJodQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@ -307,10 +319,26 @@
|
|||||||
"node": ">= 10"
|
"node": ">= 10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@tauri-apps/cli-win32-arm64-msvc": {
|
||||||
|
"version": "1.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-arm64-msvc/-/cli-win32-arm64-msvc-1.4.0.tgz",
|
||||||
|
"integrity": "sha512-gZ05GENFbI6CB5MlOUsLlU0kZ9UtHn9riYtSXKT6MYs8HSPRffPHaHSL0WxsJweWh9nR5Hgh/TUU8uW3sYCzCg==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"win32"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@tauri-apps/cli-win32-ia32-msvc": {
|
"node_modules/@tauri-apps/cli-win32-ia32-msvc": {
|
||||||
"version": "1.2.3",
|
"version": "1.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-1.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-1.4.0.tgz",
|
||||||
"integrity": "sha512-ypdO1OdC5ugNJAKO2m3sb1nsd+0TSvMS9Tr5qN/ZSMvtSduaNwrcZ3D7G/iOIanrqu/Nl8t3LYlgPZGBKlw7Ng==",
|
"integrity": "sha512-JsetT/lTx/Zq98eo8T5CiRyF1nKeX04RO8JlJrI3ZOYsZpp/A5RJvMd/szQ17iOzwiHdge+tx7k2jHysR6oBlQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"ia32"
|
"ia32"
|
||||||
],
|
],
|
||||||
@ -324,9 +352,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tauri-apps/cli-win32-x64-msvc": {
|
"node_modules/@tauri-apps/cli-win32-x64-msvc": {
|
||||||
"version": "1.2.3",
|
"version": "1.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-1.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-1.4.0.tgz",
|
||||||
"integrity": "sha512-CsbHQ+XhnV/2csOBBDVfH16cdK00gNyNYUW68isedmqcn8j+s0e9cQ1xXIqi+Hue3awp8g3ImYN5KPepf3UExw==",
|
"integrity": "sha512-z8Olcnwp5aYhzqUAarFjqF+oELCjuYWnB2HAJHlfsYNfDCAORY5kct3Fklz8PSsubC3U2EugWn8n42DwnThurg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@ -427,9 +455,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/browserslist": {
|
"node_modules/browserslist": {
|
||||||
"version": "4.21.5",
|
"version": "4.21.9",
|
||||||
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz",
|
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.9.tgz",
|
||||||
"integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==",
|
"integrity": "sha512-M0MFoZzbUrRU4KNfCrDLnvyE7gub+peetoTid3TBIqtunaDJyXlwhakT+/VkvSXcfIzFfK/nkCs4nmyTmxdNSg==",
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "opencollective",
|
"type": "opencollective",
|
||||||
@ -438,13 +466,17 @@
|
|||||||
{
|
{
|
||||||
"type": "tidelift",
|
"type": "tidelift",
|
||||||
"url": "https://tidelift.com/funding/github/npm/browserslist"
|
"url": "https://tidelift.com/funding/github/npm/browserslist"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/ai"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"caniuse-lite": "^1.0.30001449",
|
"caniuse-lite": "^1.0.30001503",
|
||||||
"electron-to-chromium": "^1.4.284",
|
"electron-to-chromium": "^1.4.431",
|
||||||
"node-releases": "^2.0.8",
|
"node-releases": "^2.0.12",
|
||||||
"update-browserslist-db": "^1.0.10"
|
"update-browserslist-db": "^1.0.11"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"browserslist": "cli.js"
|
"browserslist": "cli.js"
|
||||||
@ -462,9 +494,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/caniuse-lite": {
|
"node_modules/caniuse-lite": {
|
||||||
"version": "1.0.30001481",
|
"version": "1.0.30001515",
|
||||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001481.tgz",
|
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001515.tgz",
|
||||||
"integrity": "sha512-KCqHwRnaa1InZBtqXzP98LPg0ajCVujMKjqKDhZEthIpAsJl/YEIa3YvXjGXPVqzZVguccuu7ga9KOE1J9rKPQ==",
|
"integrity": "sha512-eEFDwUOZbE24sb+Ecsx3+OvNETqjWIdabMy52oOkIgcUtAsQifjUG9q4U9dgTHJM2mfk4uEPxc0+xuFdJ629QA==",
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "opencollective",
|
"type": "opencollective",
|
||||||
@ -588,9 +620,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/daisyui": {
|
"node_modules/daisyui": {
|
||||||
"version": "2.51.5",
|
"version": "2.52.0",
|
||||||
"resolved": "https://registry.npmjs.org/daisyui/-/daisyui-2.51.5.tgz",
|
"resolved": "https://registry.npmjs.org/daisyui/-/daisyui-2.52.0.tgz",
|
||||||
"integrity": "sha512-L05dRw0tasmz2Ha+10LhftEGLq4kaA8vRR/T0wDaXfHwqcgsf81jfXDJ6NlZ63Z7Rl1k3rj7UHs0l0p7CM3aYA==",
|
"integrity": "sha512-LQTA5/IVXAJHBMFoeaEMfd7/akAFPPcdQPR3O9fzzcFiczneJFM73CFPnScmW2sOgn/D83cvkP854ep2T9OfTg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"color": "^4.2",
|
"color": "^4.2",
|
||||||
"css-selector-tokenizer": "^0.8.0",
|
"css-selector-tokenizer": "^0.8.0",
|
||||||
@ -643,9 +675,9 @@
|
|||||||
"integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA=="
|
"integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA=="
|
||||||
},
|
},
|
||||||
"node_modules/electron-to-chromium": {
|
"node_modules/electron-to-chromium": {
|
||||||
"version": "1.4.369",
|
"version": "1.4.455",
|
||||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.369.tgz",
|
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.455.tgz",
|
||||||
"integrity": "sha512-LfxbHXdA/S+qyoTEA4EbhxGjrxx7WK2h6yb5K2v0UCOufUKX+VZaHbl3svlzZfv9sGseym/g3Ne4DpsgRULmqg=="
|
"integrity": "sha512-8tgdX0Odl24LtmLwxotpJCVjIndN559AvaOtd67u+2mo+IDsgsTF580NB+uuDCqsHw8yFg53l5+imFV9Fw3cbA=="
|
||||||
},
|
},
|
||||||
"node_modules/esbuild": {
|
"node_modules/esbuild": {
|
||||||
"version": "0.15.18",
|
"version": "0.15.18",
|
||||||
@ -1013,9 +1045,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/fast-glob": {
|
"node_modules/fast-glob": {
|
||||||
"version": "3.2.12",
|
"version": "3.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz",
|
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.0.tgz",
|
||||||
"integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==",
|
"integrity": "sha512-ChDuvbOypPuNjO8yIDf36x7BlZX1smcUMTTcyoIjycexOxd6DFsKsg21qVBzEmr3G7fUKIRy2/psii+CIUt7FA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@nodelib/fs.stat": "^2.0.2",
|
"@nodelib/fs.stat": "^2.0.2",
|
||||||
"@nodelib/fs.walk": "^1.2.3",
|
"@nodelib/fs.walk": "^1.2.3",
|
||||||
@ -1169,9 +1201,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/is-core-module": {
|
"node_modules/is-core-module": {
|
||||||
"version": "2.12.0",
|
"version": "2.12.1",
|
||||||
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.0.tgz",
|
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz",
|
||||||
"integrity": "sha512-RECHCBCd/viahWmwj6enj19sKbHfJrddi/6cBDsNTKbNq0f7VeaUkBo60BqzvPqo/W54ChS62Z5qyun7cfOMqQ==",
|
"integrity": "sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"has": "^1.0.3"
|
"has": "^1.0.3"
|
||||||
},
|
},
|
||||||
@ -1207,9 +1239,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/jiti": {
|
"node_modules/jiti": {
|
||||||
"version": "1.18.2",
|
"version": "1.19.1",
|
||||||
"resolved": "https://registry.npmjs.org/jiti/-/jiti-1.18.2.tgz",
|
"resolved": "https://registry.npmjs.org/jiti/-/jiti-1.19.1.tgz",
|
||||||
"integrity": "sha512-QAdOptna2NYiSSpv0O/BwoHBSmz4YhpzJHyi+fnMRTXFjp7B8i/YG5Z8IfusxB1ufjcD2Sre1F3R+nX3fvy7gg==",
|
"integrity": "sha512-oVhqoRDaBXf7sjkll95LHVS6Myyyb1zaunVwk4Z0+WPSW4gjS0pl01zYKHScTuyEhQsFxV5L4DR5r+YqSyqyyg==",
|
||||||
"bin": {
|
"bin": {
|
||||||
"jiti": "bin/jiti.js"
|
"jiti": "bin/jiti.js"
|
||||||
}
|
}
|
||||||
@ -1313,9 +1345,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/node-releases": {
|
"node_modules/node-releases": {
|
||||||
"version": "2.0.10",
|
"version": "2.0.13",
|
||||||
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz",
|
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz",
|
||||||
"integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w=="
|
"integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ=="
|
||||||
},
|
},
|
||||||
"node_modules/normalize-path": {
|
"node_modules/normalize-path": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
@ -1395,17 +1427,17 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/pirates": {
|
"node_modules/pirates": {
|
||||||
"version": "4.0.5",
|
"version": "4.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz",
|
||||||
"integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==",
|
"integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 6"
|
"node": ">= 6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/postcss": {
|
"node_modules/postcss": {
|
||||||
"version": "8.4.23",
|
"version": "8.4.25",
|
||||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.23.tgz",
|
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.25.tgz",
|
||||||
"integrity": "sha512-bQ3qMcpF6A/YjR55xtoTr0jGOlnPOKAIMdOWiv0EIT6HVPEaJiJB4NLljSbiHoC2RX7DN5Uvjtpbg1NPdwv1oA==",
|
"integrity": "sha512-7taJ/8t2av0Z+sQEvNzCkpDynl0tX3uJMCODi6nT3PfASC7dYCWV9aQ+uiCf+KBD4SEFcu+GvJdGdwzQ6OSjCw==",
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "opencollective",
|
"type": "opencollective",
|
||||||
@ -1430,16 +1462,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/postcss-import": {
|
"node_modules/postcss-import": {
|
||||||
"version": "14.1.0",
|
"version": "15.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-14.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz",
|
||||||
"integrity": "sha512-flwI+Vgm4SElObFVPpTIT7SU7R3qk2L7PyduMcokiaVKuWv9d/U+Gm/QAd8NDLuykTWTkcrjOeD2Pp1rMeBTGw==",
|
"integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"postcss-value-parser": "^4.0.0",
|
"postcss-value-parser": "^4.0.0",
|
||||||
"read-cache": "^1.0.0",
|
"read-cache": "^1.0.0",
|
||||||
"resolve": "^1.1.7"
|
"resolve": "^1.1.7"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10.0.0"
|
"node": ">=14.0.0"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"postcss": "^8.0.0"
|
"postcss": "^8.0.0"
|
||||||
@ -1464,15 +1496,15 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/postcss-load-config": {
|
"node_modules/postcss-load-config": {
|
||||||
"version": "3.1.4",
|
"version": "4.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.1.tgz",
|
||||||
"integrity": "sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==",
|
"integrity": "sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"lilconfig": "^2.0.5",
|
"lilconfig": "^2.0.5",
|
||||||
"yaml": "^1.10.2"
|
"yaml": "^2.1.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 10"
|
"node": ">= 14"
|
||||||
},
|
},
|
||||||
"funding": {
|
"funding": {
|
||||||
"type": "opencollective",
|
"type": "opencollective",
|
||||||
@ -1492,11 +1524,11 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/postcss-nested": {
|
"node_modules/postcss-nested": {
|
||||||
"version": "6.0.0",
|
"version": "6.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.1.tgz",
|
||||||
"integrity": "sha512-0DkamqrPcmkBDsLn+vQDIrtkSbNkv5AD/M322ySo9kqFkCIYklym2xEmWkwo+Y3/qZo34tzEPNUw4y7yMCdv5w==",
|
"integrity": "sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"postcss-selector-parser": "^6.0.10"
|
"postcss-selector-parser": "^6.0.11"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12.0"
|
"node": ">=12.0"
|
||||||
@ -1510,9 +1542,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/postcss-selector-parser": {
|
"node_modules/postcss-selector-parser": {
|
||||||
"version": "6.0.11",
|
"version": "6.0.13",
|
||||||
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.11.tgz",
|
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz",
|
||||||
"integrity": "sha512-zbARubNdogI9j7WY4nQJBiNqQf3sLS3wCP4WfOidu+p28LofJqDH1tcXypGrcmMHhDk2t9wGhCsYe/+szLTy1g==",
|
"integrity": "sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"cssesc": "^3.0.0",
|
"cssesc": "^3.0.0",
|
||||||
"util-deprecate": "^1.0.2"
|
"util-deprecate": "^1.0.2"
|
||||||
@ -1545,17 +1577,6 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/quick-lru": {
|
|
||||||
"version": "5.1.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz",
|
|
||||||
"integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=10"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/read-cache": {
|
"node_modules/read-cache": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
|
||||||
@ -1693,65 +1714,61 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/svelte": {
|
"node_modules/svelte": {
|
||||||
"version": "3.58.0",
|
"version": "3.59.2",
|
||||||
"resolved": "https://registry.npmjs.org/svelte/-/svelte-3.58.0.tgz",
|
"resolved": "https://registry.npmjs.org/svelte/-/svelte-3.59.2.tgz",
|
||||||
"integrity": "sha512-brIBNNB76mXFmU/Kerm4wFnkskBbluBDCjx/8TcpYRb298Yh2dztS2kQ6bhtjMcvUhd5ynClfwpz5h2gnzdQ1A==",
|
"integrity": "sha512-vzSyuGr3eEoAtT/A6bmajosJZIUWySzY2CzB3w2pgPvnkUjGqlDnsNnA0PMO+mMAhuyMul6C2uuZzY6ELSkzyA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 8"
|
"node": ">= 8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/svelte-hmr": {
|
"node_modules/svelte-hmr": {
|
||||||
"version": "0.15.1",
|
"version": "0.15.2",
|
||||||
"resolved": "https://registry.npmjs.org/svelte-hmr/-/svelte-hmr-0.15.1.tgz",
|
"resolved": "https://registry.npmjs.org/svelte-hmr/-/svelte-hmr-0.15.2.tgz",
|
||||||
"integrity": "sha512-BiKB4RZ8YSwRKCNVdNxK/GfY+r4Kjgp9jCLEy0DuqAKfmQtpL38cQK3afdpjw4sqSs4PLi3jIPJIFp259NkZtA==",
|
"integrity": "sha512-q/bAruCvFLwvNbeE1x3n37TYFb3mTBJ6TrCq6p2CoFbSTNhDE9oAtEfpy+wmc9So8AG0Tja+X0/mJzX9tSfvIg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^12.20 || ^14.13.1 || >= 16"
|
"node": "^12.20 || ^14.13.1 || >= 16"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"svelte": ">=3.19.0"
|
"svelte": "^3.19.0 || ^4.0.0-next.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/tailwindcss": {
|
"node_modules/tailwindcss": {
|
||||||
"version": "3.3.1",
|
"version": "3.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.2.tgz",
|
||||||
"integrity": "sha512-Vkiouc41d4CEq0ujXl6oiGFQ7bA3WEhUZdTgXAhtKxSy49OmKs8rEfQmupsfF0IGW8fv2iQkp1EVUuapCFrZ9g==",
|
"integrity": "sha512-9jPkMiIBXvPc2KywkraqsUfbfj+dHDb+JPWtSJa9MLFdrPyazI7q6WX2sUrm7R9eVR7qqv3Pas7EvQFzxKnI6w==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@alloc/quick-lru": "^5.2.0",
|
||||||
"arg": "^5.0.2",
|
"arg": "^5.0.2",
|
||||||
"chokidar": "^3.5.3",
|
"chokidar": "^3.5.3",
|
||||||
"color-name": "^1.1.4",
|
|
||||||
"didyoumean": "^1.2.2",
|
"didyoumean": "^1.2.2",
|
||||||
"dlv": "^1.1.3",
|
"dlv": "^1.1.3",
|
||||||
"fast-glob": "^3.2.12",
|
"fast-glob": "^3.2.12",
|
||||||
"glob-parent": "^6.0.2",
|
"glob-parent": "^6.0.2",
|
||||||
"is-glob": "^4.0.3",
|
"is-glob": "^4.0.3",
|
||||||
"jiti": "^1.17.2",
|
"jiti": "^1.18.2",
|
||||||
"lilconfig": "^2.0.6",
|
"lilconfig": "^2.1.0",
|
||||||
"micromatch": "^4.0.5",
|
"micromatch": "^4.0.5",
|
||||||
"normalize-path": "^3.0.0",
|
"normalize-path": "^3.0.0",
|
||||||
"object-hash": "^3.0.0",
|
"object-hash": "^3.0.0",
|
||||||
"picocolors": "^1.0.0",
|
"picocolors": "^1.0.0",
|
||||||
"postcss": "^8.0.9",
|
"postcss": "^8.4.23",
|
||||||
"postcss-import": "^14.1.0",
|
"postcss-import": "^15.1.0",
|
||||||
"postcss-js": "^4.0.0",
|
"postcss-js": "^4.0.1",
|
||||||
"postcss-load-config": "^3.1.4",
|
"postcss-load-config": "^4.0.1",
|
||||||
"postcss-nested": "6.0.0",
|
"postcss-nested": "^6.0.1",
|
||||||
"postcss-selector-parser": "^6.0.11",
|
"postcss-selector-parser": "^6.0.11",
|
||||||
"postcss-value-parser": "^4.2.0",
|
"postcss-value-parser": "^4.2.0",
|
||||||
"quick-lru": "^5.1.1",
|
"resolve": "^1.22.2",
|
||||||
"resolve": "^1.22.1",
|
"sucrase": "^3.32.0"
|
||||||
"sucrase": "^3.29.0"
|
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"tailwind": "lib/cli.js",
|
"tailwind": "lib/cli.js",
|
||||||
"tailwindcss": "lib/cli.js"
|
"tailwindcss": "lib/cli.js"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12.13.0"
|
"node": ">=14.0.0"
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"postcss": "^8.0.9"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/thenify": {
|
"node_modules/thenify": {
|
||||||
@ -1824,9 +1841,9 @@
|
|||||||
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
|
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
|
||||||
},
|
},
|
||||||
"node_modules/vite": {
|
"node_modules/vite": {
|
||||||
"version": "3.2.6",
|
"version": "3.2.7",
|
||||||
"resolved": "https://registry.npmjs.org/vite/-/vite-3.2.6.tgz",
|
"resolved": "https://registry.npmjs.org/vite/-/vite-3.2.7.tgz",
|
||||||
"integrity": "sha512-nTXTxYVvaQNLoW5BQ8PNNQ3lPia57gzsQU/Khv+JvzKPku8kNZL6NMUR/qwXhMG6E+g1idqEPanomJ+VZgixEg==",
|
"integrity": "sha512-29pdXjk49xAP0QBr0xXqu2s5jiQIXNvE/xwd0vUizYT2Hzqe4BksNNoWllFVXJf4eLZ+UlVQmXfB4lWrc+t18g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"esbuild": "^0.15.9",
|
"esbuild": "^0.15.9",
|
||||||
@ -1892,15 +1909,20 @@
|
|||||||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
|
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
|
||||||
},
|
},
|
||||||
"node_modules/yaml": {
|
"node_modules/yaml": {
|
||||||
"version": "1.10.2",
|
"version": "2.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
|
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.1.tgz",
|
||||||
"integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==",
|
"integrity": "sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ==",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 6"
|
"node": ">= 14"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@alloc/quick-lru": {
|
||||||
|
"version": "5.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz",
|
||||||
|
"integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw=="
|
||||||
|
},
|
||||||
"@esbuild/android-arm": {
|
"@esbuild/android-arm": {
|
||||||
"version": "0.15.18",
|
"version": "0.15.18",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.18.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.18.tgz",
|
||||||
@ -1994,87 +2016,95 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@tauri-apps/api": {
|
"@tauri-apps/api": {
|
||||||
"version": "1.2.0",
|
"version": "1.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@tauri-apps/api/-/api-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/@tauri-apps/api/-/api-1.4.0.tgz",
|
||||||
"integrity": "sha512-lsI54KI6HGf7VImuf/T9pnoejfgkNoXveP14pVV7XarrQ46rOejIVJLFqHI9sRReJMGdh2YuCoI3cc/yCWCsrw=="
|
"integrity": "sha512-Jd6HPoTM1PZSFIzq7FB8VmMu3qSSyo/3lSwLpoapW+lQ41CL5Dow2KryLg+gyazA/58DRWI9vu/XpEeHK4uMdw=="
|
||||||
},
|
},
|
||||||
"@tauri-apps/cli": {
|
"@tauri-apps/cli": {
|
||||||
"version": "1.2.3",
|
"version": "1.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli/-/cli-1.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/@tauri-apps/cli/-/cli-1.4.0.tgz",
|
||||||
"integrity": "sha512-erxtXuPhMEGJPBtnhPILD4AjuT81GZsraqpFvXAmEJZ2p8P6t7MVBifCL8LznRknznM3jn90D3M8RNBP3wcXTw==",
|
"integrity": "sha512-VXYr2i2iVFl98etQSQsqLzXgX96bnWiNZd1YADgatqwy/qecbd6Kl5ZAPB5R4ynsgE8A1gU7Fbzh7dCEQYFfmA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@tauri-apps/cli-darwin-arm64": "1.2.3",
|
"@tauri-apps/cli-darwin-arm64": "1.4.0",
|
||||||
"@tauri-apps/cli-darwin-x64": "1.2.3",
|
"@tauri-apps/cli-darwin-x64": "1.4.0",
|
||||||
"@tauri-apps/cli-linux-arm-gnueabihf": "1.2.3",
|
"@tauri-apps/cli-linux-arm-gnueabihf": "1.4.0",
|
||||||
"@tauri-apps/cli-linux-arm64-gnu": "1.2.3",
|
"@tauri-apps/cli-linux-arm64-gnu": "1.4.0",
|
||||||
"@tauri-apps/cli-linux-arm64-musl": "1.2.3",
|
"@tauri-apps/cli-linux-arm64-musl": "1.4.0",
|
||||||
"@tauri-apps/cli-linux-x64-gnu": "1.2.3",
|
"@tauri-apps/cli-linux-x64-gnu": "1.4.0",
|
||||||
"@tauri-apps/cli-linux-x64-musl": "1.2.3",
|
"@tauri-apps/cli-linux-x64-musl": "1.4.0",
|
||||||
"@tauri-apps/cli-win32-ia32-msvc": "1.2.3",
|
"@tauri-apps/cli-win32-arm64-msvc": "1.4.0",
|
||||||
"@tauri-apps/cli-win32-x64-msvc": "1.2.3"
|
"@tauri-apps/cli-win32-ia32-msvc": "1.4.0",
|
||||||
|
"@tauri-apps/cli-win32-x64-msvc": "1.4.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@tauri-apps/cli-darwin-arm64": {
|
"@tauri-apps/cli-darwin-arm64": {
|
||||||
"version": "1.2.3",
|
"version": "1.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-1.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-1.4.0.tgz",
|
||||||
"integrity": "sha512-phJN3fN8FtZZwqXg08bcxfq1+X1JSDglLvRxOxB7VWPq+O5SuB8uLyssjJsu+PIhyZZnIhTGdjhzLSFhSXfLsw==",
|
"integrity": "sha512-nA/ml0SfUt6/CYLVbHmT500Y+ijqsuv5+s9EBnVXYSLVg9kbPUZJJHluEYK+xKuOj6xzyuT/+rZFMRapmJD3jQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"@tauri-apps/cli-darwin-x64": {
|
"@tauri-apps/cli-darwin-x64": {
|
||||||
"version": "1.2.3",
|
"version": "1.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-1.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-1.4.0.tgz",
|
||||||
"integrity": "sha512-jFZ/y6z8z6v4yliIbXKBXA7BJgtZVMsITmEXSuD6s5+eCOpDhQxbRkr6CA+FFfr+/r96rWSDSgDenDQuSvPAKw==",
|
"integrity": "sha512-ov/F6Zr+dg9B0PtRu65stFo2G0ow2TUlneqYYrkj+vA3n+moWDHfVty0raDjMLQbQt3rv3uayFMXGPMgble9OA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"@tauri-apps/cli-linux-arm-gnueabihf": {
|
"@tauri-apps/cli-linux-arm-gnueabihf": {
|
||||||
"version": "1.2.3",
|
"version": "1.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-1.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-1.4.0.tgz",
|
||||||
"integrity": "sha512-C7h5vqAwXzY0kRGSU00Fj8PudiDWFCiQqqUNI1N+fhCILrzWZB9TPBwdx33ZfXKt/U4+emdIoo/N34v3TiAOmQ==",
|
"integrity": "sha512-zwjbiMncycXDV7doovymyKD7sCg53ouAmfgpUqEBOTY3vgBi9TwijyPhJOqoG5vUVWhouNBC08akGmE4dja15g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"@tauri-apps/cli-linux-arm64-gnu": {
|
"@tauri-apps/cli-linux-arm64-gnu": {
|
||||||
"version": "1.2.3",
|
"version": "1.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-1.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-1.4.0.tgz",
|
||||||
"integrity": "sha512-buf1c8sdkuUzVDkGPQpyUdAIIdn5r0UgXU6+H5fGPq/Xzt5K69JzXaeo6fHsZEZghbV0hOK+taKV4J0m30UUMQ==",
|
"integrity": "sha512-5MCBcziqXC72mMXnkZU68mutXIR6zavDxopArE2gQtK841IlE06bIgtLi0kUUhlFJk2nhPRgiDgdLbrPlyt7fw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"@tauri-apps/cli-linux-arm64-musl": {
|
"@tauri-apps/cli-linux-arm64-musl": {
|
||||||
"version": "1.2.3",
|
"version": "1.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-1.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-1.4.0.tgz",
|
||||||
"integrity": "sha512-x88wPS9W5xAyk392vc4uNHcKBBvCp0wf4H9JFMF9OBwB7vfd59LbQCFcPSu8f0BI7bPrOsyHqspWHuFL8ojQEA==",
|
"integrity": "sha512-7J3pRB6n6uNYgIfCeKt2Oz8J7oSaz2s8GGFRRH2HPxuTHrBNCinzVYm68UhVpJrL3bnGkU0ziVZLsW/iaOGfUg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"@tauri-apps/cli-linux-x64-gnu": {
|
"@tauri-apps/cli-linux-x64-gnu": {
|
||||||
"version": "1.2.3",
|
"version": "1.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-1.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-1.4.0.tgz",
|
||||||
"integrity": "sha512-ZMz1jxEVe0B4/7NJnlPHmwmSIuwiD6ViXKs8F+OWWz2Y4jn5TGxWKFg7DLx5OwQTRvEIZxxT7lXHi5CuTNAxKg==",
|
"integrity": "sha512-Zh5gfAJxOv5AVWxcwuueaQ2vIAhlg0d6nZui6nMyfIJ8dbf3aZQ5ZzP38sYow5h/fbvgL+3GSQxZRBIa3c2E1w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"@tauri-apps/cli-linux-x64-musl": {
|
"@tauri-apps/cli-linux-x64-musl": {
|
||||||
"version": "1.2.3",
|
"version": "1.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-1.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-1.4.0.tgz",
|
||||||
"integrity": "sha512-B/az59EjJhdbZDzawEVox0LQu2ZHCZlk8rJf85AMIktIUoAZPFbwyiUv7/zjzA/sY6Nb58OSJgaPL2/IBy7E0A==",
|
"integrity": "sha512-OLAYoICU3FaYiTdBsI+lQTKnDHeMmFMXIApN0M+xGiOkoIOQcV9CConMPjgmJQ867+NHRNgUGlvBEAh9CiJodQ==",
|
||||||
|
"dev": true,
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@tauri-apps/cli-win32-arm64-msvc": {
|
||||||
|
"version": "1.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-arm64-msvc/-/cli-win32-arm64-msvc-1.4.0.tgz",
|
||||||
|
"integrity": "sha512-gZ05GENFbI6CB5MlOUsLlU0kZ9UtHn9riYtSXKT6MYs8HSPRffPHaHSL0WxsJweWh9nR5Hgh/TUU8uW3sYCzCg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"@tauri-apps/cli-win32-ia32-msvc": {
|
"@tauri-apps/cli-win32-ia32-msvc": {
|
||||||
"version": "1.2.3",
|
"version": "1.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-1.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-1.4.0.tgz",
|
||||||
"integrity": "sha512-ypdO1OdC5ugNJAKO2m3sb1nsd+0TSvMS9Tr5qN/ZSMvtSduaNwrcZ3D7G/iOIanrqu/Nl8t3LYlgPZGBKlw7Ng==",
|
"integrity": "sha512-JsetT/lTx/Zq98eo8T5CiRyF1nKeX04RO8JlJrI3ZOYsZpp/A5RJvMd/szQ17iOzwiHdge+tx7k2jHysR6oBlQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"@tauri-apps/cli-win32-x64-msvc": {
|
"@tauri-apps/cli-win32-x64-msvc": {
|
||||||
"version": "1.2.3",
|
"version": "1.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-1.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-1.4.0.tgz",
|
||||||
"integrity": "sha512-CsbHQ+XhnV/2csOBBDVfH16cdK00gNyNYUW68isedmqcn8j+s0e9cQ1xXIqi+Hue3awp8g3ImYN5KPepf3UExw==",
|
"integrity": "sha512-z8Olcnwp5aYhzqUAarFjqF+oELCjuYWnB2HAJHlfsYNfDCAORY5kct3Fklz8PSsubC3U2EugWn8n42DwnThurg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
@ -2138,14 +2168,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"browserslist": {
|
"browserslist": {
|
||||||
"version": "4.21.5",
|
"version": "4.21.9",
|
||||||
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz",
|
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.9.tgz",
|
||||||
"integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==",
|
"integrity": "sha512-M0MFoZzbUrRU4KNfCrDLnvyE7gub+peetoTid3TBIqtunaDJyXlwhakT+/VkvSXcfIzFfK/nkCs4nmyTmxdNSg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"caniuse-lite": "^1.0.30001449",
|
"caniuse-lite": "^1.0.30001503",
|
||||||
"electron-to-chromium": "^1.4.284",
|
"electron-to-chromium": "^1.4.431",
|
||||||
"node-releases": "^2.0.8",
|
"node-releases": "^2.0.12",
|
||||||
"update-browserslist-db": "^1.0.10"
|
"update-browserslist-db": "^1.0.11"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"camelcase-css": {
|
"camelcase-css": {
|
||||||
@ -2154,9 +2184,9 @@
|
|||||||
"integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA=="
|
"integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA=="
|
||||||
},
|
},
|
||||||
"caniuse-lite": {
|
"caniuse-lite": {
|
||||||
"version": "1.0.30001481",
|
"version": "1.0.30001515",
|
||||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001481.tgz",
|
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001515.tgz",
|
||||||
"integrity": "sha512-KCqHwRnaa1InZBtqXzP98LPg0ajCVujMKjqKDhZEthIpAsJl/YEIa3YvXjGXPVqzZVguccuu7ga9KOE1J9rKPQ=="
|
"integrity": "sha512-eEFDwUOZbE24sb+Ecsx3+OvNETqjWIdabMy52oOkIgcUtAsQifjUG9q4U9dgTHJM2mfk4uEPxc0+xuFdJ629QA=="
|
||||||
},
|
},
|
||||||
"chokidar": {
|
"chokidar": {
|
||||||
"version": "3.5.3",
|
"version": "3.5.3",
|
||||||
@ -2239,9 +2269,9 @@
|
|||||||
"integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg=="
|
"integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg=="
|
||||||
},
|
},
|
||||||
"daisyui": {
|
"daisyui": {
|
||||||
"version": "2.51.5",
|
"version": "2.52.0",
|
||||||
"resolved": "https://registry.npmjs.org/daisyui/-/daisyui-2.51.5.tgz",
|
"resolved": "https://registry.npmjs.org/daisyui/-/daisyui-2.52.0.tgz",
|
||||||
"integrity": "sha512-L05dRw0tasmz2Ha+10LhftEGLq4kaA8vRR/T0wDaXfHwqcgsf81jfXDJ6NlZ63Z7Rl1k3rj7UHs0l0p7CM3aYA==",
|
"integrity": "sha512-LQTA5/IVXAJHBMFoeaEMfd7/akAFPPcdQPR3O9fzzcFiczneJFM73CFPnScmW2sOgn/D83cvkP854ep2T9OfTg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"color": "^4.2",
|
"color": "^4.2",
|
||||||
"css-selector-tokenizer": "^0.8.0",
|
"css-selector-tokenizer": "^0.8.0",
|
||||||
@ -2275,9 +2305,9 @@
|
|||||||
"integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA=="
|
"integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA=="
|
||||||
},
|
},
|
||||||
"electron-to-chromium": {
|
"electron-to-chromium": {
|
||||||
"version": "1.4.369",
|
"version": "1.4.455",
|
||||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.369.tgz",
|
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.455.tgz",
|
||||||
"integrity": "sha512-LfxbHXdA/S+qyoTEA4EbhxGjrxx7WK2h6yb5K2v0UCOufUKX+VZaHbl3svlzZfv9sGseym/g3Ne4DpsgRULmqg=="
|
"integrity": "sha512-8tgdX0Odl24LtmLwxotpJCVjIndN559AvaOtd67u+2mo+IDsgsTF580NB+uuDCqsHw8yFg53l5+imFV9Fw3cbA=="
|
||||||
},
|
},
|
||||||
"esbuild": {
|
"esbuild": {
|
||||||
"version": "0.15.18",
|
"version": "0.15.18",
|
||||||
@ -2455,9 +2485,9 @@
|
|||||||
"integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw=="
|
"integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw=="
|
||||||
},
|
},
|
||||||
"fast-glob": {
|
"fast-glob": {
|
||||||
"version": "3.2.12",
|
"version": "3.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz",
|
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.0.tgz",
|
||||||
"integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==",
|
"integrity": "sha512-ChDuvbOypPuNjO8yIDf36x7BlZX1smcUMTTcyoIjycexOxd6DFsKsg21qVBzEmr3G7fUKIRy2/psii+CIUt7FA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@nodelib/fs.stat": "^2.0.2",
|
"@nodelib/fs.stat": "^2.0.2",
|
||||||
"@nodelib/fs.walk": "^1.2.3",
|
"@nodelib/fs.walk": "^1.2.3",
|
||||||
@ -2575,9 +2605,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"is-core-module": {
|
"is-core-module": {
|
||||||
"version": "2.12.0",
|
"version": "2.12.1",
|
||||||
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.0.tgz",
|
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz",
|
||||||
"integrity": "sha512-RECHCBCd/viahWmwj6enj19sKbHfJrddi/6cBDsNTKbNq0f7VeaUkBo60BqzvPqo/W54ChS62Z5qyun7cfOMqQ==",
|
"integrity": "sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"has": "^1.0.3"
|
"has": "^1.0.3"
|
||||||
}
|
}
|
||||||
@ -2601,9 +2631,9 @@
|
|||||||
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="
|
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="
|
||||||
},
|
},
|
||||||
"jiti": {
|
"jiti": {
|
||||||
"version": "1.18.2",
|
"version": "1.19.1",
|
||||||
"resolved": "https://registry.npmjs.org/jiti/-/jiti-1.18.2.tgz",
|
"resolved": "https://registry.npmjs.org/jiti/-/jiti-1.19.1.tgz",
|
||||||
"integrity": "sha512-QAdOptna2NYiSSpv0O/BwoHBSmz4YhpzJHyi+fnMRTXFjp7B8i/YG5Z8IfusxB1ufjcD2Sre1F3R+nX3fvy7gg=="
|
"integrity": "sha512-oVhqoRDaBXf7sjkll95LHVS6Myyyb1zaunVwk4Z0+WPSW4gjS0pl01zYKHScTuyEhQsFxV5L4DR5r+YqSyqyyg=="
|
||||||
},
|
},
|
||||||
"kleur": {
|
"kleur": {
|
||||||
"version": "4.1.5",
|
"version": "4.1.5",
|
||||||
@ -2674,9 +2704,9 @@
|
|||||||
"integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA=="
|
"integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA=="
|
||||||
},
|
},
|
||||||
"node-releases": {
|
"node-releases": {
|
||||||
"version": "2.0.10",
|
"version": "2.0.13",
|
||||||
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz",
|
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz",
|
||||||
"integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w=="
|
"integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ=="
|
||||||
},
|
},
|
||||||
"normalize-path": {
|
"normalize-path": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
@ -2732,14 +2762,14 @@
|
|||||||
"integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog=="
|
"integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog=="
|
||||||
},
|
},
|
||||||
"pirates": {
|
"pirates": {
|
||||||
"version": "4.0.5",
|
"version": "4.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz",
|
||||||
"integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ=="
|
"integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg=="
|
||||||
},
|
},
|
||||||
"postcss": {
|
"postcss": {
|
||||||
"version": "8.4.23",
|
"version": "8.4.25",
|
||||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.23.tgz",
|
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.25.tgz",
|
||||||
"integrity": "sha512-bQ3qMcpF6A/YjR55xtoTr0jGOlnPOKAIMdOWiv0EIT6HVPEaJiJB4NLljSbiHoC2RX7DN5Uvjtpbg1NPdwv1oA==",
|
"integrity": "sha512-7taJ/8t2av0Z+sQEvNzCkpDynl0tX3uJMCODi6nT3PfASC7dYCWV9aQ+uiCf+KBD4SEFcu+GvJdGdwzQ6OSjCw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"nanoid": "^3.3.6",
|
"nanoid": "^3.3.6",
|
||||||
"picocolors": "^1.0.0",
|
"picocolors": "^1.0.0",
|
||||||
@ -2747,9 +2777,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"postcss-import": {
|
"postcss-import": {
|
||||||
"version": "14.1.0",
|
"version": "15.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-14.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz",
|
||||||
"integrity": "sha512-flwI+Vgm4SElObFVPpTIT7SU7R3qk2L7PyduMcokiaVKuWv9d/U+Gm/QAd8NDLuykTWTkcrjOeD2Pp1rMeBTGw==",
|
"integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"postcss-value-parser": "^4.0.0",
|
"postcss-value-parser": "^4.0.0",
|
||||||
"read-cache": "^1.0.0",
|
"read-cache": "^1.0.0",
|
||||||
@ -2765,26 +2795,26 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"postcss-load-config": {
|
"postcss-load-config": {
|
||||||
"version": "3.1.4",
|
"version": "4.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.1.tgz",
|
||||||
"integrity": "sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==",
|
"integrity": "sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"lilconfig": "^2.0.5",
|
"lilconfig": "^2.0.5",
|
||||||
"yaml": "^1.10.2"
|
"yaml": "^2.1.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"postcss-nested": {
|
"postcss-nested": {
|
||||||
"version": "6.0.0",
|
"version": "6.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.1.tgz",
|
||||||
"integrity": "sha512-0DkamqrPcmkBDsLn+vQDIrtkSbNkv5AD/M322ySo9kqFkCIYklym2xEmWkwo+Y3/qZo34tzEPNUw4y7yMCdv5w==",
|
"integrity": "sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"postcss-selector-parser": "^6.0.10"
|
"postcss-selector-parser": "^6.0.11"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"postcss-selector-parser": {
|
"postcss-selector-parser": {
|
||||||
"version": "6.0.11",
|
"version": "6.0.13",
|
||||||
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.11.tgz",
|
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz",
|
||||||
"integrity": "sha512-zbARubNdogI9j7WY4nQJBiNqQf3sLS3wCP4WfOidu+p28LofJqDH1tcXypGrcmMHhDk2t9wGhCsYe/+szLTy1g==",
|
"integrity": "sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"cssesc": "^3.0.0",
|
"cssesc": "^3.0.0",
|
||||||
"util-deprecate": "^1.0.2"
|
"util-deprecate": "^1.0.2"
|
||||||
@ -2800,11 +2830,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
|
||||||
"integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="
|
"integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="
|
||||||
},
|
},
|
||||||
"quick-lru": {
|
|
||||||
"version": "5.1.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz",
|
|
||||||
"integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA=="
|
|
||||||
},
|
|
||||||
"read-cache": {
|
"read-cache": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
|
||||||
@ -2892,47 +2917,46 @@
|
|||||||
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="
|
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="
|
||||||
},
|
},
|
||||||
"svelte": {
|
"svelte": {
|
||||||
"version": "3.58.0",
|
"version": "3.59.2",
|
||||||
"resolved": "https://registry.npmjs.org/svelte/-/svelte-3.58.0.tgz",
|
"resolved": "https://registry.npmjs.org/svelte/-/svelte-3.59.2.tgz",
|
||||||
"integrity": "sha512-brIBNNB76mXFmU/Kerm4wFnkskBbluBDCjx/8TcpYRb298Yh2dztS2kQ6bhtjMcvUhd5ynClfwpz5h2gnzdQ1A==",
|
"integrity": "sha512-vzSyuGr3eEoAtT/A6bmajosJZIUWySzY2CzB3w2pgPvnkUjGqlDnsNnA0PMO+mMAhuyMul6C2uuZzY6ELSkzyA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"svelte-hmr": {
|
"svelte-hmr": {
|
||||||
"version": "0.15.1",
|
"version": "0.15.2",
|
||||||
"resolved": "https://registry.npmjs.org/svelte-hmr/-/svelte-hmr-0.15.1.tgz",
|
"resolved": "https://registry.npmjs.org/svelte-hmr/-/svelte-hmr-0.15.2.tgz",
|
||||||
"integrity": "sha512-BiKB4RZ8YSwRKCNVdNxK/GfY+r4Kjgp9jCLEy0DuqAKfmQtpL38cQK3afdpjw4sqSs4PLi3jIPJIFp259NkZtA==",
|
"integrity": "sha512-q/bAruCvFLwvNbeE1x3n37TYFb3mTBJ6TrCq6p2CoFbSTNhDE9oAtEfpy+wmc9So8AG0Tja+X0/mJzX9tSfvIg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {}
|
"requires": {}
|
||||||
},
|
},
|
||||||
"tailwindcss": {
|
"tailwindcss": {
|
||||||
"version": "3.3.1",
|
"version": "3.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.2.tgz",
|
||||||
"integrity": "sha512-Vkiouc41d4CEq0ujXl6oiGFQ7bA3WEhUZdTgXAhtKxSy49OmKs8rEfQmupsfF0IGW8fv2iQkp1EVUuapCFrZ9g==",
|
"integrity": "sha512-9jPkMiIBXvPc2KywkraqsUfbfj+dHDb+JPWtSJa9MLFdrPyazI7q6WX2sUrm7R9eVR7qqv3Pas7EvQFzxKnI6w==",
|
||||||
"requires": {
|
"requires": {
|
||||||
|
"@alloc/quick-lru": "^5.2.0",
|
||||||
"arg": "^5.0.2",
|
"arg": "^5.0.2",
|
||||||
"chokidar": "^3.5.3",
|
"chokidar": "^3.5.3",
|
||||||
"color-name": "^1.1.4",
|
|
||||||
"didyoumean": "^1.2.2",
|
"didyoumean": "^1.2.2",
|
||||||
"dlv": "^1.1.3",
|
"dlv": "^1.1.3",
|
||||||
"fast-glob": "^3.2.12",
|
"fast-glob": "^3.2.12",
|
||||||
"glob-parent": "^6.0.2",
|
"glob-parent": "^6.0.2",
|
||||||
"is-glob": "^4.0.3",
|
"is-glob": "^4.0.3",
|
||||||
"jiti": "^1.17.2",
|
"jiti": "^1.18.2",
|
||||||
"lilconfig": "^2.0.6",
|
"lilconfig": "^2.1.0",
|
||||||
"micromatch": "^4.0.5",
|
"micromatch": "^4.0.5",
|
||||||
"normalize-path": "^3.0.0",
|
"normalize-path": "^3.0.0",
|
||||||
"object-hash": "^3.0.0",
|
"object-hash": "^3.0.0",
|
||||||
"picocolors": "^1.0.0",
|
"picocolors": "^1.0.0",
|
||||||
"postcss": "^8.0.9",
|
"postcss": "^8.4.23",
|
||||||
"postcss-import": "^14.1.0",
|
"postcss-import": "^15.1.0",
|
||||||
"postcss-js": "^4.0.0",
|
"postcss-js": "^4.0.1",
|
||||||
"postcss-load-config": "^3.1.4",
|
"postcss-load-config": "^4.0.1",
|
||||||
"postcss-nested": "6.0.0",
|
"postcss-nested": "^6.0.1",
|
||||||
"postcss-selector-parser": "^6.0.11",
|
"postcss-selector-parser": "^6.0.11",
|
||||||
"postcss-value-parser": "^4.2.0",
|
"postcss-value-parser": "^4.2.0",
|
||||||
"quick-lru": "^5.1.1",
|
"resolve": "^1.22.2",
|
||||||
"resolve": "^1.22.1",
|
"sucrase": "^3.32.0"
|
||||||
"sucrase": "^3.29.0"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"thenify": {
|
"thenify": {
|
||||||
@ -2979,9 +3003,9 @@
|
|||||||
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
|
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
|
||||||
},
|
},
|
||||||
"vite": {
|
"vite": {
|
||||||
"version": "3.2.6",
|
"version": "3.2.7",
|
||||||
"resolved": "https://registry.npmjs.org/vite/-/vite-3.2.6.tgz",
|
"resolved": "https://registry.npmjs.org/vite/-/vite-3.2.7.tgz",
|
||||||
"integrity": "sha512-nTXTxYVvaQNLoW5BQ8PNNQ3lPia57gzsQU/Khv+JvzKPku8kNZL6NMUR/qwXhMG6E+g1idqEPanomJ+VZgixEg==",
|
"integrity": "sha512-29pdXjk49xAP0QBr0xXqu2s5jiQIXNvE/xwd0vUizYT2Hzqe4BksNNoWllFVXJf4eLZ+UlVQmXfB4lWrc+t18g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"esbuild": "^0.15.9",
|
"esbuild": "^0.15.9",
|
||||||
@ -3004,9 +3028,9 @@
|
|||||||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
|
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
|
||||||
},
|
},
|
||||||
"yaml": {
|
"yaml": {
|
||||||
"version": "1.10.2",
|
"version": "2.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
|
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.1.tgz",
|
||||||
"integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg=="
|
"integrity": "sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ=="
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "creddy",
|
"name": "creddy",
|
||||||
"version": "0.2.0",
|
"version": "0.2.3",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
"build": "vite build",
|
"build": "vite build",
|
||||||
|
1246
src-tauri/Cargo.lock
generated
1246
src-tauri/Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -1,14 +1,22 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "app"
|
name = "creddy"
|
||||||
version = "0.2.0"
|
version = "0.2.3"
|
||||||
description = "A Tauri App"
|
description = "A friendly AWS credentials manager"
|
||||||
authors = ["you"]
|
authors = ["Joseph Montanaro"]
|
||||||
license = ""
|
license = ""
|
||||||
repository = ""
|
repository = ""
|
||||||
default-run = "app"
|
default-run = "creddy"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
rust-version = "1.57"
|
rust-version = "1.57"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "creddy_cli"
|
||||||
|
path = "src/bin/creddy_cli.rs"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "creddy"
|
||||||
|
path = "src/main.rs"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
@ -17,7 +25,7 @@ tauri-build = { version = "1.0.4", features = [] }
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
tauri = { version = "1.2", features = ["dialog", "os-all", "system-tray"] }
|
tauri = { version = "1.2", features = ["dialog", "dialog-open", "os-all", "system-tray"] }
|
||||||
tauri-plugin-single-instance = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "dev" }
|
tauri-plugin-single-instance = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "dev" }
|
||||||
sodiumoxide = "0.2.7"
|
sodiumoxide = "0.2.7"
|
||||||
tokio = { version = ">=1.19", features = ["full"] }
|
tokio = { version = ">=1.19", features = ["full"] }
|
||||||
@ -36,6 +44,9 @@ auto-launch = "0.4.0"
|
|||||||
dirs = "5.0"
|
dirs = "5.0"
|
||||||
clap = { version = "3.2.23", features = ["derive"] }
|
clap = { version = "3.2.23", features = ["derive"] }
|
||||||
is-terminal = "0.4.7"
|
is-terminal = "0.4.7"
|
||||||
|
argon2 = { version = "0.5.0", features = ["std"] }
|
||||||
|
chacha20poly1305 = { version = "0.10.1", features = ["std"] }
|
||||||
|
which = "4.4.0"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
# by default Tauri runs in production mode
|
# by default Tauri runs in production mode
|
||||||
|
22
src-tauri/conf/cli.wxs
Normal file
22
src-tauri/conf/cli.wxs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
|
||||||
|
<Fragment>
|
||||||
|
|
||||||
|
<DirectoryRef Id="INSTALLDIR">
|
||||||
|
<!-- Create a subdirectory for the console binary so that we can add it to PATH -->
|
||||||
|
<Directory Id="BinDir" Name="bin">
|
||||||
|
<Component Id="CliBinary" Guid="b6358c8e-504f-41fd-b14b-38af821dcd04">
|
||||||
|
<!-- Same name as the main executable, so that it can be invoked as just "creddy" -->
|
||||||
|
<File Id="Bin_Cli" Source="..\..\creddy_cli.exe" Name="creddy.exe" KeyPath="yes"/>
|
||||||
|
</Component>
|
||||||
|
</Directory>
|
||||||
|
</DirectoryRef>
|
||||||
|
|
||||||
|
<DirectoryRef Id="TARGETDIR">
|
||||||
|
<Component Id="AddToPath" Guid="b5fdaf7e-94f2-4aad-9144-aa3a8edfa675">
|
||||||
|
<Environment Id="CreddyInstallDir" Action="set" Name="PATH" Part="last" Permanent="no" Value="[BinDir]" />
|
||||||
|
</Component>
|
||||||
|
</DirectoryRef>
|
||||||
|
|
||||||
|
</Fragment>
|
||||||
|
</Wix>
|
@ -42,6 +42,7 @@ pub fn run() -> tauri::Result<()> {
|
|||||||
ipc::save_credentials,
|
ipc::save_credentials,
|
||||||
ipc::get_config,
|
ipc::get_config,
|
||||||
ipc::save_config,
|
ipc::save_config,
|
||||||
|
ipc::launch_terminal,
|
||||||
])
|
])
|
||||||
.setup(|app| rt::block_on(setup(app)))
|
.setup(|app| rt::block_on(setup(app)))
|
||||||
.build(tauri::generate_context!())?
|
.build(tauri::generate_context!())?
|
||||||
@ -74,13 +75,16 @@ pub async fn connect_db() -> Result<SqlitePool, SetupError> {
|
|||||||
async fn setup(app: &mut App) -> Result<(), Box<dyn Error>> {
|
async fn setup(app: &mut App) -> Result<(), Box<dyn Error>> {
|
||||||
APP.set(app.handle()).unwrap();
|
APP.set(app.handle()).unwrap();
|
||||||
|
|
||||||
|
let is_first_launch = config::get_or_create_db_path()?.exists();
|
||||||
|
|
||||||
let pool = connect_db().await?;
|
let pool = connect_db().await?;
|
||||||
let conf = AppConfig::load(&pool).await?;
|
let conf = AppConfig::load(&pool).await?;
|
||||||
let session = Session::load(&pool).await?;
|
let session = Session::load(&pool).await?;
|
||||||
let srv = Server::new(conf.listen_addr, conf.listen_port, app.handle()).await?;
|
let srv = Server::new(conf.listen_addr, conf.listen_port, app.handle()).await?;
|
||||||
|
|
||||||
config::set_auto_launch(conf.start_on_login)?;
|
config::set_auto_launch(conf.start_on_login)?;
|
||||||
if !conf.start_minimized {
|
// if session is empty, this is probably the first launch, so don't autohide
|
||||||
|
if !conf.start_minimized || is_first_launch {
|
||||||
app.get_window("main")
|
app.get_window("main")
|
||||||
.ok_or(HandlerError::NoMainWindow)?
|
.ok_or(HandlerError::NoMainWindow)?
|
||||||
.show()?;
|
.show()?;
|
||||||
|
45
src-tauri/src/bin/creddy_cli.rs
Normal file
45
src-tauri/src/bin/creddy_cli.rs
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
// Windows isn't really amenable to having a single executable work as both a CLI and GUI app,
|
||||||
|
// so we just have a second binary for CLI usage
|
||||||
|
use creddy::{
|
||||||
|
cli,
|
||||||
|
errors::CliError,
|
||||||
|
};
|
||||||
|
use std::{
|
||||||
|
env,
|
||||||
|
process::{self, Command},
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let args = cli::parser().get_matches();
|
||||||
|
if let Some(true) = args.get_one::<bool>("help") {
|
||||||
|
cli::parser().print_help().unwrap(); // if we can't print help we can't print an error
|
||||||
|
process::exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
let res = match args.subcommand() {
|
||||||
|
None | Some(("run", _)) => launch_gui(),
|
||||||
|
Some(("show", m)) => cli::show(m),
|
||||||
|
Some(("exec", m)) => cli::exec(m),
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Err(e) = res {
|
||||||
|
eprintln!("Error: {e}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn launch_gui() -> Result<(), CliError> {
|
||||||
|
let mut path = env::current_exe()?;
|
||||||
|
path.pop(); // bin dir
|
||||||
|
|
||||||
|
// binaries are colocated in dev, but not in production
|
||||||
|
#[cfg(not(debug_assertions))]
|
||||||
|
path.pop(); // install dir
|
||||||
|
|
||||||
|
path.push("creddy.exe"); // exe in main install dir (aka gui exe)
|
||||||
|
|
||||||
|
Command::new(path).spawn()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
@ -1,3 +1,4 @@
|
|||||||
|
use std::ffi::OsString;
|
||||||
use std::process::Command as ChildCommand;
|
use std::process::Command as ChildCommand;
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
use std::os::unix::process::CommandExt;
|
use std::os::unix::process::CommandExt;
|
||||||
@ -89,12 +90,29 @@ pub fn exec(args: &ArgMatches) -> Result<(), CliError> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
cmd.exec().map_err(|e| ExecError::ExecutionFailed(e))?;
|
{
|
||||||
|
// cmd.exec() never returns if successful
|
||||||
|
let e = cmd.exec();
|
||||||
|
match e.kind() {
|
||||||
|
std::io::ErrorKind::NotFound => {
|
||||||
|
let name: OsString = cmd_name.into();
|
||||||
|
Err(ExecError::NotFound(name).into())
|
||||||
|
}
|
||||||
|
e => Err(ExecError::ExecutionFailed(e).into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
{
|
{
|
||||||
let mut child = cmd.spawn()
|
let mut child = match cmd.spawn() {
|
||||||
.map_err(|e| ExecError::ExecutionFailed(e))?;
|
Ok(c) => c,
|
||||||
|
Err(e) if e.kind() == std::io::ErrorKind::NotFound => {
|
||||||
|
let name: OsString = cmd_name.into();
|
||||||
|
return Err(ExecError::NotFound(name).into());
|
||||||
|
}
|
||||||
|
Err(e) => return Err(ExecError::ExecutionFailed(e).into()),
|
||||||
|
};
|
||||||
|
|
||||||
let status = child.wait()
|
let status = child.wait()
|
||||||
.map_err(|e| ExecError::ExecutionFailed(e))?;
|
.map_err(|e| ExecError::ExecutionFailed(e))?;
|
||||||
std::process::exit(status.code().unwrap_or(1));
|
std::process::exit(status.code().unwrap_or(1));
|
||||||
|
@ -9,6 +9,17 @@ use sqlx::SqlitePool;
|
|||||||
use crate::errors::*;
|
use crate::errors::*;
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
pub struct TermConfig {
|
||||||
|
pub name: String,
|
||||||
|
// we call it exec because it isn't always the actual path,
|
||||||
|
// in some cases it's just the name and relies on path-searching
|
||||||
|
// it's a string because it can come from the frontend as json
|
||||||
|
pub exec: String,
|
||||||
|
pub args: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
pub struct AppConfig {
|
pub struct AppConfig {
|
||||||
#[serde(default = "default_listen_addr")]
|
#[serde(default = "default_listen_addr")]
|
||||||
@ -21,6 +32,8 @@ pub struct AppConfig {
|
|||||||
pub start_minimized: bool,
|
pub start_minimized: bool,
|
||||||
#[serde(default = "default_start_on_login")]
|
#[serde(default = "default_start_on_login")]
|
||||||
pub start_on_login: bool,
|
pub start_on_login: bool,
|
||||||
|
#[serde(default = "default_term_config")]
|
||||||
|
pub terminal: TermConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -32,6 +45,7 @@ impl Default for AppConfig {
|
|||||||
rehide_ms: default_rehide_ms(),
|
rehide_ms: default_rehide_ms(),
|
||||||
start_minimized: default_start_minimized(),
|
start_minimized: default_start_minimized(),
|
||||||
start_on_login: default_start_on_login(),
|
start_on_login: default_start_on_login(),
|
||||||
|
terminal: default_term_config(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -116,6 +130,46 @@ fn default_listen_port() -> u16 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn default_term_config() -> TermConfig {
|
||||||
|
#[cfg(windows)]
|
||||||
|
{
|
||||||
|
let shell = if which::which("pwsh.exe").is_ok() {
|
||||||
|
"pwsh.exe".to_string()
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
"powershell.exe".to_string()
|
||||||
|
};
|
||||||
|
|
||||||
|
let (exec, args) = if cfg!(debug_assertions) {
|
||||||
|
("conhost.exe".to_string(), vec![shell.clone()])
|
||||||
|
} else {
|
||||||
|
(shell.clone(), vec![])
|
||||||
|
};
|
||||||
|
|
||||||
|
TermConfig { name: shell, exec, args }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
{
|
||||||
|
for bin in ["gnome-terminal", "konsole"] {
|
||||||
|
if let Ok(_) = which::which(bin) {
|
||||||
|
return TermConfig {
|
||||||
|
name: bin.into(),
|
||||||
|
exec: bin.into(),
|
||||||
|
args: vec![],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return TermConfig {
|
||||||
|
name: "gnome-terminal".into(),
|
||||||
|
exec: "gnome-terminal".into(),
|
||||||
|
args: vec![],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
fn default_listen_addr() -> Ipv4Addr { Ipv4Addr::LOCALHOST }
|
fn default_listen_addr() -> Ipv4Addr { Ipv4Addr::LOCALHOST }
|
||||||
fn default_rehide_ms() -> u64 { 1000 }
|
fn default_rehide_ms() -> u64 { 1000 }
|
||||||
// start minimized and on login only in production mode
|
// start minimized and on login only in production mode
|
||||||
|
@ -1,7 +1,25 @@
|
|||||||
use std::fmt::{self, Formatter};
|
use std::fmt::{self, Formatter};
|
||||||
use std::time::{SystemTime, UNIX_EPOCH};
|
use std::time::{SystemTime, UNIX_EPOCH};
|
||||||
|
|
||||||
use aws_smithy_types::date_time::{DateTime, Format};
|
use aws_smithy_types::date_time::{DateTime, Format};
|
||||||
|
use argon2::{
|
||||||
|
Argon2,
|
||||||
|
Algorithm,
|
||||||
|
Version,
|
||||||
|
ParamsBuilder,
|
||||||
|
password_hash::rand_core::{RngCore, OsRng},
|
||||||
|
};
|
||||||
|
use chacha20poly1305::{
|
||||||
|
XChaCha20Poly1305,
|
||||||
|
XNonce,
|
||||||
|
aead::{
|
||||||
|
Aead,
|
||||||
|
AeadCore,
|
||||||
|
KeyInit,
|
||||||
|
Error as AeadError,
|
||||||
|
generic_array::GenericArray,
|
||||||
|
},
|
||||||
|
};
|
||||||
use serde::{
|
use serde::{
|
||||||
Serialize,
|
Serialize,
|
||||||
Deserialize,
|
Deserialize,
|
||||||
@ -10,12 +28,7 @@ use serde::{
|
|||||||
};
|
};
|
||||||
use serde::de::{self, Visitor};
|
use serde::de::{self, Visitor};
|
||||||
use sqlx::SqlitePool;
|
use sqlx::SqlitePool;
|
||||||
use sodiumoxide::crypto::{
|
|
||||||
pwhash,
|
|
||||||
pwhash::Salt,
|
|
||||||
secretbox,
|
|
||||||
secretbox::{Nonce, Key}
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::errors::*;
|
use crate::errors::*;
|
||||||
|
|
||||||
@ -40,18 +53,17 @@ impl Session {
|
|||||||
None => {return Ok(Session::Empty);}
|
None => {return Ok(Session::Empty);}
|
||||||
};
|
};
|
||||||
|
|
||||||
let salt_buf: [u8; 32] = row.salt
|
let salt: [u8; 32] = row.salt
|
||||||
.try_into()
|
|
||||||
.map_err(|_e| SetupError::InvalidRecord)?;
|
|
||||||
let nonce_buf: [u8; 24] = row.nonce
|
|
||||||
.try_into()
|
.try_into()
|
||||||
.map_err(|_e| SetupError::InvalidRecord)?;
|
.map_err(|_e| SetupError::InvalidRecord)?;
|
||||||
|
let nonce = XNonce::from_exact_iter(row.nonce.into_iter())
|
||||||
|
.ok_or(SetupError::InvalidRecord)?;
|
||||||
|
|
||||||
let creds = LockedCredentials {
|
let creds = LockedCredentials {
|
||||||
access_key_id: row.access_key_id,
|
access_key_id: row.access_key_id,
|
||||||
secret_key_enc: row.secret_key_enc,
|
secret_key_enc: row.secret_key_enc,
|
||||||
salt: Salt(salt_buf),
|
salt,
|
||||||
nonce: Nonce(nonce_buf),
|
nonce,
|
||||||
};
|
};
|
||||||
Ok(Session::Locked(creds))
|
Ok(Session::Locked(creds))
|
||||||
}
|
}
|
||||||
@ -69,6 +81,16 @@ impl Session {
|
|||||||
Session::Empty => Err(GetSessionError::CredentialsEmpty),
|
Session::Empty => Err(GetSessionError::CredentialsEmpty),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn try_get(
|
||||||
|
&self
|
||||||
|
) -> Result<(&BaseCredentials, &SessionCredentials), GetCredentialsError> {
|
||||||
|
match self {
|
||||||
|
Self::Empty => Err(GetCredentialsError::Empty),
|
||||||
|
Self::Locked(_) => Err(GetCredentialsError::Locked),
|
||||||
|
Self::Unlocked{ ref base, ref session } => Ok((base, session))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -76,8 +98,8 @@ impl Session {
|
|||||||
pub struct LockedCredentials {
|
pub struct LockedCredentials {
|
||||||
pub access_key_id: String,
|
pub access_key_id: String,
|
||||||
pub secret_key_enc: Vec<u8>,
|
pub secret_key_enc: Vec<u8>,
|
||||||
pub salt: Salt,
|
pub salt: [u8; 32],
|
||||||
pub nonce: Nonce,
|
pub nonce: XNonce,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LockedCredentials {
|
impl LockedCredentials {
|
||||||
@ -88,8 +110,8 @@ impl LockedCredentials {
|
|||||||
)
|
)
|
||||||
.bind(&self.access_key_id)
|
.bind(&self.access_key_id)
|
||||||
.bind(&self.secret_key_enc)
|
.bind(&self.secret_key_enc)
|
||||||
.bind(&self.salt.0[0..])
|
.bind(&self.salt[..])
|
||||||
.bind(&self.nonce.0[0..])
|
.bind(&self.nonce[..])
|
||||||
.execute(pool)
|
.execute(pool)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
@ -97,11 +119,10 @@ impl LockedCredentials {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn decrypt(&self, passphrase: &str) -> Result<BaseCredentials, UnlockError> {
|
pub fn decrypt(&self, passphrase: &str) -> Result<BaseCredentials, UnlockError> {
|
||||||
let mut key_buf = [0; secretbox::KEYBYTES];
|
let crypto = Crypto::new(passphrase, &self.salt)
|
||||||
// pretty sure this only fails if we're out of memory
|
.map_err(|e| CryptoError::Argon2(e))?;
|
||||||
pwhash::derive_key_interactive(&mut key_buf, passphrase.as_bytes(), &self.salt).unwrap();
|
let decrypted = crypto.decrypt(&self.nonce, &self.secret_key_enc)
|
||||||
let decrypted = secretbox::open(&self.secret_key_enc, &self.nonce, &Key(key_buf))
|
.map_err(|e| CryptoError::Aead(e))?;
|
||||||
.map_err(|_| UnlockError::BadPassphrase)?;
|
|
||||||
let secret_access_key = String::from_utf8(decrypted)
|
let secret_access_key = String::from_utf8(decrypted)
|
||||||
.map_err(|_| UnlockError::InvalidUtf8)?;
|
.map_err(|_| UnlockError::InvalidUtf8)?;
|
||||||
|
|
||||||
@ -122,21 +143,18 @@ pub struct BaseCredentials {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl BaseCredentials {
|
impl BaseCredentials {
|
||||||
pub fn encrypt(&self, passphrase: &str) -> LockedCredentials {
|
pub fn encrypt(&self, passphrase: &str) -> Result<LockedCredentials, CryptoError> {
|
||||||
let salt = pwhash::gen_salt();
|
let salt = Crypto::salt();
|
||||||
let mut key_buf = [0; secretbox::KEYBYTES];
|
let crypto = Crypto::new(passphrase, &salt)?;
|
||||||
pwhash::derive_key_interactive(&mut key_buf, passphrase.as_bytes(), &salt).unwrap();
|
let (nonce, secret_key_enc) = crypto.encrypt(self.secret_access_key.as_bytes())?;
|
||||||
let key = Key(key_buf);
|
|
||||||
let nonce = secretbox::gen_nonce();
|
|
||||||
|
|
||||||
let secret_key_enc = secretbox::seal(self.secret_access_key.as_bytes(), &nonce, &key);
|
let locked = LockedCredentials {
|
||||||
|
|
||||||
LockedCredentials {
|
|
||||||
access_key_id: self.access_key_id.clone(),
|
access_key_id: self.access_key_id.clone(),
|
||||||
secret_key_enc,
|
secret_key_enc,
|
||||||
salt,
|
salt,
|
||||||
nonce,
|
nonce,
|
||||||
}
|
};
|
||||||
|
Ok(locked)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -241,4 +259,73 @@ fn deserialize_expiration<'de, D>(deserializer: D) -> Result<DateTime, D::Error>
|
|||||||
where D: Deserializer<'de>
|
where D: Deserializer<'de>
|
||||||
{
|
{
|
||||||
deserializer.deserialize_str(DateTimeVisitor)
|
deserializer.deserialize_str(DateTimeVisitor)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct Crypto {
|
||||||
|
cipher: XChaCha20Poly1305,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Crypto {
|
||||||
|
/// Argon2 params rationale:
|
||||||
|
///
|
||||||
|
/// m_cost is measured in KiB, so 128 * 1024 gives us 128MiB.
|
||||||
|
/// This should roughly double the memory usage of the application
|
||||||
|
/// while deriving the key.
|
||||||
|
///
|
||||||
|
/// p_cost is irrelevant since (at present) there isn't any parallelism
|
||||||
|
/// implemented, so we leave it at 1.
|
||||||
|
///
|
||||||
|
/// With the above m_cost, t_cost = 8 results in about 800ms to derive
|
||||||
|
/// a key on my (somewhat older) CPU. This is probably overkill, but
|
||||||
|
/// given that it should only have to happen ~once a day for most
|
||||||
|
/// usage, it should be acceptable.
|
||||||
|
#[cfg(not(debug_assertions))]
|
||||||
|
const MEM_COST: u32 = 128 * 1024;
|
||||||
|
#[cfg(not(debug_assertions))]
|
||||||
|
const TIME_COST: u32 = 8;
|
||||||
|
|
||||||
|
/// But since this takes a million years without optimizations,
|
||||||
|
/// we turn it way down in debug builds.
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
const MEM_COST: u32 = 48 * 1024;
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
const TIME_COST: u32 = 1;
|
||||||
|
|
||||||
|
|
||||||
|
fn new(passphrase: &str, salt: &[u8]) -> argon2::Result<Crypto> {
|
||||||
|
let params = ParamsBuilder::new()
|
||||||
|
.m_cost(Self::MEM_COST)
|
||||||
|
.p_cost(1)
|
||||||
|
.t_cost(Self::TIME_COST)
|
||||||
|
.build()
|
||||||
|
.unwrap(); // only errors if the given params are invalid
|
||||||
|
|
||||||
|
let hasher = Argon2::new(
|
||||||
|
Algorithm::Argon2id,
|
||||||
|
Version::V0x13,
|
||||||
|
params,
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut key = [0; 32];
|
||||||
|
hasher.hash_password_into(passphrase.as_bytes(), &salt, &mut key)?;
|
||||||
|
let cipher = XChaCha20Poly1305::new(GenericArray::from_slice(&key));
|
||||||
|
Ok(Crypto { cipher })
|
||||||
|
}
|
||||||
|
|
||||||
|
fn salt() -> [u8; 32] {
|
||||||
|
let mut salt = [0; 32];
|
||||||
|
OsRng.fill_bytes(&mut salt);
|
||||||
|
salt
|
||||||
|
}
|
||||||
|
|
||||||
|
fn encrypt(&self, data: &[u8]) -> Result<(XNonce, Vec<u8>), AeadError> {
|
||||||
|
let nonce = XChaCha20Poly1305::generate_nonce(&mut OsRng);
|
||||||
|
let ciphertext = self.cipher.encrypt(&nonce, data)?;
|
||||||
|
Ok((nonce, ciphertext))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn decrypt(&self, nonce: &XNonce, data: &[u8]) -> Result<Vec<u8>, AeadError> {
|
||||||
|
self.cipher.decrypt(nonce, data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::convert::AsRef;
|
use std::convert::AsRef;
|
||||||
|
use std::ffi::OsString;
|
||||||
use std::sync::mpsc;
|
use std::sync::mpsc;
|
||||||
use strum_macros::AsRefStr;
|
use strum_macros::AsRefStr;
|
||||||
|
|
||||||
@ -57,8 +58,12 @@ where
|
|||||||
E: Error,
|
E: Error,
|
||||||
M: serde::ser::SerializeMap,
|
M: serde::ser::SerializeMap,
|
||||||
{
|
{
|
||||||
let src = err.source().map(|s| format!("{s}"));
|
let msg = err.source().map(|s| format!("{s}"));
|
||||||
map.serialize_entry("source", &src)
|
map.serialize_entry("msg", &msg)?;
|
||||||
|
map.serialize_entry("code", &None::<&str>)?;
|
||||||
|
map.serialize_entry("source", &None::<&str>)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -164,8 +169,8 @@ pub enum UnlockError {
|
|||||||
NotLocked,
|
NotLocked,
|
||||||
#[error("No saved credentials were found")]
|
#[error("No saved credentials were found")]
|
||||||
NoCredentials,
|
NoCredentials,
|
||||||
#[error("Invalid passphrase")]
|
#[error(transparent)]
|
||||||
BadPassphrase,
|
Crypto(#[from] CryptoError),
|
||||||
#[error("Data was found to be corrupt after decryption")]
|
#[error("Data was found to be corrupt after decryption")]
|
||||||
InvalidUtf8, // Somehow we got invalid utf-8 even though decryption succeeded
|
InvalidUtf8, // Somehow we got invalid utf-8 even though decryption succeeded
|
||||||
#[error("Database error: {0}")]
|
#[error("Database error: {0}")]
|
||||||
@ -175,6 +180,15 @@ pub enum UnlockError {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Debug, ThisError, AsRefStr)]
|
||||||
|
pub enum CryptoError {
|
||||||
|
#[error(transparent)]
|
||||||
|
Argon2(#[from] argon2::Error),
|
||||||
|
#[error("Invalid passphrase")] // I think this is the only way decryption fails
|
||||||
|
Aead(#[from] chacha20poly1305::aead::Error),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Errors encountered while trying to figure out who's on the other end of a request
|
// Errors encountered while trying to figure out who's on the other end of a request
|
||||||
#[derive(Debug, ThisError, AsRefStr)]
|
#[derive(Debug, ThisError, AsRefStr)]
|
||||||
pub enum ClientInfoError {
|
pub enum ClientInfoError {
|
||||||
@ -203,22 +217,28 @@ pub enum RequestError {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Errors encountered while running a subprocess (via creddy exec)
|
|
||||||
#[derive(Debug, ThisError, AsRefStr)]
|
|
||||||
pub enum ExecError {
|
|
||||||
#[error("Please specify a command")]
|
|
||||||
NoCommand,
|
|
||||||
#[error("Failed to execute command: {0}")]
|
|
||||||
ExecutionFailed(#[from] std::io::Error)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, ThisError, AsRefStr)]
|
#[derive(Debug, ThisError, AsRefStr)]
|
||||||
pub enum CliError {
|
pub enum CliError {
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
Request(#[from] RequestError),
|
Request(#[from] RequestError),
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
Exec(#[from] ExecError),
|
Exec(#[from] ExecError),
|
||||||
|
#[error(transparent)]
|
||||||
|
Io(#[from] std::io::Error),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Errors encountered while trying to launch a child process
|
||||||
|
#[derive(Debug, ThisError, AsRefStr)]
|
||||||
|
pub enum ExecError {
|
||||||
|
#[error("Please specify a command")]
|
||||||
|
NoCommand,
|
||||||
|
#[error("Executable not found: {0:?}")]
|
||||||
|
NotFound(OsString),
|
||||||
|
#[error("Failed to execute command: {0}")]
|
||||||
|
ExecutionFailed(#[from] std::io::Error),
|
||||||
|
#[error(transparent)]
|
||||||
|
GetCredentials(#[from] GetCredentialsError),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -312,3 +332,18 @@ impl Serialize for UnlockError {
|
|||||||
map.end()
|
map.end()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl Serialize for ExecError {
|
||||||
|
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||||
|
let mut map = serializer.serialize_map(None)?;
|
||||||
|
map.serialize_entry("code", self.as_ref())?;
|
||||||
|
map.serialize_entry("msg", &format!("{self}"))?;
|
||||||
|
|
||||||
|
match self {
|
||||||
|
ExecError::GetCredentials(src) => map.serialize_entry("source", &src)?,
|
||||||
|
_ => serialize_upstream_err(self, &mut map)?,
|
||||||
|
}
|
||||||
|
map.end()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -6,6 +6,7 @@ use crate::credentials::{Session,BaseCredentials};
|
|||||||
use crate::errors::*;
|
use crate::errors::*;
|
||||||
use crate::clientinfo::Client;
|
use crate::clientinfo::Client;
|
||||||
use crate::state::AppState;
|
use crate::state::AppState;
|
||||||
|
use crate::terminal;
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
@ -78,3 +79,9 @@ pub async fn save_config(config: AppConfig, app_state: State<'_, AppState>) -> R
|
|||||||
.map_err(|e| format!("Error saving config: {e}"))?;
|
.map_err(|e| format!("Error saving config: {e}"))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
pub async fn launch_terminal(base: bool) -> Result<(), ExecError> {
|
||||||
|
terminal::launch(base).await
|
||||||
|
}
|
||||||
|
11
src-tauri/src/lib.rs
Normal file
11
src-tauri/src/lib.rs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
pub mod app;
|
||||||
|
pub mod cli;
|
||||||
|
mod config;
|
||||||
|
mod credentials;
|
||||||
|
pub mod errors;
|
||||||
|
mod clientinfo;
|
||||||
|
mod ipc;
|
||||||
|
mod state;
|
||||||
|
mod server;
|
||||||
|
mod terminal;
|
||||||
|
mod tray;
|
@ -3,20 +3,11 @@
|
|||||||
windows_subsystem = "windows"
|
windows_subsystem = "windows"
|
||||||
)]
|
)]
|
||||||
|
|
||||||
|
use creddy::{
|
||||||
mod app;
|
app,
|
||||||
mod cli;
|
cli,
|
||||||
mod config;
|
errors::ErrorPopup,
|
||||||
mod credentials;
|
};
|
||||||
mod errors;
|
|
||||||
mod clientinfo;
|
|
||||||
mod ipc;
|
|
||||||
mod state;
|
|
||||||
mod server;
|
|
||||||
mod tray;
|
|
||||||
|
|
||||||
|
|
||||||
use crate::errors::ErrorPopup;
|
|
||||||
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
@ -48,7 +48,7 @@ impl AppState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn new_creds(&self, base_creds: BaseCredentials, passphrase: &str) -> Result<(), UnlockError> {
|
pub async fn new_creds(&self, base_creds: BaseCredentials, passphrase: &str) -> Result<(), UnlockError> {
|
||||||
let locked = base_creds.encrypt(passphrase);
|
let locked = base_creds.encrypt(passphrase)?;
|
||||||
// do this first so that if it fails we don't save bad credentials
|
// do this first so that if it fails we don't save bad credentials
|
||||||
self.new_session(base_creds).await?;
|
self.new_session(base_creds).await?;
|
||||||
locked.save(&self.pool).await?;
|
locked.save(&self.pool).await?;
|
||||||
@ -142,21 +142,15 @@ impl AppState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn serialize_base_creds(&self) -> Result<String, GetCredentialsError> {
|
pub async fn serialize_base_creds(&self) -> Result<String, GetCredentialsError> {
|
||||||
let session = self.session.read().await;
|
let app_session = self.session.read().await;
|
||||||
match *session {
|
let (base, _session) = app_session.try_get()?;
|
||||||
Session::Unlocked{ref base, ..} => Ok(serde_json::to_string(base).unwrap()),
|
Ok(serde_json::to_string(base).unwrap())
|
||||||
Session::Locked(_) => Err(GetCredentialsError::Locked),
|
|
||||||
Session::Empty => Err(GetCredentialsError::Empty),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn serialize_session_creds(&self) -> Result<String, GetCredentialsError> {
|
pub async fn serialize_session_creds(&self) -> Result<String, GetCredentialsError> {
|
||||||
let session = self.session.read().await;
|
let app_session = self.session.read().await;
|
||||||
match *session {
|
let (_bsae, session) = app_session.try_get()?;
|
||||||
Session::Unlocked{ref session, ..} => Ok(serde_json::to_string(session).unwrap()),
|
Ok(serde_json::to_string(session).unwrap())
|
||||||
Session::Locked(_) => Err(GetCredentialsError::Locked),
|
|
||||||
Session::Empty => Err(GetCredentialsError::Empty),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn new_session(&self, base: BaseCredentials) -> Result<(), GetSessionError> {
|
async fn new_session(&self, base: BaseCredentials) -> Result<(), GetSessionError> {
|
||||||
|
43
src-tauri/src/terminal.rs
Normal file
43
src-tauri/src/terminal.rs
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
use std::process::Command;
|
||||||
|
|
||||||
|
use tauri::Manager;
|
||||||
|
|
||||||
|
use crate::app::APP;
|
||||||
|
use crate::errors::*;
|
||||||
|
use crate::state::AppState;
|
||||||
|
|
||||||
|
|
||||||
|
pub async fn launch(use_base: bool) -> Result<(), ExecError> {
|
||||||
|
let state = APP.get().unwrap().state::<AppState>();
|
||||||
|
// do all this in a block so we don't hold the lock any longer than necessary
|
||||||
|
let mut cmd = {
|
||||||
|
let config = state.config.read().await;
|
||||||
|
let mut cmd = Command::new(&config.terminal.exec);
|
||||||
|
cmd.args(&config.terminal.args);
|
||||||
|
cmd
|
||||||
|
};
|
||||||
|
|
||||||
|
// similarly
|
||||||
|
{
|
||||||
|
let state = APP.get().unwrap().state::<AppState>();
|
||||||
|
let app_session = state.session.read().await;
|
||||||
|
let (base_creds, session_creds) = app_session.try_get()?;
|
||||||
|
if use_base {
|
||||||
|
cmd.env("AWS_ACCESS_KEY_ID", &base_creds.access_key_id);
|
||||||
|
cmd.env("AWS_SECRET_ACCESS_KEY", &base_creds.secret_access_key);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
cmd.env("AWS_ACCESS_KEY_ID", &session_creds.access_key_id);
|
||||||
|
cmd.env("AWS_SECRET_ACCESS_KEY", &session_creds.secret_access_key);
|
||||||
|
cmd.env("AWS_SESSION_TOKEN", &session_creds.token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
match cmd.spawn() {
|
||||||
|
Ok(_) => Ok(()),
|
||||||
|
Err(e) if std::io::ErrorKind::NotFound == e.kind() => {
|
||||||
|
Err(ExecError::NotFound(cmd.get_program().to_owned()))
|
||||||
|
},
|
||||||
|
Err(e) => Err(e.into()),
|
||||||
|
}
|
||||||
|
}
|
@ -8,11 +8,12 @@
|
|||||||
},
|
},
|
||||||
"package": {
|
"package": {
|
||||||
"productName": "creddy",
|
"productName": "creddy",
|
||||||
"version": "0.2.0"
|
"version": "0.2.3"
|
||||||
},
|
},
|
||||||
"tauri": {
|
"tauri": {
|
||||||
"allowlist": {
|
"allowlist": {
|
||||||
"os": {"all": true}
|
"os": {"all": true},
|
||||||
|
"dialog": {"open": true}
|
||||||
},
|
},
|
||||||
"bundle": {
|
"bundle": {
|
||||||
"active": true,
|
"active": true,
|
||||||
@ -44,7 +45,11 @@
|
|||||||
"windows": {
|
"windows": {
|
||||||
"certificateThumbprint": null,
|
"certificateThumbprint": null,
|
||||||
"digestAlgorithm": "sha256",
|
"digestAlgorithm": "sha256",
|
||||||
"timestampUrl": ""
|
"timestampUrl": "",
|
||||||
|
"wix": {
|
||||||
|
"fragmentPaths": ["conf/cli.wxs"],
|
||||||
|
"componentRefs": ["CliBinary", "AddToPath"]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"security": {
|
"security": {
|
||||||
|
@ -15,7 +15,6 @@ invoke('get_config').then(config => $appState.config = config);
|
|||||||
listen('credentials-request', (tauriEvent) => {
|
listen('credentials-request', (tauriEvent) => {
|
||||||
$appState.pendingRequests.put(tauriEvent.payload);
|
$appState.pendingRequests.put(tauriEvent.payload);
|
||||||
});
|
});
|
||||||
window.state = $appState;
|
|
||||||
|
|
||||||
acceptRequest();
|
acceptRequest();
|
||||||
</script>
|
</script>
|
||||||
|
113
src/ui/Spinner.svelte
Normal file
113
src/ui/Spinner.svelte
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
<script>
|
||||||
|
export let color = 'base-content';
|
||||||
|
export let thickness = '2px';
|
||||||
|
let classes = '';
|
||||||
|
export { classes as class };
|
||||||
|
|
||||||
|
const colorVars = {
|
||||||
|
'primary': 'p',
|
||||||
|
'primary-focus': 'pf',
|
||||||
|
'primary-content': 'pc',
|
||||||
|
'secondary': 's',
|
||||||
|
'secondary-focus': 'sf',
|
||||||
|
'secondary-content': 'sc',
|
||||||
|
'accent': 'a',
|
||||||
|
'accent-focus': 'af',
|
||||||
|
'accent-content': 'ac',
|
||||||
|
'neutral': 'n',
|
||||||
|
'neutral-focus': 'nf',
|
||||||
|
'neutral-content': 'nc',
|
||||||
|
'base-100': 'b1',
|
||||||
|
'base-200': 'b2',
|
||||||
|
'base-300': 'b3',
|
||||||
|
'base-content': 'bc',
|
||||||
|
'info': 'in',
|
||||||
|
'info-content': 'inc',
|
||||||
|
'success': 'su',
|
||||||
|
'success-content': 'suc',
|
||||||
|
'warning': 'wa',
|
||||||
|
'warning-content': 'wac',
|
||||||
|
'error': 'er',
|
||||||
|
'error-content': 'erc',
|
||||||
|
}
|
||||||
|
|
||||||
|
let arcStyle = `border-width: ${thickness};`;
|
||||||
|
arcStyle += `border-color: hsl(var(--${colorVars[color]})) transparent transparent transparent;`;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
#spinner {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
animation: spin;
|
||||||
|
animation-duration: 1.5s;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes spin {
|
||||||
|
50% { transform: rotate(225deg); }
|
||||||
|
100% { transform: rotate(360deg); }
|
||||||
|
}
|
||||||
|
|
||||||
|
.arc {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
border-radius: 9999px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.arc-top {
|
||||||
|
transform: rotate(-45deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.arc-right {
|
||||||
|
animation: spin-right;
|
||||||
|
animation-duration: 3s;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.arc-bottom {
|
||||||
|
animation: spin-bottom;
|
||||||
|
animation-duration: 3s;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.arc-left {
|
||||||
|
animation: spin-left;
|
||||||
|
animation-duration: 3s;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes spin-top {
|
||||||
|
0% { transform: rotate(-45deg); }
|
||||||
|
50% { transform: rotate(315deg); }
|
||||||
|
100% { transform: rotate(-45deg); }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes spin-right {
|
||||||
|
0% { transform: rotate(45deg); }
|
||||||
|
50% { transform: rotate(315deg); }
|
||||||
|
100% { transform: rotate(405deg); }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes spin-bottom {
|
||||||
|
0% { transform: rotate(135deg); }
|
||||||
|
50% { transform: rotate(315deg); }
|
||||||
|
100% { transform: rotate(495deg); }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes spin-left {
|
||||||
|
0% { transform: rotate(225deg); }
|
||||||
|
50% { transform: rotate(315deg); }
|
||||||
|
100% { transform: rotate(585deg); }
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
|
||||||
|
<div id="spinner" class="w-6 h-6 {classes}">
|
||||||
|
<div class="arc arc-top w-full h-full" style={arcStyle}></div>
|
||||||
|
<div class="arc arc-right w-full h-full" style={arcStyle}></div>
|
||||||
|
<div class="arc arc-bottom w-full h-full" style={arcStyle}></div>
|
||||||
|
<div class="arc arc-left w-full h-full" style={arcStyle}></div>
|
||||||
|
</div>
|
28
src/ui/settings/FileSetting.svelte
Normal file
28
src/ui/settings/FileSetting.svelte
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<script>
|
||||||
|
import { createEventDispatcher } from 'svelte';
|
||||||
|
import { open } from '@tauri-apps/api/dialog';
|
||||||
|
import Setting from './Setting.svelte';
|
||||||
|
|
||||||
|
export let title;
|
||||||
|
export let divider = true;
|
||||||
|
export let value;
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<Setting {title} {divider}>
|
||||||
|
<div slot="input">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="input input-sm input-bordered grow text-right"
|
||||||
|
bind:value
|
||||||
|
on:change={() => dispatch('update', {value})}
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
class="btn btn-sm btn-primary"
|
||||||
|
on:click={async () => value = await open()}
|
||||||
|
>Browse</button>
|
||||||
|
</div>
|
||||||
|
<slot name="description" slot="description"></slot>
|
||||||
|
</Setting>
|
@ -4,6 +4,7 @@
|
|||||||
import Setting from './Setting.svelte';
|
import Setting from './Setting.svelte';
|
||||||
|
|
||||||
export let title;
|
export let title;
|
||||||
|
export let divider = true;
|
||||||
export let value;
|
export let value;
|
||||||
export let unit = '';
|
export let unit = '';
|
||||||
export let min = null;
|
export let min = null;
|
||||||
@ -59,7 +60,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
<Setting {title}>
|
<Setting {title} {divider}>
|
||||||
<div slot="input">
|
<div slot="input">
|
||||||
{#if unit}
|
{#if unit}
|
||||||
<span class="mr-2">{unit}:</span>
|
<span class="mr-2">{unit}:</span>
|
||||||
|
@ -3,12 +3,15 @@
|
|||||||
import ErrorAlert from '../ErrorAlert.svelte';
|
import ErrorAlert from '../ErrorAlert.svelte';
|
||||||
|
|
||||||
export let title;
|
export let title;
|
||||||
|
export let divider = true;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
<div class="divider"></div>
|
{#if divider}
|
||||||
<div class="flex justify-between">
|
<div class="divider"></div>
|
||||||
<h3 class="text-lg font-bold">{title}</h3>
|
{/if}
|
||||||
|
<div class="flex flex-wrap justify-between gap-y-4">
|
||||||
|
<h3 class="text-lg font-bold shrink-0">{title}</h3>
|
||||||
<slot name="input"></slot>
|
<slot name="input"></slot>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
23
src/ui/settings/TextSetting.svelte
Normal file
23
src/ui/settings/TextSetting.svelte
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<script>
|
||||||
|
import { createEventDispatcher } from 'svelte';
|
||||||
|
import Setting from './Setting.svelte';
|
||||||
|
|
||||||
|
export let title;
|
||||||
|
export let divider = true;
|
||||||
|
export let value;
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<Setting {title} {divider}>
|
||||||
|
<div slot="input">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="input input-sm input-bordered grow text-right"
|
||||||
|
bind:value
|
||||||
|
on:change={() => dispatch('update', {value})}
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<slot name="description" slot="description"></slot>
|
||||||
|
</Setting>
|
@ -4,13 +4,14 @@
|
|||||||
import Setting from './Setting.svelte';
|
import Setting from './Setting.svelte';
|
||||||
|
|
||||||
export let title;
|
export let title;
|
||||||
|
export let divider = true; // passed through to Setting
|
||||||
export let value;
|
export let value;
|
||||||
|
|
||||||
const dispatch = createEventDispatcher();
|
const dispatch = createEventDispatcher();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
<Setting {title}>
|
<Setting {title} {divider}>
|
||||||
<input
|
<input
|
||||||
slot="input"
|
slot="input"
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
export { default as Setting } from './Setting.svelte';
|
export { default as Setting } from './Setting.svelte';
|
||||||
export { default as ToggleSetting } from './ToggleSetting.svelte';
|
export { default as ToggleSetting } from './ToggleSetting.svelte';
|
||||||
export { default as NumericSetting } from './NumericSetting.svelte';
|
export { default as NumericSetting } from './NumericSetting.svelte';
|
||||||
|
export { default as FileSetting } from './FileSetting.svelte';
|
||||||
|
export { default as TextSetting } from './TextSetting.svelte';
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
import { navigate } from '../lib/routing.js';
|
import { navigate } from '../lib/routing.js';
|
||||||
import Link from '../ui/Link.svelte';
|
import Link from '../ui/Link.svelte';
|
||||||
import ErrorAlert from '../ui/ErrorAlert.svelte';
|
import ErrorAlert from '../ui/ErrorAlert.svelte';
|
||||||
|
import Spinner from '../ui/Spinner.svelte';
|
||||||
|
|
||||||
|
|
||||||
let errorMsg = null;
|
let errorMsg = null;
|
||||||
@ -19,6 +20,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let saving = false;
|
||||||
async function save() {
|
async function save() {
|
||||||
if (passphrase !== confirmPassphrase) {
|
if (passphrase !== confirmPassphrase) {
|
||||||
alert.shake();
|
alert.shake();
|
||||||
@ -27,6 +29,7 @@
|
|||||||
|
|
||||||
let credentials = {AccessKeyId, SecretAccessKey};
|
let credentials = {AccessKeyId, SecretAccessKey};
|
||||||
try {
|
try {
|
||||||
|
saving = true;
|
||||||
await invoke('save_credentials', {credentials, passphrase});
|
await invoke('save_credentials', {credentials, passphrase});
|
||||||
if ($appState.currentRequest) {
|
if ($appState.currentRequest) {
|
||||||
navigate('Approve');
|
navigate('Approve');
|
||||||
@ -36,17 +39,21 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
if (e.code === "GetSession") {
|
window.error = e;
|
||||||
let root = getRootCause(e);
|
const root = getRootCause(e);
|
||||||
|
if (e.code === 'GetSession' && root.code) {
|
||||||
errorMsg = `Error response from AWS (${root.code}): ${root.msg}`;
|
errorMsg = `Error response from AWS (${root.code}): ${root.msg}`;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
errorMsg = e.msg;
|
errorMsg = e.msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if the alert already existed, shake it
|
||||||
if (alert) {
|
if (alert) {
|
||||||
alert.shake();
|
alert.shake();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
saving = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
@ -65,7 +72,13 @@
|
|||||||
<input type="password" placeholder="Passphrase" bind:value="{passphrase}" class="input input-bordered" />
|
<input type="password" placeholder="Passphrase" bind:value="{passphrase}" class="input input-bordered" />
|
||||||
<input type="password" placeholder="Re-enter passphrase" bind:value={confirmPassphrase} class="input input-bordered" on:change={confirm} />
|
<input type="password" placeholder="Re-enter passphrase" bind:value={confirmPassphrase} class="input input-bordered" on:change={confirm} />
|
||||||
|
|
||||||
<input type="submit" class="btn btn-primary" />
|
<button type="submit" class="btn btn-primary">
|
||||||
|
{#if saving}
|
||||||
|
<Spinner class="w-5 h-5" color="primary-content" thickness="2px"/>
|
||||||
|
{:else}
|
||||||
|
Submit
|
||||||
|
{/if}
|
||||||
|
</button>
|
||||||
<Link target="Home" hotkey="Escape">
|
<Link target="Home" hotkey="Escape">
|
||||||
<button class="btn btn-sm btn-outline w-full">Cancel</button>
|
<button class="btn btn-sm btn-outline w-full">Cancel</button>
|
||||||
</Link>
|
</Link>
|
||||||
|
@ -10,13 +10,11 @@
|
|||||||
|
|
||||||
import vaultDoorSvg from '../assets/vault_door.svg?raw';
|
import vaultDoorSvg from '../assets/vault_door.svg?raw';
|
||||||
|
|
||||||
|
let launchBase = false;
|
||||||
// onMount(async () => {
|
function launchTerminal() {
|
||||||
// // will block until a request comes in
|
invoke('launch_terminal', {base: launchBase});
|
||||||
// let req = await $appState.pendingRequests.get();
|
launchBase = false;
|
||||||
// $appState.currentRequest = req;
|
}
|
||||||
// navigate('Approve');
|
|
||||||
// });
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
@ -25,25 +23,32 @@
|
|||||||
</Nav>
|
</Nav>
|
||||||
|
|
||||||
<div class="flex flex-col h-screen items-center justify-center p-4 space-y-4">
|
<div class="flex flex-col h-screen items-center justify-center p-4 space-y-4">
|
||||||
{#await invoke('get_session_status') then status}
|
<div class="flex flex-col items-center space-y-4">
|
||||||
{#if status === 'locked'}
|
{@html vaultDoorSvg}
|
||||||
|
{#await invoke('get_session_status') then status}
|
||||||
|
{#if status === 'locked'}
|
||||||
|
|
||||||
{@html vaultDoorSvg}
|
<h2 class="text-2xl font-bold">Creddy is locked</h2>
|
||||||
<h2 class="text-2xl font-bold">Creddy is locked</h2>
|
<Link target="Unlock" hotkey="Enter" class="w-64">
|
||||||
<Link target="Unlock" hotkey="Enter" class="w-64">
|
<button class="btn btn-primary w-full">Unlock</button>
|
||||||
<button class="btn btn-primary w-full">Unlock</button>
|
</Link>
|
||||||
</Link>
|
|
||||||
|
|
||||||
{:else if status === 'unlocked'}
|
{:else if status === 'unlocked'}
|
||||||
{@html vaultDoorSvg}
|
<h2 class="text-2xl font-bold">Waiting for requests</h2>
|
||||||
<h2 class="text-2xl font-bold">Waiting for requests</h2>
|
<button class="btn btn-primary w-full" on:click={launchTerminal}>
|
||||||
|
Launch Terminal
|
||||||
|
</button>
|
||||||
|
<label class="label cursor-pointer flex items-center space-x-2">
|
||||||
|
<input type="checkbox" class="checkbox checkbox-sm" bind:checked={launchBase}>
|
||||||
|
<span class="label-text">Launch with base credentials</span>
|
||||||
|
</label>
|
||||||
|
|
||||||
{:else if status === 'empty'}
|
{:else if status === 'empty'}
|
||||||
{@html vaultDoorSvg}
|
<h2 class="text-2xl font-bold">No credentials found</h2>
|
||||||
<h2 class="text-2xl font-bold">No credentials found</h2>
|
<Link target="EnterCredentials" hotkey="Enter" class="w-64">
|
||||||
<Link target="EnterCredentials" hotkey="Enter" class="w-64">
|
<button class="btn btn-primary w-full">Enter Credentials</button>
|
||||||
<button class="btn btn-primary w-full">Enter Credentials</button>
|
</Link>
|
||||||
</Link>
|
{/if}
|
||||||
{/if}
|
{/await}
|
||||||
{/await}
|
</div>
|
||||||
</div>
|
</div>
|
@ -6,7 +6,7 @@
|
|||||||
import Nav from '../ui/Nav.svelte';
|
import Nav from '../ui/Nav.svelte';
|
||||||
import Link from '../ui/Link.svelte';
|
import Link from '../ui/Link.svelte';
|
||||||
import ErrorAlert from '../ui/ErrorAlert.svelte';
|
import ErrorAlert from '../ui/ErrorAlert.svelte';
|
||||||
import { Setting, ToggleSetting, NumericSetting } from '../ui/settings';
|
import { Setting, ToggleSetting, NumericSetting, FileSetting, TextSetting } from '../ui/settings';
|
||||||
|
|
||||||
import { fly } from 'svelte/transition';
|
import { fly } from 'svelte/transition';
|
||||||
import { backInOut } from 'svelte/easing';
|
import { backInOut } from 'svelte/easing';
|
||||||
@ -25,18 +25,25 @@
|
|||||||
|
|
||||||
let osType = '';
|
let osType = '';
|
||||||
type().then(t => osType = t);
|
type().then(t => osType = t);
|
||||||
|
|
||||||
|
console.log($appState.config.terminal);
|
||||||
|
window.term = $appState.config.terminal;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
<Nav>
|
<Nav>
|
||||||
<h2 slot="title" class="text-2xl font-bold">Settings</h2>
|
<h1 slot="title" class="text-2xl font-bold">Settings</h1>
|
||||||
</Nav>
|
</Nav>
|
||||||
|
|
||||||
{#await invoke('get_config') then config}
|
{#await invoke('get_config') then config}
|
||||||
<div class="max-w-md mx-auto mt-1.5 p-4">
|
<div class="max-w-lg mx-auto mt-1.5 p-4">
|
||||||
<!-- <h2 class="text-2xl font-bold text-center">Settings</h2> -->
|
<!-- <h2 class="text-2xl font-bold text-center">Settings</h2> -->
|
||||||
|
|
||||||
<ToggleSetting title="Start on login" bind:value={$appState.config.start_on_login} on:update={save}>
|
<div class="divider mt-0 mb-8">
|
||||||
|
<h2 class="text-xl font-bold">General</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ToggleSetting title="Start on login" divider={false} bind:value={$appState.config.start_on_login} on:update={save}>
|
||||||
<svelte:fragment slot="description">
|
<svelte:fragment slot="description">
|
||||||
Start Creddy when you log in to your computer.
|
Start Creddy when you log in to your computer.
|
||||||
</svelte:fragment>
|
</svelte:fragment>
|
||||||
@ -76,6 +83,21 @@
|
|||||||
Update or re-enter your encrypted credentials.
|
Update or re-enter your encrypted credentials.
|
||||||
</svelte:fragment>
|
</svelte:fragment>
|
||||||
</Setting>
|
</Setting>
|
||||||
|
|
||||||
|
<div class="divider mt-10 mb-8">
|
||||||
|
<h2 class="text-xl font-bold">Terminal</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<FileSetting
|
||||||
|
title="Emulator"
|
||||||
|
divider={false}
|
||||||
|
bind:value={$appState.config.terminal.exec}
|
||||||
|
on:update={save}
|
||||||
|
>
|
||||||
|
<svelte:fragment slot="description">
|
||||||
|
Choose your preferred terminal emulator (e.g. <code>gnome-terminal</code>, <code>wt.exe</code>.) May be an absolute path or an executable discoverable on <code>$PATH</code>.
|
||||||
|
</svelte:fragment>
|
||||||
|
</FileSetting>
|
||||||
</div>
|
</div>
|
||||||
{/await}
|
{/await}
|
||||||
|
|
||||||
|
@ -7,12 +7,14 @@
|
|||||||
import { getRootCause } from '../lib/errors.js';
|
import { getRootCause } from '../lib/errors.js';
|
||||||
import ErrorAlert from '../ui/ErrorAlert.svelte';
|
import ErrorAlert from '../ui/ErrorAlert.svelte';
|
||||||
import Link from '../ui/Link.svelte';
|
import Link from '../ui/Link.svelte';
|
||||||
|
import Spinner from '../ui/Spinner.svelte';
|
||||||
|
|
||||||
|
|
||||||
let errorMsg = null;
|
let errorMsg = null;
|
||||||
let alert;
|
let alert;
|
||||||
let passphrase = '';
|
let passphrase = '';
|
||||||
let loadTime = 0;
|
let loadTime = 0;
|
||||||
|
let saving = false;
|
||||||
async function unlock() {
|
async function unlock() {
|
||||||
// The hotkey for navigating here from homepage is Enter, which also
|
// The hotkey for navigating here from homepage is Enter, which also
|
||||||
// happens to trigger the form submit event
|
// happens to trigger the form submit event
|
||||||
@ -21,6 +23,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
saving = true;
|
||||||
let r = await invoke('unlock', {passphrase});
|
let r = await invoke('unlock', {passphrase});
|
||||||
$appState.credentialStatus = 'unlocked';
|
$appState.credentialStatus = 'unlocked';
|
||||||
if ($appState.currentRequest) {
|
if ($appState.currentRequest) {
|
||||||
@ -31,18 +34,20 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
window.error = e;
|
const root = getRootCause(e);
|
||||||
if (e.code === 'GetSession') {
|
if (e.code === 'GetSession' && root.code) {
|
||||||
let root = getRootCause(e);
|
|
||||||
errorMsg = `Error response from AWS (${root.code}): ${root.msg}`;
|
errorMsg = `Error response from AWS (${root.code}): ${root.msg}`;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
errorMsg = e.msg;
|
errorMsg = e.msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if the alert already existed, shake it
|
||||||
if (alert) {
|
if (alert) {
|
||||||
alert.shake();
|
alert.shake();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
saving = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,7 +67,14 @@
|
|||||||
<!-- svelte-ignore a11y-autofocus -->
|
<!-- svelte-ignore a11y-autofocus -->
|
||||||
<input autofocus name="password" type="password" placeholder="correct horse battery staple" bind:value="{passphrase}" class="input input-bordered" />
|
<input autofocus name="password" type="password" placeholder="correct horse battery staple" bind:value="{passphrase}" class="input input-bordered" />
|
||||||
|
|
||||||
<input type="submit" class="btn btn-primary" />
|
<button type="submit" class="btn btn-primary">
|
||||||
|
{#if saving}
|
||||||
|
<Spinner class="w-5 h-5" color="primary-content" thickness="2px"/>
|
||||||
|
{:else}
|
||||||
|
Submit
|
||||||
|
{/if}
|
||||||
|
</button>
|
||||||
|
|
||||||
<Link target="Home" hotkey="Escape">
|
<Link target="Home" hotkey="Escape">
|
||||||
<button class="btn btn-outline btn-sm w-full">Cancel</button>
|
<button class="btn btn-outline btn-sm w-full">Cancel</button>
|
||||||
</Link>
|
</Link>
|
||||||
|
Reference in New Issue
Block a user