Compare commits
1
Commits
v0.2.3
..
a8aafa1519
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a8aafa1519 |
No files matched your search
@@ -5,4 +5,3 @@ src-tauri/target/
|
|||||||
|
|
||||||
# just in case
|
# just in case
|
||||||
credentials*
|
credentials*
|
||||||
!credentials.rs
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
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.
|
|
||||||
Generated
+258
-282
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "creddy",
|
"name": "creddy",
|
||||||
"version": "0.2.2",
|
"version": "0.1.0",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "creddy",
|
"name": "creddy",
|
||||||
"version": "0.2.2",
|
"version": "0.1.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tauri-apps/api": "^1.0.2",
|
"@tauri-apps/api": "^1.0.2",
|
||||||
"daisyui": "^2.51.5"
|
"daisyui": "^2.51.5"
|
||||||
@@ -21,17 +21,6 @@
|
|||||||
"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",
|
||||||
@@ -166,9 +155,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tauri-apps/api": {
|
"node_modules/@tauri-apps/api": {
|
||||||
"version": "1.4.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/@tauri-apps/api/-/api-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/@tauri-apps/api/-/api-1.2.0.tgz",
|
||||||
"integrity": "sha512-Jd6HPoTM1PZSFIzq7FB8VmMu3qSSyo/3lSwLpoapW+lQ41CL5Dow2KryLg+gyazA/58DRWI9vu/XpEeHK4uMdw==",
|
"integrity": "sha512-lsI54KI6HGf7VImuf/T9pnoejfgkNoXveP14pVV7XarrQ46rOejIVJLFqHI9sRReJMGdh2YuCoI3cc/yCWCsrw==",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 14.6.0",
|
"node": ">= 14.6.0",
|
||||||
"npm": ">= 6.6.0",
|
"npm": ">= 6.6.0",
|
||||||
@@ -180,9 +169,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tauri-apps/cli": {
|
"node_modules/@tauri-apps/cli": {
|
||||||
"version": "1.4.0",
|
"version": "1.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli/-/cli-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/@tauri-apps/cli/-/cli-1.2.3.tgz",
|
||||||
"integrity": "sha512-VXYr2i2iVFl98etQSQsqLzXgX96bnWiNZd1YADgatqwy/qecbd6Kl5ZAPB5R4ynsgE8A1gU7Fbzh7dCEQYFfmA==",
|
"integrity": "sha512-erxtXuPhMEGJPBtnhPILD4AjuT81GZsraqpFvXAmEJZ2p8P6t7MVBifCL8LznRknznM3jn90D3M8RNBP3wcXTw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"tauri": "tauri.js"
|
"tauri": "tauri.js"
|
||||||
@@ -195,22 +184,21 @@
|
|||||||
"url": "https://opencollective.com/tauri"
|
"url": "https://opencollective.com/tauri"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@tauri-apps/cli-darwin-arm64": "1.4.0",
|
"@tauri-apps/cli-darwin-arm64": "1.2.3",
|
||||||
"@tauri-apps/cli-darwin-x64": "1.4.0",
|
"@tauri-apps/cli-darwin-x64": "1.2.3",
|
||||||
"@tauri-apps/cli-linux-arm-gnueabihf": "1.4.0",
|
"@tauri-apps/cli-linux-arm-gnueabihf": "1.2.3",
|
||||||
"@tauri-apps/cli-linux-arm64-gnu": "1.4.0",
|
"@tauri-apps/cli-linux-arm64-gnu": "1.2.3",
|
||||||
"@tauri-apps/cli-linux-arm64-musl": "1.4.0",
|
"@tauri-apps/cli-linux-arm64-musl": "1.2.3",
|
||||||
"@tauri-apps/cli-linux-x64-gnu": "1.4.0",
|
"@tauri-apps/cli-linux-x64-gnu": "1.2.3",
|
||||||
"@tauri-apps/cli-linux-x64-musl": "1.4.0",
|
"@tauri-apps/cli-linux-x64-musl": "1.2.3",
|
||||||
"@tauri-apps/cli-win32-arm64-msvc": "1.4.0",
|
"@tauri-apps/cli-win32-ia32-msvc": "1.2.3",
|
||||||
"@tauri-apps/cli-win32-ia32-msvc": "1.4.0",
|
"@tauri-apps/cli-win32-x64-msvc": "1.2.3"
|
||||||
"@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.4.0",
|
"version": "1.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-1.2.3.tgz",
|
||||||
"integrity": "sha512-nA/ml0SfUt6/CYLVbHmT500Y+ijqsuv5+s9EBnVXYSLVg9kbPUZJJHluEYK+xKuOj6xzyuT/+rZFMRapmJD3jQ==",
|
"integrity": "sha512-phJN3fN8FtZZwqXg08bcxfq1+X1JSDglLvRxOxB7VWPq+O5SuB8uLyssjJsu+PIhyZZnIhTGdjhzLSFhSXfLsw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -224,9 +212,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tauri-apps/cli-darwin-x64": {
|
"node_modules/@tauri-apps/cli-darwin-x64": {
|
||||||
"version": "1.4.0",
|
"version": "1.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-1.2.3.tgz",
|
||||||
"integrity": "sha512-ov/F6Zr+dg9B0PtRu65stFo2G0ow2TUlneqYYrkj+vA3n+moWDHfVty0raDjMLQbQt3rv3uayFMXGPMgble9OA==",
|
"integrity": "sha512-jFZ/y6z8z6v4yliIbXKBXA7BJgtZVMsITmEXSuD6s5+eCOpDhQxbRkr6CA+FFfr+/r96rWSDSgDenDQuSvPAKw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -240,9 +228,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tauri-apps/cli-linux-arm-gnueabihf": {
|
"node_modules/@tauri-apps/cli-linux-arm-gnueabihf": {
|
||||||
"version": "1.4.0",
|
"version": "1.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-1.2.3.tgz",
|
||||||
"integrity": "sha512-zwjbiMncycXDV7doovymyKD7sCg53ouAmfgpUqEBOTY3vgBi9TwijyPhJOqoG5vUVWhouNBC08akGmE4dja15g==",
|
"integrity": "sha512-C7h5vqAwXzY0kRGSU00Fj8PudiDWFCiQqqUNI1N+fhCILrzWZB9TPBwdx33ZfXKt/U4+emdIoo/N34v3TiAOmQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm"
|
"arm"
|
||||||
],
|
],
|
||||||
@@ -256,9 +244,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tauri-apps/cli-linux-arm64-gnu": {
|
"node_modules/@tauri-apps/cli-linux-arm64-gnu": {
|
||||||
"version": "1.4.0",
|
"version": "1.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-1.2.3.tgz",
|
||||||
"integrity": "sha512-5MCBcziqXC72mMXnkZU68mutXIR6zavDxopArE2gQtK841IlE06bIgtLi0kUUhlFJk2nhPRgiDgdLbrPlyt7fw==",
|
"integrity": "sha512-buf1c8sdkuUzVDkGPQpyUdAIIdn5r0UgXU6+H5fGPq/Xzt5K69JzXaeo6fHsZEZghbV0hOK+taKV4J0m30UUMQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -272,9 +260,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tauri-apps/cli-linux-arm64-musl": {
|
"node_modules/@tauri-apps/cli-linux-arm64-musl": {
|
||||||
"version": "1.4.0",
|
"version": "1.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-1.2.3.tgz",
|
||||||
"integrity": "sha512-7J3pRB6n6uNYgIfCeKt2Oz8J7oSaz2s8GGFRRH2HPxuTHrBNCinzVYm68UhVpJrL3bnGkU0ziVZLsW/iaOGfUg==",
|
"integrity": "sha512-x88wPS9W5xAyk392vc4uNHcKBBvCp0wf4H9JFMF9OBwB7vfd59LbQCFcPSu8f0BI7bPrOsyHqspWHuFL8ojQEA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -288,9 +276,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tauri-apps/cli-linux-x64-gnu": {
|
"node_modules/@tauri-apps/cli-linux-x64-gnu": {
|
||||||
"version": "1.4.0",
|
"version": "1.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-1.2.3.tgz",
|
||||||
"integrity": "sha512-Zh5gfAJxOv5AVWxcwuueaQ2vIAhlg0d6nZui6nMyfIJ8dbf3aZQ5ZzP38sYow5h/fbvgL+3GSQxZRBIa3c2E1w==",
|
"integrity": "sha512-ZMz1jxEVe0B4/7NJnlPHmwmSIuwiD6ViXKs8F+OWWz2Y4jn5TGxWKFg7DLx5OwQTRvEIZxxT7lXHi5CuTNAxKg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -304,9 +292,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tauri-apps/cli-linux-x64-musl": {
|
"node_modules/@tauri-apps/cli-linux-x64-musl": {
|
||||||
"version": "1.4.0",
|
"version": "1.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-1.2.3.tgz",
|
||||||
"integrity": "sha512-OLAYoICU3FaYiTdBsI+lQTKnDHeMmFMXIApN0M+xGiOkoIOQcV9CConMPjgmJQ867+NHRNgUGlvBEAh9CiJodQ==",
|
"integrity": "sha512-B/az59EjJhdbZDzawEVox0LQu2ZHCZlk8rJf85AMIktIUoAZPFbwyiUv7/zjzA/sY6Nb58OSJgaPL2/IBy7E0A==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -319,26 +307,10 @@
|
|||||||
"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.4.0",
|
"version": "1.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-1.2.3.tgz",
|
||||||
"integrity": "sha512-JsetT/lTx/Zq98eo8T5CiRyF1nKeX04RO8JlJrI3ZOYsZpp/A5RJvMd/szQ17iOzwiHdge+tx7k2jHysR6oBlQ==",
|
"integrity": "sha512-ypdO1OdC5ugNJAKO2m3sb1nsd+0TSvMS9Tr5qN/ZSMvtSduaNwrcZ3D7G/iOIanrqu/Nl8t3LYlgPZGBKlw7Ng==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"ia32"
|
"ia32"
|
||||||
],
|
],
|
||||||
@@ -352,9 +324,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tauri-apps/cli-win32-x64-msvc": {
|
"node_modules/@tauri-apps/cli-win32-x64-msvc": {
|
||||||
"version": "1.4.0",
|
"version": "1.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-1.2.3.tgz",
|
||||||
"integrity": "sha512-z8Olcnwp5aYhzqUAarFjqF+oELCjuYWnB2HAJHlfsYNfDCAORY5kct3Fklz8PSsubC3U2EugWn8n42DwnThurg==",
|
"integrity": "sha512-CsbHQ+XhnV/2csOBBDVfH16cdK00gNyNYUW68isedmqcn8j+s0e9cQ1xXIqi+Hue3awp8g3ImYN5KPepf3UExw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -455,9 +427,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/browserslist": {
|
"node_modules/browserslist": {
|
||||||
"version": "4.21.9",
|
"version": "4.21.5",
|
||||||
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.9.tgz",
|
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz",
|
||||||
"integrity": "sha512-M0MFoZzbUrRU4KNfCrDLnvyE7gub+peetoTid3TBIqtunaDJyXlwhakT+/VkvSXcfIzFfK/nkCs4nmyTmxdNSg==",
|
"integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==",
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "opencollective",
|
"type": "opencollective",
|
||||||
@@ -466,17 +438,13 @@
|
|||||||
{
|
{
|
||||||
"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.30001503",
|
"caniuse-lite": "^1.0.30001449",
|
||||||
"electron-to-chromium": "^1.4.431",
|
"electron-to-chromium": "^1.4.284",
|
||||||
"node-releases": "^2.0.12",
|
"node-releases": "^2.0.8",
|
||||||
"update-browserslist-db": "^1.0.11"
|
"update-browserslist-db": "^1.0.10"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"browserslist": "cli.js"
|
"browserslist": "cli.js"
|
||||||
@@ -494,9 +462,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/caniuse-lite": {
|
"node_modules/caniuse-lite": {
|
||||||
"version": "1.0.30001515",
|
"version": "1.0.30001481",
|
||||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001515.tgz",
|
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001481.tgz",
|
||||||
"integrity": "sha512-eEFDwUOZbE24sb+Ecsx3+OvNETqjWIdabMy52oOkIgcUtAsQifjUG9q4U9dgTHJM2mfk4uEPxc0+xuFdJ629QA==",
|
"integrity": "sha512-KCqHwRnaa1InZBtqXzP98LPg0ajCVujMKjqKDhZEthIpAsJl/YEIa3YvXjGXPVqzZVguccuu7ga9KOE1J9rKPQ==",
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "opencollective",
|
"type": "opencollective",
|
||||||
@@ -620,9 +588,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/daisyui": {
|
"node_modules/daisyui": {
|
||||||
"version": "2.52.0",
|
"version": "2.51.5",
|
||||||
"resolved": "https://registry.npmjs.org/daisyui/-/daisyui-2.52.0.tgz",
|
"resolved": "https://registry.npmjs.org/daisyui/-/daisyui-2.51.5.tgz",
|
||||||
"integrity": "sha512-LQTA5/IVXAJHBMFoeaEMfd7/akAFPPcdQPR3O9fzzcFiczneJFM73CFPnScmW2sOgn/D83cvkP854ep2T9OfTg==",
|
"integrity": "sha512-L05dRw0tasmz2Ha+10LhftEGLq4kaA8vRR/T0wDaXfHwqcgsf81jfXDJ6NlZ63Z7Rl1k3rj7UHs0l0p7CM3aYA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"color": "^4.2",
|
"color": "^4.2",
|
||||||
"css-selector-tokenizer": "^0.8.0",
|
"css-selector-tokenizer": "^0.8.0",
|
||||||
@@ -675,9 +643,9 @@
|
|||||||
"integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA=="
|
"integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA=="
|
||||||
},
|
},
|
||||||
"node_modules/electron-to-chromium": {
|
"node_modules/electron-to-chromium": {
|
||||||
"version": "1.4.455",
|
"version": "1.4.369",
|
||||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.455.tgz",
|
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.369.tgz",
|
||||||
"integrity": "sha512-8tgdX0Odl24LtmLwxotpJCVjIndN559AvaOtd67u+2mo+IDsgsTF580NB+uuDCqsHw8yFg53l5+imFV9Fw3cbA=="
|
"integrity": "sha512-LfxbHXdA/S+qyoTEA4EbhxGjrxx7WK2h6yb5K2v0UCOufUKX+VZaHbl3svlzZfv9sGseym/g3Ne4DpsgRULmqg=="
|
||||||
},
|
},
|
||||||
"node_modules/esbuild": {
|
"node_modules/esbuild": {
|
||||||
"version": "0.15.18",
|
"version": "0.15.18",
|
||||||
@@ -1045,9 +1013,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/fast-glob": {
|
"node_modules/fast-glob": {
|
||||||
"version": "3.3.0",
|
"version": "3.2.12",
|
||||||
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz",
|
||||||
"integrity": "sha512-ChDuvbOypPuNjO8yIDf36x7BlZX1smcUMTTcyoIjycexOxd6DFsKsg21qVBzEmr3G7fUKIRy2/psii+CIUt7FA==",
|
"integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==",
|
||||||
"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",
|
||||||
@@ -1201,9 +1169,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/is-core-module": {
|
"node_modules/is-core-module": {
|
||||||
"version": "2.12.1",
|
"version": "2.12.0",
|
||||||
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz",
|
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.0.tgz",
|
||||||
"integrity": "sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==",
|
"integrity": "sha512-RECHCBCd/viahWmwj6enj19sKbHfJrddi/6cBDsNTKbNq0f7VeaUkBo60BqzvPqo/W54ChS62Z5qyun7cfOMqQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"has": "^1.0.3"
|
"has": "^1.0.3"
|
||||||
},
|
},
|
||||||
@@ -1239,9 +1207,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/jiti": {
|
"node_modules/jiti": {
|
||||||
"version": "1.19.1",
|
"version": "1.18.2",
|
||||||
"resolved": "https://registry.npmjs.org/jiti/-/jiti-1.19.1.tgz",
|
"resolved": "https://registry.npmjs.org/jiti/-/jiti-1.18.2.tgz",
|
||||||
"integrity": "sha512-oVhqoRDaBXf7sjkll95LHVS6Myyyb1zaunVwk4Z0+WPSW4gjS0pl01zYKHScTuyEhQsFxV5L4DR5r+YqSyqyyg==",
|
"integrity": "sha512-QAdOptna2NYiSSpv0O/BwoHBSmz4YhpzJHyi+fnMRTXFjp7B8i/YG5Z8IfusxB1ufjcD2Sre1F3R+nX3fvy7gg==",
|
||||||
"bin": {
|
"bin": {
|
||||||
"jiti": "bin/jiti.js"
|
"jiti": "bin/jiti.js"
|
||||||
}
|
}
|
||||||
@@ -1345,9 +1313,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/node-releases": {
|
"node_modules/node-releases": {
|
||||||
"version": "2.0.13",
|
"version": "2.0.10",
|
||||||
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz",
|
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz",
|
||||||
"integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ=="
|
"integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w=="
|
||||||
},
|
},
|
||||||
"node_modules/normalize-path": {
|
"node_modules/normalize-path": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
@@ -1427,17 +1395,17 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/pirates": {
|
"node_modules/pirates": {
|
||||||
"version": "4.0.6",
|
"version": "4.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz",
|
||||||
"integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==",
|
"integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 6"
|
"node": ">= 6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/postcss": {
|
"node_modules/postcss": {
|
||||||
"version": "8.4.25",
|
"version": "8.4.23",
|
||||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.25.tgz",
|
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.23.tgz",
|
||||||
"integrity": "sha512-7taJ/8t2av0Z+sQEvNzCkpDynl0tX3uJMCODi6nT3PfASC7dYCWV9aQ+uiCf+KBD4SEFcu+GvJdGdwzQ6OSjCw==",
|
"integrity": "sha512-bQ3qMcpF6A/YjR55xtoTr0jGOlnPOKAIMdOWiv0EIT6HVPEaJiJB4NLljSbiHoC2RX7DN5Uvjtpbg1NPdwv1oA==",
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "opencollective",
|
"type": "opencollective",
|
||||||
@@ -1462,16 +1430,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/postcss-import": {
|
"node_modules/postcss-import": {
|
||||||
"version": "15.1.0",
|
"version": "14.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-14.1.0.tgz",
|
||||||
"integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==",
|
"integrity": "sha512-flwI+Vgm4SElObFVPpTIT7SU7R3qk2L7PyduMcokiaVKuWv9d/U+Gm/QAd8NDLuykTWTkcrjOeD2Pp1rMeBTGw==",
|
||||||
"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": ">=14.0.0"
|
"node": ">=10.0.0"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"postcss": "^8.0.0"
|
"postcss": "^8.0.0"
|
||||||
@@ -1496,15 +1464,15 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/postcss-load-config": {
|
"node_modules/postcss-load-config": {
|
||||||
"version": "4.0.1",
|
"version": "3.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.4.tgz",
|
||||||
"integrity": "sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA==",
|
"integrity": "sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"lilconfig": "^2.0.5",
|
"lilconfig": "^2.0.5",
|
||||||
"yaml": "^2.1.1"
|
"yaml": "^1.10.2"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 14"
|
"node": ">= 10"
|
||||||
},
|
},
|
||||||
"funding": {
|
"funding": {
|
||||||
"type": "opencollective",
|
"type": "opencollective",
|
||||||
@@ -1524,11 +1492,11 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/postcss-nested": {
|
"node_modules/postcss-nested": {
|
||||||
"version": "6.0.1",
|
"version": "6.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.0.tgz",
|
||||||
"integrity": "sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==",
|
"integrity": "sha512-0DkamqrPcmkBDsLn+vQDIrtkSbNkv5AD/M322ySo9kqFkCIYklym2xEmWkwo+Y3/qZo34tzEPNUw4y7yMCdv5w==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"postcss-selector-parser": "^6.0.11"
|
"postcss-selector-parser": "^6.0.10"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12.0"
|
"node": ">=12.0"
|
||||||
@@ -1542,9 +1510,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/postcss-selector-parser": {
|
"node_modules/postcss-selector-parser": {
|
||||||
"version": "6.0.13",
|
"version": "6.0.11",
|
||||||
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz",
|
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.11.tgz",
|
||||||
"integrity": "sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==",
|
"integrity": "sha512-zbARubNdogI9j7WY4nQJBiNqQf3sLS3wCP4WfOidu+p28LofJqDH1tcXypGrcmMHhDk2t9wGhCsYe/+szLTy1g==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"cssesc": "^3.0.0",
|
"cssesc": "^3.0.0",
|
||||||
"util-deprecate": "^1.0.2"
|
"util-deprecate": "^1.0.2"
|
||||||
@@ -1577,6 +1545,17 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"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",
|
||||||
@@ -1714,61 +1693,65 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/svelte": {
|
"node_modules/svelte": {
|
||||||
"version": "3.59.2",
|
"version": "3.58.0",
|
||||||
"resolved": "https://registry.npmjs.org/svelte/-/svelte-3.59.2.tgz",
|
"resolved": "https://registry.npmjs.org/svelte/-/svelte-3.58.0.tgz",
|
||||||
"integrity": "sha512-vzSyuGr3eEoAtT/A6bmajosJZIUWySzY2CzB3w2pgPvnkUjGqlDnsNnA0PMO+mMAhuyMul6C2uuZzY6ELSkzyA==",
|
"integrity": "sha512-brIBNNB76mXFmU/Kerm4wFnkskBbluBDCjx/8TcpYRb298Yh2dztS2kQ6bhtjMcvUhd5ynClfwpz5h2gnzdQ1A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 8"
|
"node": ">= 8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/svelte-hmr": {
|
"node_modules/svelte-hmr": {
|
||||||
"version": "0.15.2",
|
"version": "0.15.1",
|
||||||
"resolved": "https://registry.npmjs.org/svelte-hmr/-/svelte-hmr-0.15.2.tgz",
|
"resolved": "https://registry.npmjs.org/svelte-hmr/-/svelte-hmr-0.15.1.tgz",
|
||||||
"integrity": "sha512-q/bAruCvFLwvNbeE1x3n37TYFb3mTBJ6TrCq6p2CoFbSTNhDE9oAtEfpy+wmc9So8AG0Tja+X0/mJzX9tSfvIg==",
|
"integrity": "sha512-BiKB4RZ8YSwRKCNVdNxK/GfY+r4Kjgp9jCLEy0DuqAKfmQtpL38cQK3afdpjw4sqSs4PLi3jIPJIFp259NkZtA==",
|
||||||
"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 || ^4.0.0-next.0"
|
"svelte": ">=3.19.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/tailwindcss": {
|
"node_modules/tailwindcss": {
|
||||||
"version": "3.3.2",
|
"version": "3.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.1.tgz",
|
||||||
"integrity": "sha512-9jPkMiIBXvPc2KywkraqsUfbfj+dHDb+JPWtSJa9MLFdrPyazI7q6WX2sUrm7R9eVR7qqv3Pas7EvQFzxKnI6w==",
|
"integrity": "sha512-Vkiouc41d4CEq0ujXl6oiGFQ7bA3WEhUZdTgXAhtKxSy49OmKs8rEfQmupsfF0IGW8fv2iQkp1EVUuapCFrZ9g==",
|
||||||
"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.18.2",
|
"jiti": "^1.17.2",
|
||||||
"lilconfig": "^2.1.0",
|
"lilconfig": "^2.0.6",
|
||||||
"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.4.23",
|
"postcss": "^8.0.9",
|
||||||
"postcss-import": "^15.1.0",
|
"postcss-import": "^14.1.0",
|
||||||
"postcss-js": "^4.0.1",
|
"postcss-js": "^4.0.0",
|
||||||
"postcss-load-config": "^4.0.1",
|
"postcss-load-config": "^3.1.4",
|
||||||
"postcss-nested": "^6.0.1",
|
"postcss-nested": "6.0.0",
|
||||||
"postcss-selector-parser": "^6.0.11",
|
"postcss-selector-parser": "^6.0.11",
|
||||||
"postcss-value-parser": "^4.2.0",
|
"postcss-value-parser": "^4.2.0",
|
||||||
"resolve": "^1.22.2",
|
"quick-lru": "^5.1.1",
|
||||||
"sucrase": "^3.32.0"
|
"resolve": "^1.22.1",
|
||||||
|
"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": ">=14.0.0"
|
"node": ">=12.13.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"postcss": "^8.0.9"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/thenify": {
|
"node_modules/thenify": {
|
||||||
@@ -1841,9 +1824,9 @@
|
|||||||
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
|
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
|
||||||
},
|
},
|
||||||
"node_modules/vite": {
|
"node_modules/vite": {
|
||||||
"version": "3.2.7",
|
"version": "3.2.6",
|
||||||
"resolved": "https://registry.npmjs.org/vite/-/vite-3.2.7.tgz",
|
"resolved": "https://registry.npmjs.org/vite/-/vite-3.2.6.tgz",
|
||||||
"integrity": "sha512-29pdXjk49xAP0QBr0xXqu2s5jiQIXNvE/xwd0vUizYT2Hzqe4BksNNoWllFVXJf4eLZ+UlVQmXfB4lWrc+t18g==",
|
"integrity": "sha512-nTXTxYVvaQNLoW5BQ8PNNQ3lPia57gzsQU/Khv+JvzKPku8kNZL6NMUR/qwXhMG6E+g1idqEPanomJ+VZgixEg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"esbuild": "^0.15.9",
|
"esbuild": "^0.15.9",
|
||||||
@@ -1909,20 +1892,15 @@
|
|||||||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
|
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
|
||||||
},
|
},
|
||||||
"node_modules/yaml": {
|
"node_modules/yaml": {
|
||||||
"version": "2.3.1",
|
"version": "1.10.2",
|
||||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
|
||||||
"integrity": "sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ==",
|
"integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 14"
|
"node": ">= 6"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"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",
|
||||||
@@ -2016,95 +1994,87 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@tauri-apps/api": {
|
"@tauri-apps/api": {
|
||||||
"version": "1.4.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/@tauri-apps/api/-/api-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/@tauri-apps/api/-/api-1.2.0.tgz",
|
||||||
"integrity": "sha512-Jd6HPoTM1PZSFIzq7FB8VmMu3qSSyo/3lSwLpoapW+lQ41CL5Dow2KryLg+gyazA/58DRWI9vu/XpEeHK4uMdw=="
|
"integrity": "sha512-lsI54KI6HGf7VImuf/T9pnoejfgkNoXveP14pVV7XarrQ46rOejIVJLFqHI9sRReJMGdh2YuCoI3cc/yCWCsrw=="
|
||||||
},
|
},
|
||||||
"@tauri-apps/cli": {
|
"@tauri-apps/cli": {
|
||||||
"version": "1.4.0",
|
"version": "1.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli/-/cli-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/@tauri-apps/cli/-/cli-1.2.3.tgz",
|
||||||
"integrity": "sha512-VXYr2i2iVFl98etQSQsqLzXgX96bnWiNZd1YADgatqwy/qecbd6Kl5ZAPB5R4ynsgE8A1gU7Fbzh7dCEQYFfmA==",
|
"integrity": "sha512-erxtXuPhMEGJPBtnhPILD4AjuT81GZsraqpFvXAmEJZ2p8P6t7MVBifCL8LznRknznM3jn90D3M8RNBP3wcXTw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@tauri-apps/cli-darwin-arm64": "1.4.0",
|
"@tauri-apps/cli-darwin-arm64": "1.2.3",
|
||||||
"@tauri-apps/cli-darwin-x64": "1.4.0",
|
"@tauri-apps/cli-darwin-x64": "1.2.3",
|
||||||
"@tauri-apps/cli-linux-arm-gnueabihf": "1.4.0",
|
"@tauri-apps/cli-linux-arm-gnueabihf": "1.2.3",
|
||||||
"@tauri-apps/cli-linux-arm64-gnu": "1.4.0",
|
"@tauri-apps/cli-linux-arm64-gnu": "1.2.3",
|
||||||
"@tauri-apps/cli-linux-arm64-musl": "1.4.0",
|
"@tauri-apps/cli-linux-arm64-musl": "1.2.3",
|
||||||
"@tauri-apps/cli-linux-x64-gnu": "1.4.0",
|
"@tauri-apps/cli-linux-x64-gnu": "1.2.3",
|
||||||
"@tauri-apps/cli-linux-x64-musl": "1.4.0",
|
"@tauri-apps/cli-linux-x64-musl": "1.2.3",
|
||||||
"@tauri-apps/cli-win32-arm64-msvc": "1.4.0",
|
"@tauri-apps/cli-win32-ia32-msvc": "1.2.3",
|
||||||
"@tauri-apps/cli-win32-ia32-msvc": "1.4.0",
|
"@tauri-apps/cli-win32-x64-msvc": "1.2.3"
|
||||||
"@tauri-apps/cli-win32-x64-msvc": "1.4.0"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@tauri-apps/cli-darwin-arm64": {
|
"@tauri-apps/cli-darwin-arm64": {
|
||||||
"version": "1.4.0",
|
"version": "1.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-1.2.3.tgz",
|
||||||
"integrity": "sha512-nA/ml0SfUt6/CYLVbHmT500Y+ijqsuv5+s9EBnVXYSLVg9kbPUZJJHluEYK+xKuOj6xzyuT/+rZFMRapmJD3jQ==",
|
"integrity": "sha512-phJN3fN8FtZZwqXg08bcxfq1+X1JSDglLvRxOxB7VWPq+O5SuB8uLyssjJsu+PIhyZZnIhTGdjhzLSFhSXfLsw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"@tauri-apps/cli-darwin-x64": {
|
"@tauri-apps/cli-darwin-x64": {
|
||||||
"version": "1.4.0",
|
"version": "1.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-1.2.3.tgz",
|
||||||
"integrity": "sha512-ov/F6Zr+dg9B0PtRu65stFo2G0ow2TUlneqYYrkj+vA3n+moWDHfVty0raDjMLQbQt3rv3uayFMXGPMgble9OA==",
|
"integrity": "sha512-jFZ/y6z8z6v4yliIbXKBXA7BJgtZVMsITmEXSuD6s5+eCOpDhQxbRkr6CA+FFfr+/r96rWSDSgDenDQuSvPAKw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"@tauri-apps/cli-linux-arm-gnueabihf": {
|
"@tauri-apps/cli-linux-arm-gnueabihf": {
|
||||||
"version": "1.4.0",
|
"version": "1.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-1.2.3.tgz",
|
||||||
"integrity": "sha512-zwjbiMncycXDV7doovymyKD7sCg53ouAmfgpUqEBOTY3vgBi9TwijyPhJOqoG5vUVWhouNBC08akGmE4dja15g==",
|
"integrity": "sha512-C7h5vqAwXzY0kRGSU00Fj8PudiDWFCiQqqUNI1N+fhCILrzWZB9TPBwdx33ZfXKt/U4+emdIoo/N34v3TiAOmQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"@tauri-apps/cli-linux-arm64-gnu": {
|
"@tauri-apps/cli-linux-arm64-gnu": {
|
||||||
"version": "1.4.0",
|
"version": "1.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-1.2.3.tgz",
|
||||||
"integrity": "sha512-5MCBcziqXC72mMXnkZU68mutXIR6zavDxopArE2gQtK841IlE06bIgtLi0kUUhlFJk2nhPRgiDgdLbrPlyt7fw==",
|
"integrity": "sha512-buf1c8sdkuUzVDkGPQpyUdAIIdn5r0UgXU6+H5fGPq/Xzt5K69JzXaeo6fHsZEZghbV0hOK+taKV4J0m30UUMQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"@tauri-apps/cli-linux-arm64-musl": {
|
"@tauri-apps/cli-linux-arm64-musl": {
|
||||||
"version": "1.4.0",
|
"version": "1.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-1.2.3.tgz",
|
||||||
"integrity": "sha512-7J3pRB6n6uNYgIfCeKt2Oz8J7oSaz2s8GGFRRH2HPxuTHrBNCinzVYm68UhVpJrL3bnGkU0ziVZLsW/iaOGfUg==",
|
"integrity": "sha512-x88wPS9W5xAyk392vc4uNHcKBBvCp0wf4H9JFMF9OBwB7vfd59LbQCFcPSu8f0BI7bPrOsyHqspWHuFL8ojQEA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"@tauri-apps/cli-linux-x64-gnu": {
|
"@tauri-apps/cli-linux-x64-gnu": {
|
||||||
"version": "1.4.0",
|
"version": "1.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-1.2.3.tgz",
|
||||||
"integrity": "sha512-Zh5gfAJxOv5AVWxcwuueaQ2vIAhlg0d6nZui6nMyfIJ8dbf3aZQ5ZzP38sYow5h/fbvgL+3GSQxZRBIa3c2E1w==",
|
"integrity": "sha512-ZMz1jxEVe0B4/7NJnlPHmwmSIuwiD6ViXKs8F+OWWz2Y4jn5TGxWKFg7DLx5OwQTRvEIZxxT7lXHi5CuTNAxKg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"@tauri-apps/cli-linux-x64-musl": {
|
"@tauri-apps/cli-linux-x64-musl": {
|
||||||
"version": "1.4.0",
|
"version": "1.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-1.2.3.tgz",
|
||||||
"integrity": "sha512-OLAYoICU3FaYiTdBsI+lQTKnDHeMmFMXIApN0M+xGiOkoIOQcV9CConMPjgmJQ867+NHRNgUGlvBEAh9CiJodQ==",
|
"integrity": "sha512-B/az59EjJhdbZDzawEVox0LQu2ZHCZlk8rJf85AMIktIUoAZPFbwyiUv7/zjzA/sY6Nb58OSJgaPL2/IBy7E0A==",
|
||||||
"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.4.0",
|
"version": "1.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-1.2.3.tgz",
|
||||||
"integrity": "sha512-JsetT/lTx/Zq98eo8T5CiRyF1nKeX04RO8JlJrI3ZOYsZpp/A5RJvMd/szQ17iOzwiHdge+tx7k2jHysR6oBlQ==",
|
"integrity": "sha512-ypdO1OdC5ugNJAKO2m3sb1nsd+0TSvMS9Tr5qN/ZSMvtSduaNwrcZ3D7G/iOIanrqu/Nl8t3LYlgPZGBKlw7Ng==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"@tauri-apps/cli-win32-x64-msvc": {
|
"@tauri-apps/cli-win32-x64-msvc": {
|
||||||
"version": "1.4.0",
|
"version": "1.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-1.2.3.tgz",
|
||||||
"integrity": "sha512-z8Olcnwp5aYhzqUAarFjqF+oELCjuYWnB2HAJHlfsYNfDCAORY5kct3Fklz8PSsubC3U2EugWn8n42DwnThurg==",
|
"integrity": "sha512-CsbHQ+XhnV/2csOBBDVfH16cdK00gNyNYUW68isedmqcn8j+s0e9cQ1xXIqi+Hue3awp8g3ImYN5KPepf3UExw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
@@ -2168,14 +2138,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"browserslist": {
|
"browserslist": {
|
||||||
"version": "4.21.9",
|
"version": "4.21.5",
|
||||||
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.9.tgz",
|
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz",
|
||||||
"integrity": "sha512-M0MFoZzbUrRU4KNfCrDLnvyE7gub+peetoTid3TBIqtunaDJyXlwhakT+/VkvSXcfIzFfK/nkCs4nmyTmxdNSg==",
|
"integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"caniuse-lite": "^1.0.30001503",
|
"caniuse-lite": "^1.0.30001449",
|
||||||
"electron-to-chromium": "^1.4.431",
|
"electron-to-chromium": "^1.4.284",
|
||||||
"node-releases": "^2.0.12",
|
"node-releases": "^2.0.8",
|
||||||
"update-browserslist-db": "^1.0.11"
|
"update-browserslist-db": "^1.0.10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"camelcase-css": {
|
"camelcase-css": {
|
||||||
@@ -2184,9 +2154,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.30001515",
|
"version": "1.0.30001481",
|
||||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001515.tgz",
|
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001481.tgz",
|
||||||
"integrity": "sha512-eEFDwUOZbE24sb+Ecsx3+OvNETqjWIdabMy52oOkIgcUtAsQifjUG9q4U9dgTHJM2mfk4uEPxc0+xuFdJ629QA=="
|
"integrity": "sha512-KCqHwRnaa1InZBtqXzP98LPg0ajCVujMKjqKDhZEthIpAsJl/YEIa3YvXjGXPVqzZVguccuu7ga9KOE1J9rKPQ=="
|
||||||
},
|
},
|
||||||
"chokidar": {
|
"chokidar": {
|
||||||
"version": "3.5.3",
|
"version": "3.5.3",
|
||||||
@@ -2269,9 +2239,9 @@
|
|||||||
"integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg=="
|
"integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg=="
|
||||||
},
|
},
|
||||||
"daisyui": {
|
"daisyui": {
|
||||||
"version": "2.52.0",
|
"version": "2.51.5",
|
||||||
"resolved": "https://registry.npmjs.org/daisyui/-/daisyui-2.52.0.tgz",
|
"resolved": "https://registry.npmjs.org/daisyui/-/daisyui-2.51.5.tgz",
|
||||||
"integrity": "sha512-LQTA5/IVXAJHBMFoeaEMfd7/akAFPPcdQPR3O9fzzcFiczneJFM73CFPnScmW2sOgn/D83cvkP854ep2T9OfTg==",
|
"integrity": "sha512-L05dRw0tasmz2Ha+10LhftEGLq4kaA8vRR/T0wDaXfHwqcgsf81jfXDJ6NlZ63Z7Rl1k3rj7UHs0l0p7CM3aYA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"color": "^4.2",
|
"color": "^4.2",
|
||||||
"css-selector-tokenizer": "^0.8.0",
|
"css-selector-tokenizer": "^0.8.0",
|
||||||
@@ -2305,9 +2275,9 @@
|
|||||||
"integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA=="
|
"integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA=="
|
||||||
},
|
},
|
||||||
"electron-to-chromium": {
|
"electron-to-chromium": {
|
||||||
"version": "1.4.455",
|
"version": "1.4.369",
|
||||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.455.tgz",
|
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.369.tgz",
|
||||||
"integrity": "sha512-8tgdX0Odl24LtmLwxotpJCVjIndN559AvaOtd67u+2mo+IDsgsTF580NB+uuDCqsHw8yFg53l5+imFV9Fw3cbA=="
|
"integrity": "sha512-LfxbHXdA/S+qyoTEA4EbhxGjrxx7WK2h6yb5K2v0UCOufUKX+VZaHbl3svlzZfv9sGseym/g3Ne4DpsgRULmqg=="
|
||||||
},
|
},
|
||||||
"esbuild": {
|
"esbuild": {
|
||||||
"version": "0.15.18",
|
"version": "0.15.18",
|
||||||
@@ -2485,9 +2455,9 @@
|
|||||||
"integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw=="
|
"integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw=="
|
||||||
},
|
},
|
||||||
"fast-glob": {
|
"fast-glob": {
|
||||||
"version": "3.3.0",
|
"version": "3.2.12",
|
||||||
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz",
|
||||||
"integrity": "sha512-ChDuvbOypPuNjO8yIDf36x7BlZX1smcUMTTcyoIjycexOxd6DFsKsg21qVBzEmr3G7fUKIRy2/psii+CIUt7FA==",
|
"integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==",
|
||||||
"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",
|
||||||
@@ -2605,9 +2575,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"is-core-module": {
|
"is-core-module": {
|
||||||
"version": "2.12.1",
|
"version": "2.12.0",
|
||||||
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz",
|
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.0.tgz",
|
||||||
"integrity": "sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==",
|
"integrity": "sha512-RECHCBCd/viahWmwj6enj19sKbHfJrddi/6cBDsNTKbNq0f7VeaUkBo60BqzvPqo/W54ChS62Z5qyun7cfOMqQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"has": "^1.0.3"
|
"has": "^1.0.3"
|
||||||
}
|
}
|
||||||
@@ -2631,9 +2601,9 @@
|
|||||||
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="
|
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="
|
||||||
},
|
},
|
||||||
"jiti": {
|
"jiti": {
|
||||||
"version": "1.19.1",
|
"version": "1.18.2",
|
||||||
"resolved": "https://registry.npmjs.org/jiti/-/jiti-1.19.1.tgz",
|
"resolved": "https://registry.npmjs.org/jiti/-/jiti-1.18.2.tgz",
|
||||||
"integrity": "sha512-oVhqoRDaBXf7sjkll95LHVS6Myyyb1zaunVwk4Z0+WPSW4gjS0pl01zYKHScTuyEhQsFxV5L4DR5r+YqSyqyyg=="
|
"integrity": "sha512-QAdOptna2NYiSSpv0O/BwoHBSmz4YhpzJHyi+fnMRTXFjp7B8i/YG5Z8IfusxB1ufjcD2Sre1F3R+nX3fvy7gg=="
|
||||||
},
|
},
|
||||||
"kleur": {
|
"kleur": {
|
||||||
"version": "4.1.5",
|
"version": "4.1.5",
|
||||||
@@ -2704,9 +2674,9 @@
|
|||||||
"integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA=="
|
"integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA=="
|
||||||
},
|
},
|
||||||
"node-releases": {
|
"node-releases": {
|
||||||
"version": "2.0.13",
|
"version": "2.0.10",
|
||||||
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz",
|
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz",
|
||||||
"integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ=="
|
"integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w=="
|
||||||
},
|
},
|
||||||
"normalize-path": {
|
"normalize-path": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
@@ -2762,14 +2732,14 @@
|
|||||||
"integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog=="
|
"integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog=="
|
||||||
},
|
},
|
||||||
"pirates": {
|
"pirates": {
|
||||||
"version": "4.0.6",
|
"version": "4.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz",
|
||||||
"integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg=="
|
"integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ=="
|
||||||
},
|
},
|
||||||
"postcss": {
|
"postcss": {
|
||||||
"version": "8.4.25",
|
"version": "8.4.23",
|
||||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.25.tgz",
|
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.23.tgz",
|
||||||
"integrity": "sha512-7taJ/8t2av0Z+sQEvNzCkpDynl0tX3uJMCODi6nT3PfASC7dYCWV9aQ+uiCf+KBD4SEFcu+GvJdGdwzQ6OSjCw==",
|
"integrity": "sha512-bQ3qMcpF6A/YjR55xtoTr0jGOlnPOKAIMdOWiv0EIT6HVPEaJiJB4NLljSbiHoC2RX7DN5Uvjtpbg1NPdwv1oA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"nanoid": "^3.3.6",
|
"nanoid": "^3.3.6",
|
||||||
"picocolors": "^1.0.0",
|
"picocolors": "^1.0.0",
|
||||||
@@ -2777,9 +2747,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"postcss-import": {
|
"postcss-import": {
|
||||||
"version": "15.1.0",
|
"version": "14.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-14.1.0.tgz",
|
||||||
"integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==",
|
"integrity": "sha512-flwI+Vgm4SElObFVPpTIT7SU7R3qk2L7PyduMcokiaVKuWv9d/U+Gm/QAd8NDLuykTWTkcrjOeD2Pp1rMeBTGw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"postcss-value-parser": "^4.0.0",
|
"postcss-value-parser": "^4.0.0",
|
||||||
"read-cache": "^1.0.0",
|
"read-cache": "^1.0.0",
|
||||||
@@ -2795,26 +2765,26 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"postcss-load-config": {
|
"postcss-load-config": {
|
||||||
"version": "4.0.1",
|
"version": "3.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.4.tgz",
|
||||||
"integrity": "sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA==",
|
"integrity": "sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"lilconfig": "^2.0.5",
|
"lilconfig": "^2.0.5",
|
||||||
"yaml": "^2.1.1"
|
"yaml": "^1.10.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"postcss-nested": {
|
"postcss-nested": {
|
||||||
"version": "6.0.1",
|
"version": "6.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.0.tgz",
|
||||||
"integrity": "sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==",
|
"integrity": "sha512-0DkamqrPcmkBDsLn+vQDIrtkSbNkv5AD/M322ySo9kqFkCIYklym2xEmWkwo+Y3/qZo34tzEPNUw4y7yMCdv5w==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"postcss-selector-parser": "^6.0.11"
|
"postcss-selector-parser": "^6.0.10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"postcss-selector-parser": {
|
"postcss-selector-parser": {
|
||||||
"version": "6.0.13",
|
"version": "6.0.11",
|
||||||
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz",
|
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.11.tgz",
|
||||||
"integrity": "sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==",
|
"integrity": "sha512-zbARubNdogI9j7WY4nQJBiNqQf3sLS3wCP4WfOidu+p28LofJqDH1tcXypGrcmMHhDk2t9wGhCsYe/+szLTy1g==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"cssesc": "^3.0.0",
|
"cssesc": "^3.0.0",
|
||||||
"util-deprecate": "^1.0.2"
|
"util-deprecate": "^1.0.2"
|
||||||
@@ -2830,6 +2800,11 @@
|
|||||||
"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",
|
||||||
@@ -2917,46 +2892,47 @@
|
|||||||
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="
|
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="
|
||||||
},
|
},
|
||||||
"svelte": {
|
"svelte": {
|
||||||
"version": "3.59.2",
|
"version": "3.58.0",
|
||||||
"resolved": "https://registry.npmjs.org/svelte/-/svelte-3.59.2.tgz",
|
"resolved": "https://registry.npmjs.org/svelte/-/svelte-3.58.0.tgz",
|
||||||
"integrity": "sha512-vzSyuGr3eEoAtT/A6bmajosJZIUWySzY2CzB3w2pgPvnkUjGqlDnsNnA0PMO+mMAhuyMul6C2uuZzY6ELSkzyA==",
|
"integrity": "sha512-brIBNNB76mXFmU/Kerm4wFnkskBbluBDCjx/8TcpYRb298Yh2dztS2kQ6bhtjMcvUhd5ynClfwpz5h2gnzdQ1A==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"svelte-hmr": {
|
"svelte-hmr": {
|
||||||
"version": "0.15.2",
|
"version": "0.15.1",
|
||||||
"resolved": "https://registry.npmjs.org/svelte-hmr/-/svelte-hmr-0.15.2.tgz",
|
"resolved": "https://registry.npmjs.org/svelte-hmr/-/svelte-hmr-0.15.1.tgz",
|
||||||
"integrity": "sha512-q/bAruCvFLwvNbeE1x3n37TYFb3mTBJ6TrCq6p2CoFbSTNhDE9oAtEfpy+wmc9So8AG0Tja+X0/mJzX9tSfvIg==",
|
"integrity": "sha512-BiKB4RZ8YSwRKCNVdNxK/GfY+r4Kjgp9jCLEy0DuqAKfmQtpL38cQK3afdpjw4sqSs4PLi3jIPJIFp259NkZtA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {}
|
"requires": {}
|
||||||
},
|
},
|
||||||
"tailwindcss": {
|
"tailwindcss": {
|
||||||
"version": "3.3.2",
|
"version": "3.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.1.tgz",
|
||||||
"integrity": "sha512-9jPkMiIBXvPc2KywkraqsUfbfj+dHDb+JPWtSJa9MLFdrPyazI7q6WX2sUrm7R9eVR7qqv3Pas7EvQFzxKnI6w==",
|
"integrity": "sha512-Vkiouc41d4CEq0ujXl6oiGFQ7bA3WEhUZdTgXAhtKxSy49OmKs8rEfQmupsfF0IGW8fv2iQkp1EVUuapCFrZ9g==",
|
||||||
"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.18.2",
|
"jiti": "^1.17.2",
|
||||||
"lilconfig": "^2.1.0",
|
"lilconfig": "^2.0.6",
|
||||||
"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.4.23",
|
"postcss": "^8.0.9",
|
||||||
"postcss-import": "^15.1.0",
|
"postcss-import": "^14.1.0",
|
||||||
"postcss-js": "^4.0.1",
|
"postcss-js": "^4.0.0",
|
||||||
"postcss-load-config": "^4.0.1",
|
"postcss-load-config": "^3.1.4",
|
||||||
"postcss-nested": "^6.0.1",
|
"postcss-nested": "6.0.0",
|
||||||
"postcss-selector-parser": "^6.0.11",
|
"postcss-selector-parser": "^6.0.11",
|
||||||
"postcss-value-parser": "^4.2.0",
|
"postcss-value-parser": "^4.2.0",
|
||||||
"resolve": "^1.22.2",
|
"quick-lru": "^5.1.1",
|
||||||
"sucrase": "^3.32.0"
|
"resolve": "^1.22.1",
|
||||||
|
"sucrase": "^3.29.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"thenify": {
|
"thenify": {
|
||||||
@@ -3003,9 +2979,9 @@
|
|||||||
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
|
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
|
||||||
},
|
},
|
||||||
"vite": {
|
"vite": {
|
||||||
"version": "3.2.7",
|
"version": "3.2.6",
|
||||||
"resolved": "https://registry.npmjs.org/vite/-/vite-3.2.7.tgz",
|
"resolved": "https://registry.npmjs.org/vite/-/vite-3.2.6.tgz",
|
||||||
"integrity": "sha512-29pdXjk49xAP0QBr0xXqu2s5jiQIXNvE/xwd0vUizYT2Hzqe4BksNNoWllFVXJf4eLZ+UlVQmXfB4lWrc+t18g==",
|
"integrity": "sha512-nTXTxYVvaQNLoW5BQ8PNNQ3lPia57gzsQU/Khv+JvzKPku8kNZL6NMUR/qwXhMG6E+g1idqEPanomJ+VZgixEg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"esbuild": "^0.15.9",
|
"esbuild": "^0.15.9",
|
||||||
@@ -3028,9 +3004,9 @@
|
|||||||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
|
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
|
||||||
},
|
},
|
||||||
"yaml": {
|
"yaml": {
|
||||||
"version": "2.3.1",
|
"version": "1.10.2",
|
||||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
|
||||||
"integrity": "sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ=="
|
"integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg=="
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "creddy",
|
"name": "creddy",
|
||||||
"version": "0.2.3",
|
"version": "0.1.0",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
"build": "vite build",
|
"build": "vite build",
|
||||||
|
|||||||
+1
-1
@@ -1 +1 @@
|
|||||||
DATABASE_URL=sqlite://C:/Users/Joe/AppData/Roaming/creddy/creddy.dev.db
|
DATABASE_URL=sqlite://creddy.db?mode=rwc
|
||||||
Generated
+1058
-1788
File diff suppressed because it is too large.
Load diff
+6
-21
@@ -1,22 +1,14 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "creddy"
|
name = "app"
|
||||||
version = "0.2.3"
|
version = "0.1.0"
|
||||||
description = "A friendly AWS credentials manager"
|
description = "A Tauri App"
|
||||||
authors = ["Joseph Montanaro"]
|
authors = ["you"]
|
||||||
license = ""
|
license = ""
|
||||||
repository = ""
|
repository = ""
|
||||||
default-run = "creddy"
|
default-run = "app"
|
||||||
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]
|
||||||
@@ -25,8 +17,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.0.5", features = ["api-all", "system-tray"] }
|
||||||
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"] }
|
||||||
sqlx = { version = "0.6.2", features = ["sqlite", "runtime-tokio-rustls"] }
|
sqlx = { version = "0.6.2", features = ["sqlite", "runtime-tokio-rustls"] }
|
||||||
@@ -40,12 +31,6 @@ thiserror = "1.0.38"
|
|||||||
once_cell = "1.16.0"
|
once_cell = "1.16.0"
|
||||||
strum = "0.24"
|
strum = "0.24"
|
||||||
strum_macros = "0.24"
|
strum_macros = "0.24"
|
||||||
auto-launch = "0.4.0"
|
|
||||||
dirs = "5.0"
|
|
||||||
clap = { version = "3.2.23", features = ["derive"] }
|
|
||||||
is-terminal = "0.4.7"
|
|
||||||
argon2 = { version = "0.5.0", features = ["std"] }
|
|
||||||
chacha20poly1305 = { version = "0.10.1", features = ["std"] }
|
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
# by default Tauri runs in production mode
|
# by default Tauri runs in production mode
|
||||||
|
|||||||
@@ -1,22 +0,0 @@
|
|||||||
<?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>
|
|
||||||
@@ -8,7 +8,7 @@ CREATE TABLE credentials (
|
|||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE config (
|
CREATE TABLE config (
|
||||||
name TEXT UNIQUE NOT NULL,
|
name TEXT NOT NULL,
|
||||||
data TEXT NOT NULL
|
data TEXT NOT NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -1,92 +0,0 @@
|
|||||||
use std::error::Error;
|
|
||||||
|
|
||||||
use once_cell::sync::OnceCell;
|
|
||||||
use sqlx::{
|
|
||||||
SqlitePool,
|
|
||||||
sqlite::SqlitePoolOptions,
|
|
||||||
sqlite::SqliteConnectOptions,
|
|
||||||
};
|
|
||||||
use tauri::{
|
|
||||||
App,
|
|
||||||
AppHandle,
|
|
||||||
Manager,
|
|
||||||
async_runtime as rt,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
config::{self, AppConfig},
|
|
||||||
credentials::Session,
|
|
||||||
ipc,
|
|
||||||
server::Server,
|
|
||||||
errors::*,
|
|
||||||
state::AppState,
|
|
||||||
tray,
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
pub static APP: OnceCell<AppHandle> = OnceCell::new();
|
|
||||||
|
|
||||||
|
|
||||||
pub fn run() -> tauri::Result<()> {
|
|
||||||
tauri::Builder::default()
|
|
||||||
.plugin(tauri_plugin_single_instance::init(|app, _argv, _cwd| {
|
|
||||||
app.get_window("main")
|
|
||||||
.map(|w| w.show().error_popup("Failed to show main window"));
|
|
||||||
}))
|
|
||||||
.system_tray(tray::create())
|
|
||||||
.on_system_tray_event(tray::handle_event)
|
|
||||||
.invoke_handler(tauri::generate_handler![
|
|
||||||
ipc::unlock,
|
|
||||||
ipc::respond,
|
|
||||||
ipc::get_session_status,
|
|
||||||
ipc::save_credentials,
|
|
||||||
ipc::get_config,
|
|
||||||
ipc::save_config,
|
|
||||||
])
|
|
||||||
.setup(|app| rt::block_on(setup(app)))
|
|
||||||
.build(tauri::generate_context!())?
|
|
||||||
.run(|app, run_event| match run_event {
|
|
||||||
tauri::RunEvent::WindowEvent { label, event, .. } => match event {
|
|
||||||
tauri::WindowEvent::CloseRequested { api, .. } => {
|
|
||||||
let _ = app.get_window(&label).map(|w| w.hide());
|
|
||||||
api.prevent_close();
|
|
||||||
}
|
|
||||||
_ => ()
|
|
||||||
}
|
|
||||||
_ => ()
|
|
||||||
});
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
pub async fn connect_db() -> Result<SqlitePool, SetupError> {
|
|
||||||
let conn_opts = SqliteConnectOptions::new()
|
|
||||||
.filename(config::get_or_create_db_path()?)
|
|
||||||
.create_if_missing(true);
|
|
||||||
let pool_opts = SqlitePoolOptions::new();
|
|
||||||
let pool: SqlitePool = pool_opts.connect_with(conn_opts).await?;
|
|
||||||
sqlx::migrate!().run(&pool).await?;
|
|
||||||
Ok(pool)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
async fn setup(app: &mut App) -> Result<(), Box<dyn Error>> {
|
|
||||||
APP.set(app.handle()).unwrap();
|
|
||||||
|
|
||||||
let pool = connect_db().await?;
|
|
||||||
let conf = AppConfig::load(&pool).await?;
|
|
||||||
let session = Session::load(&pool).await?;
|
|
||||||
let srv = Server::new(conf.listen_addr, conf.listen_port, app.handle()).await?;
|
|
||||||
|
|
||||||
config::set_auto_launch(conf.start_on_login)?;
|
|
||||||
if !conf.start_minimized {
|
|
||||||
app.get_window("main")
|
|
||||||
.ok_or(HandlerError::NoMainWindow)?
|
|
||||||
.show()?;
|
|
||||||
}
|
|
||||||
|
|
||||||
let state = AppState::new(conf, session, srv, pool);
|
|
||||||
app.manage(state);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
// 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,146 +0,0 @@
|
|||||||
use std::process::Command as ChildCommand;
|
|
||||||
#[cfg(unix)]
|
|
||||||
use std::os::unix::process::CommandExt;
|
|
||||||
|
|
||||||
use clap::{
|
|
||||||
Command,
|
|
||||||
Arg,
|
|
||||||
ArgMatches,
|
|
||||||
ArgAction
|
|
||||||
};
|
|
||||||
use tokio::{
|
|
||||||
net::TcpStream,
|
|
||||||
io::{AsyncReadExt, AsyncWriteExt},
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
use crate::app;
|
|
||||||
use crate::config::AppConfig;
|
|
||||||
use crate::credentials::{BaseCredentials, SessionCredentials};
|
|
||||||
use crate::errors::*;
|
|
||||||
|
|
||||||
|
|
||||||
pub fn parser() -> Command<'static> {
|
|
||||||
Command::new("creddy")
|
|
||||||
.about("A friendly AWS credentials manager")
|
|
||||||
.subcommand(
|
|
||||||
Command::new("run")
|
|
||||||
.about("Launch Creddy")
|
|
||||||
)
|
|
||||||
.subcommand(
|
|
||||||
Command::new("show")
|
|
||||||
.about("Fetch and display AWS credentials")
|
|
||||||
.arg(
|
|
||||||
Arg::new("base")
|
|
||||||
.short('b')
|
|
||||||
.long("base")
|
|
||||||
.action(ArgAction::SetTrue)
|
|
||||||
.help("Use base credentials instead of session credentials")
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.subcommand(
|
|
||||||
Command::new("exec")
|
|
||||||
.about("Inject AWS credentials into the environment of another command")
|
|
||||||
.trailing_var_arg(true)
|
|
||||||
.arg(
|
|
||||||
Arg::new("base")
|
|
||||||
.short('b')
|
|
||||||
.long("base")
|
|
||||||
.action(ArgAction::SetTrue)
|
|
||||||
.help("Use base credentials instead of session credentials")
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::new("command")
|
|
||||||
.multiple_values(true)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
pub fn show(args: &ArgMatches) -> Result<(), CliError> {
|
|
||||||
let base = args.get_one("base").unwrap_or(&false);
|
|
||||||
let creds = get_credentials(*base)?;
|
|
||||||
println!("{creds}");
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
pub fn exec(args: &ArgMatches) -> Result<(), CliError> {
|
|
||||||
let base = *args.get_one("base").unwrap_or(&false);
|
|
||||||
let mut cmd_line = args.get_many("command")
|
|
||||||
.ok_or(ExecError::NoCommand)?;
|
|
||||||
|
|
||||||
let cmd_name: &String = cmd_line.next().unwrap(); // Clap guarantees that there will be at least one
|
|
||||||
let mut cmd = ChildCommand::new(cmd_name);
|
|
||||||
cmd.args(cmd_line);
|
|
||||||
|
|
||||||
if base {
|
|
||||||
let creds: BaseCredentials = serde_json::from_str(&get_credentials(base)?)
|
|
||||||
.map_err(|_| RequestError::InvalidJson)?;
|
|
||||||
cmd.env("AWS_ACCESS_KEY_ID", creds.access_key_id);
|
|
||||||
cmd.env("AWS_SECRET_ACCESS_KEY", creds.secret_access_key);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
let creds: SessionCredentials = serde_json::from_str(&get_credentials(base)?)
|
|
||||||
.map_err(|_| RequestError::InvalidJson)?;
|
|
||||||
cmd.env("AWS_ACCESS_KEY_ID", creds.access_key_id);
|
|
||||||
cmd.env("AWS_SECRET_ACCESS_KEY", creds.secret_access_key);
|
|
||||||
cmd.env("AWS_SESSION_TOKEN", creds.token);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(unix)]
|
|
||||||
{
|
|
||||||
let e = cmd.exec(); // never returns if successful
|
|
||||||
Err(ExecError::ExecutionFailed(e))?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(windows)]
|
|
||||||
{
|
|
||||||
let mut child = cmd.spawn()
|
|
||||||
.map_err(|e| ExecError::ExecutionFailed(e))?;
|
|
||||||
let status = child.wait()
|
|
||||||
.map_err(|e| ExecError::ExecutionFailed(e))?;
|
|
||||||
std::process::exit(status.code().unwrap_or(1));
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#[tokio::main]
|
|
||||||
async fn get_credentials(base: bool) -> Result<String, RequestError> {
|
|
||||||
let pool = app::connect_db().await?;
|
|
||||||
let config = AppConfig::load(&pool).await?;
|
|
||||||
let path = if base {"/creddy/base-credentials"} else {"/"};
|
|
||||||
|
|
||||||
let mut stream = TcpStream::connect((config.listen_addr, config.listen_port)).await?;
|
|
||||||
let req = format!("GET {path} HTTP/1.0\r\n\r\n");
|
|
||||||
stream.write_all(req.as_bytes()).await?;
|
|
||||||
|
|
||||||
// some day we'll have a proper HTTP parser
|
|
||||||
let mut buf = vec![0; 8192];
|
|
||||||
stream.read_to_end(&mut buf).await?;
|
|
||||||
|
|
||||||
let status = buf.split(|&c| &[c] == b" ")
|
|
||||||
.skip(1)
|
|
||||||
.next()
|
|
||||||
.ok_or(RequestError::MalformedHttpResponse)?;
|
|
||||||
|
|
||||||
if status != b"200" {
|
|
||||||
let s = String::from_utf8_lossy(status).to_string();
|
|
||||||
return Err(RequestError::Failed(s));
|
|
||||||
}
|
|
||||||
|
|
||||||
let break_idx = buf.windows(4)
|
|
||||||
.position(|w| w == b"\r\n\r\n")
|
|
||||||
.ok_or(RequestError::MalformedHttpResponse)?;
|
|
||||||
let body = &buf[(break_idx + 4)..];
|
|
||||||
|
|
||||||
let creds_str = std::str::from_utf8(body)
|
|
||||||
.map_err(|_| RequestError::MalformedHttpResponse)?
|
|
||||||
.to_string();
|
|
||||||
|
|
||||||
if creds_str == "Denied!" {
|
|
||||||
return Err(RequestError::Rejected);
|
|
||||||
}
|
|
||||||
Ok(creds_str)
|
|
||||||
}
|
|
||||||
+12
-24
@@ -1,37 +1,25 @@
|
|||||||
use std::path::PathBuf;
|
|
||||||
|
|
||||||
use netstat2::{AddressFamilyFlags, ProtocolFlags, ProtocolSocketInfo};
|
use netstat2::{AddressFamilyFlags, ProtocolFlags, ProtocolSocketInfo};
|
||||||
use tauri::Manager;
|
|
||||||
use sysinfo::{System, SystemExt, Pid, PidExt, ProcessExt};
|
use sysinfo::{System, SystemExt, Pid, PidExt, ProcessExt};
|
||||||
use serde::{Serialize, Deserialize};
|
use serde::{Serialize, Deserialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::errors::*;
|
||||||
app::APP,
|
use crate::get_state;
|
||||||
errors::*,
|
|
||||||
config::AppConfig,
|
|
||||||
state::AppState,
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Hash)]
|
#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Hash)]
|
||||||
pub struct Client {
|
pub struct Client {
|
||||||
pub pid: u32,
|
pub pid: u32,
|
||||||
pub exe: PathBuf,
|
pub exe: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async fn get_associated_pids(local_port: u16) -> Result<Vec<u32>, netstat2::error::Error> {
|
fn get_associated_pids(local_port: u16) -> Result<Vec<u32>, netstat2::error::Error> {
|
||||||
let state = APP.get().unwrap().state::<AppState>();
|
|
||||||
let AppConfig {
|
|
||||||
listen_addr: app_listen_addr,
|
|
||||||
listen_port: app_listen_port,
|
|
||||||
..
|
|
||||||
} = *state.config.read().await;
|
|
||||||
|
|
||||||
let sockets_iter = netstat2::iterate_sockets_info(
|
let sockets_iter = netstat2::iterate_sockets_info(
|
||||||
AddressFamilyFlags::IPV4,
|
AddressFamilyFlags::IPV4,
|
||||||
ProtocolFlags::TCP
|
ProtocolFlags::TCP
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
get_state!(config as app_config);
|
||||||
for item in sockets_iter {
|
for item in sockets_iter {
|
||||||
let sock_info = item?;
|
let sock_info = item?;
|
||||||
let proto_info = match sock_info.protocol_socket_info {
|
let proto_info = match sock_info.protocol_socket_info {
|
||||||
@@ -40,9 +28,9 @@ async fn get_associated_pids(local_port: u16) -> Result<Vec<u32>, netstat2::erro
|
|||||||
};
|
};
|
||||||
|
|
||||||
if proto_info.local_port == local_port
|
if proto_info.local_port == local_port
|
||||||
&& proto_info.remote_port == app_listen_port
|
&& proto_info.remote_port == app_config.listen_port
|
||||||
&& proto_info.local_addr == app_listen_addr
|
&& proto_info.local_addr == app_config.listen_addr
|
||||||
&& proto_info.remote_addr == app_listen_addr
|
&& proto_info.remote_addr == app_config.listen_addr
|
||||||
{
|
{
|
||||||
return Ok(sock_info.associated_pids)
|
return Ok(sock_info.associated_pids)
|
||||||
}
|
}
|
||||||
@@ -52,10 +40,10 @@ async fn get_associated_pids(local_port: u16) -> Result<Vec<u32>, netstat2::erro
|
|||||||
|
|
||||||
|
|
||||||
// Theoretically, on some systems, multiple processes can share a socket
|
// Theoretically, on some systems, multiple processes can share a socket
|
||||||
pub async fn get_clients(local_port: u16) -> Result<Vec<Option<Client>>, ClientInfoError> {
|
pub fn get_clients(local_port: u16) -> Result<Vec<Option<Client>>, ClientInfoError> {
|
||||||
let mut clients = Vec::new();
|
let mut clients = Vec::new();
|
||||||
let mut sys = System::new();
|
let mut sys = System::new();
|
||||||
for p in get_associated_pids(local_port).await? {
|
for p in get_associated_pids(local_port)? {
|
||||||
let pid = Pid::from_u32(p);
|
let pid = Pid::from_u32(p);
|
||||||
sys.refresh_process(pid);
|
sys.refresh_process(pid);
|
||||||
let proc = sys.process(pid)
|
let proc = sys.process(pid)
|
||||||
@@ -63,7 +51,7 @@ pub async fn get_clients(local_port: u16) -> Result<Vec<Option<Client>>, ClientI
|
|||||||
|
|
||||||
let client = Client {
|
let client = Client {
|
||||||
pid: p,
|
pid: p,
|
||||||
exe: proc.exe().to_path_buf(),
|
exe: proc.exe().to_string_lossy().into_owned(),
|
||||||
};
|
};
|
||||||
clients.push(Some(client));
|
clients.push(Some(client));
|
||||||
}
|
}
|
||||||
|
|||||||
+15
-58
@@ -1,8 +1,6 @@
|
|||||||
use std::net::Ipv4Addr;
|
use std::net::Ipv4Addr;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use auto_launch::AutoLaunchBuilder;
|
|
||||||
use is_terminal::IsTerminal;
|
|
||||||
use serde::{Serialize, Deserialize};
|
use serde::{Serialize, Deserialize};
|
||||||
use sqlx::SqlitePool;
|
use sqlx::SqlitePool;
|
||||||
|
|
||||||
@@ -19,8 +17,6 @@ pub struct AppConfig {
|
|||||||
pub rehide_ms: u64,
|
pub rehide_ms: u64,
|
||||||
#[serde(default = "default_start_minimized")]
|
#[serde(default = "default_start_minimized")]
|
||||||
pub start_minimized: bool,
|
pub start_minimized: bool,
|
||||||
#[serde(default = "default_start_on_login")]
|
|
||||||
pub start_on_login: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -31,13 +27,11 @@ impl Default for AppConfig {
|
|||||||
listen_port: default_listen_port(),
|
listen_port: default_listen_port(),
|
||||||
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(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl AppConfig {
|
|
||||||
pub async fn load(pool: &SqlitePool) -> Result<AppConfig, SetupError> {
|
pub async fn load(pool: &SqlitePool) -> Result<AppConfig, SetupError> {
|
||||||
let res = sqlx::query!("SELECT * from config where name = 'main'")
|
let res = sqlx::query!("SELECT * from config where name = 'main'")
|
||||||
.fetch_optional(pool)
|
.fetch_optional(pool)
|
||||||
@@ -51,59 +45,22 @@ impl AppConfig {
|
|||||||
Ok(serde_json::from_str(&row.data)?)
|
Ok(serde_json::from_str(&row.data)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn save(&self, pool: &SqlitePool) -> Result<(), sqlx::error::Error> {
|
|
||||||
let data = serde_json::to_string(self).unwrap();
|
|
||||||
sqlx::query(
|
|
||||||
"INSERT INTO config (name, data) VALUES ('main', ?)
|
|
||||||
ON CONFLICT (name) DO UPDATE SET data = ?"
|
|
||||||
)
|
|
||||||
.bind(&data)
|
|
||||||
.bind(&data)
|
|
||||||
.execute(pool)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
Ok(())
|
pub fn get_or_create_db_path() -> PathBuf {
|
||||||
}
|
if cfg!(debug_assertions) {
|
||||||
|
return PathBuf::from("./creddy.db");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut parent = std::env::var("HOME")
|
||||||
|
.map(|h| {
|
||||||
|
let mut p = PathBuf::from(h);
|
||||||
|
p.push(".config");
|
||||||
|
p
|
||||||
|
})
|
||||||
|
.unwrap_or(PathBuf::from("."));
|
||||||
|
|
||||||
pub fn set_auto_launch(is_configured: bool) -> Result<(), SetupError> {
|
parent.push("creddy.db");
|
||||||
let path_buf = std::env::current_exe()
|
parent
|
||||||
.map_err(|e| auto_launch::Error::Io(e))?;
|
|
||||||
let path = path_buf
|
|
||||||
.to_string_lossy();
|
|
||||||
|
|
||||||
let auto = AutoLaunchBuilder::new()
|
|
||||||
.set_app_name("Creddy")
|
|
||||||
.set_app_path(&path)
|
|
||||||
.build()?;
|
|
||||||
|
|
||||||
let is_enabled = auto.is_enabled()?;
|
|
||||||
if is_configured && !is_enabled {
|
|
||||||
auto.enable()?;
|
|
||||||
}
|
|
||||||
else if !is_configured && is_enabled {
|
|
||||||
auto.disable()?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
pub fn get_or_create_db_path() -> Result<PathBuf, DataDirError> {
|
|
||||||
let mut path = dirs::data_dir()
|
|
||||||
.ok_or(DataDirError::NotFound)?;
|
|
||||||
path.push("Creddy");
|
|
||||||
|
|
||||||
std::fs::create_dir_all(&path)?;
|
|
||||||
if cfg!(debug_assertions) && std::io::stdout().is_terminal() {
|
|
||||||
path.push("creddy.dev.db");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
path.push("creddy.db");
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(path)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -117,7 +74,7 @@ fn default_listen_port() -> u16 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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
|
|
||||||
fn default_start_minimized() -> bool { !cfg!(debug_assertions) }
|
fn default_start_minimized() -> bool { !cfg!(debug_assertions) } // default to start-minimized in production only
|
||||||
fn default_start_on_login() -> bool { !cfg!(debug_assertions) }
|
|
||||||
@@ -1,321 +0,0 @@
|
|||||||
use std::fmt::{self, Formatter};
|
|
||||||
use std::time::{SystemTime, UNIX_EPOCH};
|
|
||||||
|
|
||||||
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::{
|
|
||||||
Serialize,
|
|
||||||
Deserialize,
|
|
||||||
Serializer,
|
|
||||||
Deserializer,
|
|
||||||
};
|
|
||||||
use serde::de::{self, Visitor};
|
|
||||||
use sqlx::SqlitePool;
|
|
||||||
|
|
||||||
|
|
||||||
use crate::errors::*;
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub enum Session {
|
|
||||||
Unlocked{
|
|
||||||
base: BaseCredentials,
|
|
||||||
session: SessionCredentials,
|
|
||||||
},
|
|
||||||
Locked(LockedCredentials),
|
|
||||||
Empty,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Session {
|
|
||||||
pub async fn load(pool: &SqlitePool) -> Result<Self, SetupError> {
|
|
||||||
let res = sqlx::query!("SELECT * FROM credentials ORDER BY created_at desc")
|
|
||||||
.fetch_optional(pool)
|
|
||||||
.await?;
|
|
||||||
let row = match res {
|
|
||||||
Some(r) => r,
|
|
||||||
None => {return Ok(Session::Empty);}
|
|
||||||
};
|
|
||||||
|
|
||||||
let salt: [u8; 32] = row.salt
|
|
||||||
.try_into()
|
|
||||||
.map_err(|_e| SetupError::InvalidRecord)?;
|
|
||||||
let nonce = XNonce::from_exact_iter(row.nonce.into_iter())
|
|
||||||
.ok_or(SetupError::InvalidRecord)?;
|
|
||||||
|
|
||||||
let creds = LockedCredentials {
|
|
||||||
access_key_id: row.access_key_id,
|
|
||||||
secret_key_enc: row.secret_key_enc,
|
|
||||||
salt,
|
|
||||||
nonce,
|
|
||||||
};
|
|
||||||
Ok(Session::Locked(creds))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn renew_if_expired(&mut self) -> Result<bool, GetSessionError> {
|
|
||||||
match self {
|
|
||||||
Session::Unlocked{ref base, ref mut session} => {
|
|
||||||
if !session.is_expired() {
|
|
||||||
return Ok(false);
|
|
||||||
}
|
|
||||||
*session = SessionCredentials::from_base(base).await?;
|
|
||||||
Ok(true)
|
|
||||||
},
|
|
||||||
Session::Locked(_) => Err(GetSessionError::CredentialsLocked),
|
|
||||||
Session::Empty => Err(GetSessionError::CredentialsEmpty),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub struct LockedCredentials {
|
|
||||||
pub access_key_id: String,
|
|
||||||
pub secret_key_enc: Vec<u8>,
|
|
||||||
pub salt: [u8; 32],
|
|
||||||
pub nonce: XNonce,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl LockedCredentials {
|
|
||||||
pub async fn save(&self, pool: &SqlitePool) -> Result<(), sqlx::Error> {
|
|
||||||
sqlx::query(
|
|
||||||
"INSERT INTO credentials (access_key_id, secret_key_enc, salt, nonce, created_at)
|
|
||||||
VALUES (?, ?, ?, ?, strftime('%s'))"
|
|
||||||
)
|
|
||||||
.bind(&self.access_key_id)
|
|
||||||
.bind(&self.secret_key_enc)
|
|
||||||
.bind(&self.salt[..])
|
|
||||||
.bind(&self.nonce[..])
|
|
||||||
.execute(pool)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn decrypt(&self, passphrase: &str) -> Result<BaseCredentials, UnlockError> {
|
|
||||||
let crypto = Crypto::new(passphrase, &self.salt)
|
|
||||||
.map_err(|e| CryptoError::Argon2(e))?;
|
|
||||||
let decrypted = crypto.decrypt(&self.nonce, &self.secret_key_enc)
|
|
||||||
.map_err(|e| CryptoError::Aead(e))?;
|
|
||||||
let secret_access_key = String::from_utf8(decrypted)
|
|
||||||
.map_err(|_| UnlockError::InvalidUtf8)?;
|
|
||||||
|
|
||||||
let creds = BaseCredentials {
|
|
||||||
access_key_id: self.access_key_id.clone(),
|
|
||||||
secret_access_key,
|
|
||||||
};
|
|
||||||
Ok(creds)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
|
||||||
#[serde(rename_all = "PascalCase")]
|
|
||||||
pub struct BaseCredentials {
|
|
||||||
pub access_key_id: String,
|
|
||||||
pub secret_access_key: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BaseCredentials {
|
|
||||||
pub fn encrypt(&self, passphrase: &str) -> Result<LockedCredentials, CryptoError> {
|
|
||||||
let salt = Crypto::salt();
|
|
||||||
let crypto = Crypto::new(passphrase, &salt)?;
|
|
||||||
let (nonce, secret_key_enc) = crypto.encrypt(self.secret_access_key.as_bytes())?;
|
|
||||||
|
|
||||||
let locked = LockedCredentials {
|
|
||||||
access_key_id: self.access_key_id.clone(),
|
|
||||||
secret_key_enc,
|
|
||||||
salt,
|
|
||||||
nonce,
|
|
||||||
};
|
|
||||||
Ok(locked)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
|
||||||
#[serde(rename_all = "PascalCase")]
|
|
||||||
pub struct SessionCredentials {
|
|
||||||
pub access_key_id: String,
|
|
||||||
pub secret_access_key: String,
|
|
||||||
pub token: String,
|
|
||||||
#[serde(serialize_with = "serialize_expiration")]
|
|
||||||
#[serde(deserialize_with = "deserialize_expiration")]
|
|
||||||
pub expiration: DateTime,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SessionCredentials {
|
|
||||||
pub async fn from_base(base: &BaseCredentials) -> Result<Self, GetSessionError> {
|
|
||||||
let req_creds = aws_sdk_sts::Credentials::new(
|
|
||||||
&base.access_key_id,
|
|
||||||
&base.secret_access_key,
|
|
||||||
None, // token
|
|
||||||
None, //expiration
|
|
||||||
"Creddy", // "provider name" apparently
|
|
||||||
);
|
|
||||||
let config = aws_config::from_env()
|
|
||||||
.credentials_provider(req_creds)
|
|
||||||
.load()
|
|
||||||
.await;
|
|
||||||
|
|
||||||
let client = aws_sdk_sts::Client::new(&config);
|
|
||||||
let resp = client.get_session_token()
|
|
||||||
.duration_seconds(43_200)
|
|
||||||
.send()
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
let aws_session = resp.credentials().ok_or(GetSessionError::EmptyResponse)?;
|
|
||||||
|
|
||||||
let access_key_id = aws_session.access_key_id()
|
|
||||||
.ok_or(GetSessionError::EmptyResponse)?
|
|
||||||
.to_string();
|
|
||||||
let secret_access_key = aws_session.secret_access_key()
|
|
||||||
.ok_or(GetSessionError::EmptyResponse)?
|
|
||||||
.to_string();
|
|
||||||
let token = aws_session.session_token()
|
|
||||||
.ok_or(GetSessionError::EmptyResponse)?
|
|
||||||
.to_string();
|
|
||||||
let expiration = aws_session.expiration()
|
|
||||||
.ok_or(GetSessionError::EmptyResponse)?
|
|
||||||
.clone();
|
|
||||||
|
|
||||||
let session_creds = SessionCredentials {
|
|
||||||
access_key_id,
|
|
||||||
secret_access_key,
|
|
||||||
token,
|
|
||||||
expiration,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
println!("Got new session:\n{}", serde_json::to_string(&session_creds).unwrap());
|
|
||||||
|
|
||||||
Ok(session_creds)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_expired(&self) -> bool {
|
|
||||||
let current_ts = SystemTime::now()
|
|
||||||
.duration_since(UNIX_EPOCH)
|
|
||||||
.unwrap() // doesn't panic because UNIX_EPOCH won't be later than now()
|
|
||||||
.as_secs();
|
|
||||||
|
|
||||||
let expire_ts = self.expiration.secs();
|
|
||||||
let remaining = expire_ts - (current_ts as i64);
|
|
||||||
remaining < 60
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn serialize_expiration<S>(exp: &DateTime, serializer: S) -> Result<S::Ok, S::Error>
|
|
||||||
where S: Serializer
|
|
||||||
{
|
|
||||||
// this only fails if the d/t is out of range, which it can't be for this format
|
|
||||||
let time_str = exp.fmt(Format::DateTime).unwrap();
|
|
||||||
serializer.serialize_str(&time_str)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
struct DateTimeVisitor;
|
|
||||||
|
|
||||||
impl<'de> Visitor<'de> for DateTimeVisitor {
|
|
||||||
type Value = DateTime;
|
|
||||||
|
|
||||||
fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
|
|
||||||
write!(formatter, "an RFC 3339 UTC string, e.g. \"2014-01-05T10:17:34Z\"")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_str<E: de::Error>(self, v: &str) -> Result<DateTime, E> {
|
|
||||||
DateTime::from_str(v, Format::DateTime)
|
|
||||||
.map_err(|_| E::custom(format!("Invalid date/time: {v}")))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fn deserialize_expiration<'de, D>(deserializer: D) -> Result<DateTime, D::Error>
|
|
||||||
where D: Deserializer<'de>
|
|
||||||
{
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+33
-115
@@ -1,9 +1,9 @@
|
|||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::convert::AsRef;
|
use std::convert::AsRef;
|
||||||
use std::sync::mpsc;
|
|
||||||
use strum_macros::AsRefStr;
|
use strum_macros::AsRefStr;
|
||||||
|
|
||||||
use thiserror::Error as ThisError;
|
use thiserror::Error as ThisError;
|
||||||
|
|
||||||
use aws_sdk_sts::{
|
use aws_sdk_sts::{
|
||||||
types::SdkError as AwsSdkError,
|
types::SdkError as AwsSdkError,
|
||||||
error::GetSessionTokenError,
|
error::GetSessionTokenError,
|
||||||
@@ -12,29 +12,32 @@ use sqlx::{
|
|||||||
error::Error as SqlxError,
|
error::Error as SqlxError,
|
||||||
migrate::MigrateError,
|
migrate::MigrateError,
|
||||||
};
|
};
|
||||||
use tauri::api::dialog::{
|
|
||||||
MessageDialogBuilder,
|
|
||||||
MessageDialogKind,
|
|
||||||
};
|
|
||||||
use serde::{Serialize, Serializer, ser::SerializeMap};
|
use serde::{Serialize, Serializer, ser::SerializeMap};
|
||||||
|
|
||||||
|
|
||||||
pub trait ErrorPopup {
|
// pub struct SerializeError<E> {
|
||||||
fn error_popup(self, title: &str);
|
// pub err: E,
|
||||||
}
|
// }
|
||||||
|
|
||||||
impl<E: Error> ErrorPopup for Result<(), E> {
|
// impl<E: std::error::Error> Serialize for SerializeError<E>
|
||||||
fn error_popup(self, title: &str) {
|
// {
|
||||||
if let Err(e) = self {
|
// fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||||
let (tx, rx) = mpsc::channel();
|
// let mut map = serializer.serialize_map(None)?;
|
||||||
MessageDialogBuilder::new(title, format!("{e}"))
|
// map.serialize_entry("msg", &format!("{}", self.err))?;
|
||||||
.kind(MessageDialogKind::Error)
|
// if let Some(src) = self.err.source() {
|
||||||
.show(move |_| tx.send(true).unwrap());
|
// let ser_src = SerializeError { err: src };
|
||||||
|
// map.serialize_entry("source", &ser_src)?;
|
||||||
|
// }
|
||||||
|
// map.end()
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
rx.recv().unwrap();
|
// impl<E: std::error::Error> From<E> for SerializeError<E> {
|
||||||
}
|
// fn from(err: E) -> Self {
|
||||||
}
|
// SerializeError { err }
|
||||||
}
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
fn serialize_basic_err<E, S>(err: &E, serializer: S) -> Result<S::Ok, S::Error>
|
fn serialize_basic_err<E, S>(err: &E, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
@@ -84,21 +87,6 @@ pub enum SetupError {
|
|||||||
MigrationError(#[from] MigrateError),
|
MigrationError(#[from] MigrateError),
|
||||||
#[error("Error parsing configuration from database")]
|
#[error("Error parsing configuration from database")]
|
||||||
ConfigParseError(#[from] serde_json::Error),
|
ConfigParseError(#[from] serde_json::Error),
|
||||||
#[error("Failed to set up start-on-login: {0}")]
|
|
||||||
AutoLaunchError(#[from] auto_launch::Error),
|
|
||||||
#[error("Failed to start listener: {0}")]
|
|
||||||
ServerSetupError(#[from] std::io::Error),
|
|
||||||
#[error("Failed to resolve data directory: {0}")]
|
|
||||||
DataDir(#[from] DataDirError),
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, ThisError, AsRefStr)]
|
|
||||||
pub enum DataDirError {
|
|
||||||
#[error("Could not determine data directory")]
|
|
||||||
NotFound,
|
|
||||||
#[error("Failed to create data directory: {0}")]
|
|
||||||
Io(#[from] std::io::Error),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -106,23 +94,20 @@ pub enum DataDirError {
|
|||||||
#[derive(Debug, ThisError, AsRefStr)]
|
#[derive(Debug, ThisError, AsRefStr)]
|
||||||
pub enum SendResponseError {
|
pub enum SendResponseError {
|
||||||
#[error("The specified credentials request was not found")]
|
#[error("The specified credentials request was not found")]
|
||||||
NotFound,
|
NotFound, // no request with the given id
|
||||||
#[error("The specified request was already closed by the client")]
|
#[error("The specified request was already closed by the client")]
|
||||||
Abandoned,
|
Abandoned, // request has already been closed by client
|
||||||
#[error("Could not renew AWS sesssion: {0}")]
|
|
||||||
SessionRenew(#[from] GetSessionError),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// errors encountered while handling an HTTP request
|
// errors encountered while handling an HTTP request
|
||||||
#[derive(Debug, ThisError, AsRefStr)]
|
#[derive(Debug, ThisError, AsRefStr)]
|
||||||
pub enum HandlerError {
|
pub enum RequestError {
|
||||||
#[error("Error writing to stream: {0}")]
|
#[error("Error writing to stream: {0}")]
|
||||||
StreamIOError(#[from] std::io::Error),
|
StreamIOError(#[from] std::io::Error),
|
||||||
// #[error("Received invalid UTF-8 in request")]
|
// #[error("Received invalid UTF-8 in request")]
|
||||||
// InvalidUtf8,
|
// InvalidUtf8,
|
||||||
#[error("HTTP request malformed")]
|
// MalformedHttpRequest,
|
||||||
BadRequest(Vec<u8>),
|
|
||||||
#[error("HTTP request too large")]
|
#[error("HTTP request too large")]
|
||||||
RequestTooLarge,
|
RequestTooLarge,
|
||||||
#[error("Error accessing credentials: {0}")]
|
#[error("Error accessing credentials: {0}")]
|
||||||
@@ -148,13 +133,9 @@ pub enum GetCredentialsError {
|
|||||||
#[derive(Debug, ThisError, AsRefStr)]
|
#[derive(Debug, ThisError, AsRefStr)]
|
||||||
pub enum GetSessionError {
|
pub enum GetSessionError {
|
||||||
#[error("Request completed successfully but no credentials were returned")]
|
#[error("Request completed successfully but no credentials were returned")]
|
||||||
EmptyResponse, // SDK returned successfully but credentials are None
|
NoCredentials, // SDK returned successfully but credentials are None
|
||||||
#[error("Error response from AWS SDK: {0}")]
|
#[error("Error response from AWS SDK: {0}")]
|
||||||
SdkError(#[from] AwsSdkError<GetSessionTokenError>),
|
SdkError(#[from] AwsSdkError<GetSessionTokenError>),
|
||||||
#[error("Could not construt session: credentials are locked")]
|
|
||||||
CredentialsLocked,
|
|
||||||
#[error("Could not construct session: no credentials are known")]
|
|
||||||
CredentialsEmpty,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -164,8 +145,8 @@ pub enum UnlockError {
|
|||||||
NotLocked,
|
NotLocked,
|
||||||
#[error("No saved credentials were found")]
|
#[error("No saved credentials were found")]
|
||||||
NoCredentials,
|
NoCredentials,
|
||||||
#[error(transparent)]
|
#[error("Invalid passphrase")]
|
||||||
Crypto(#[from] CryptoError),
|
BadPassphrase,
|
||||||
#[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,15 +156,6 @@ 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 {
|
||||||
@@ -194,45 +166,6 @@ pub enum ClientInfoError {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Errors encountered while requesting credentials via CLI (creddy show, creddy exec)
|
|
||||||
#[derive(Debug, ThisError, AsRefStr)]
|
|
||||||
pub enum RequestError {
|
|
||||||
#[error("Credentials request failed: HTTP {0}")]
|
|
||||||
Failed(String),
|
|
||||||
#[error("Credentials request was rejected")]
|
|
||||||
Rejected,
|
|
||||||
#[error("Couldn't interpret the server's response")]
|
|
||||||
MalformedHttpResponse,
|
|
||||||
#[error("The server did not respond with valid JSON")]
|
|
||||||
InvalidJson,
|
|
||||||
#[error("Error reading/writing stream: {0}")]
|
|
||||||
StreamIOError(#[from] std::io::Error),
|
|
||||||
#[error("Error loading configuration data: {0}")]
|
|
||||||
Setup(#[from] SetupError),
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// 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)]
|
|
||||||
pub enum CliError {
|
|
||||||
#[error(transparent)]
|
|
||||||
Request(#[from] RequestError),
|
|
||||||
#[error(transparent)]
|
|
||||||
Exec(#[from] ExecError),
|
|
||||||
#[error(transparent)]
|
|
||||||
Io(#[from] std::io::Error),
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// =========================
|
// =========================
|
||||||
// Serialize implementations
|
// Serialize implementations
|
||||||
// =========================
|
// =========================
|
||||||
@@ -254,35 +187,20 @@ impl Serialize for SerializeWrapper<&GetSessionTokenError> {
|
|||||||
|
|
||||||
|
|
||||||
impl_serialize_basic!(SetupError);
|
impl_serialize_basic!(SetupError);
|
||||||
|
impl_serialize_basic!(SendResponseError);
|
||||||
impl_serialize_basic!(GetCredentialsError);
|
impl_serialize_basic!(GetCredentialsError);
|
||||||
impl_serialize_basic!(ClientInfoError);
|
impl_serialize_basic!(ClientInfoError);
|
||||||
|
|
||||||
|
|
||||||
impl Serialize for HandlerError {
|
impl Serialize for RequestError {
|
||||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||||
let mut map = serializer.serialize_map(None)?;
|
let mut map = serializer.serialize_map(None)?;
|
||||||
map.serialize_entry("code", self.as_ref())?;
|
map.serialize_entry("code", self.as_ref())?;
|
||||||
map.serialize_entry("msg", &format!("{self}"))?;
|
map.serialize_entry("msg", &format!("{self}"))?;
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
HandlerError::NoCredentials(src) => map.serialize_entry("source", &src)?,
|
RequestError::NoCredentials(src) => map.serialize_entry("source", &src)?,
|
||||||
HandlerError::ClientInfo(src) => map.serialize_entry("source", &src)?,
|
RequestError::ClientInfo(src) => map.serialize_entry("source", &src)?,
|
||||||
_ => serialize_upstream_err(self, &mut map)?,
|
|
||||||
}
|
|
||||||
|
|
||||||
map.end()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
impl Serialize for SendResponseError {
|
|
||||||
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 {
|
|
||||||
SendResponseError::SessionRenew(src) => map.serialize_entry("source", &src)?,
|
|
||||||
_ => serialize_upstream_err(self, &mut map)?,
|
_ => serialize_upstream_err(self, &mut map)?,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+19
-23
@@ -1,18 +1,16 @@
|
|||||||
use serde::{Serialize, Deserialize};
|
use serde::{Serialize, Deserialize};
|
||||||
use tauri::State;
|
use tauri::State;
|
||||||
|
|
||||||
use crate::config::AppConfig;
|
|
||||||
use crate::credentials::{Session,BaseCredentials};
|
|
||||||
use crate::errors::*;
|
use crate::errors::*;
|
||||||
|
use crate::config::AppConfig;
|
||||||
use crate::clientinfo::Client;
|
use crate::clientinfo::Client;
|
||||||
use crate::state::AppState;
|
use crate::state::{AppState, Session, Credentials};
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
pub struct Request {
|
pub struct Request {
|
||||||
pub id: u64,
|
pub id: u64,
|
||||||
pub clients: Vec<Option<Client>>,
|
pub clients: Vec<Option<Client>>,
|
||||||
pub base: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -31,50 +29,48 @@ pub enum Approval {
|
|||||||
|
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn respond(response: RequestResponse, app_state: State<'_, AppState>) -> Result<(), SendResponseError> {
|
pub fn respond(response: RequestResponse, app_state: State<'_, AppState>) -> Result<(), String> {
|
||||||
app_state.send_response(response).await
|
app_state.send_response(response)
|
||||||
|
.map_err(|e| format!("Error responding to request: {e}"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn unlock(passphrase: String, app_state: State<'_, AppState>) -> Result<(), UnlockError> {
|
pub async fn unlock(passphrase: String, app_state: State<'_, AppState>) -> Result<(), UnlockError> {
|
||||||
app_state.unlock(&passphrase).await
|
app_state.decrypt(&passphrase).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn get_session_status(app_state: State<'_, AppState>) -> Result<String, ()> {
|
pub fn get_session_status(app_state: State<'_, AppState>) -> String {
|
||||||
let session = app_state.session.read().await;
|
let session = app_state.session.read().unwrap();
|
||||||
let status = match *session {
|
match *session {
|
||||||
Session::Locked(_) => "locked".into(),
|
Session::Locked(_) => "locked".into(),
|
||||||
Session::Unlocked{..} => "unlocked".into(),
|
Session::Unlocked(_) => "unlocked".into(),
|
||||||
Session::Empty => "empty".into()
|
Session::Empty => "empty".into()
|
||||||
};
|
}
|
||||||
Ok(status)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn save_credentials(
|
pub async fn save_credentials(
|
||||||
credentials: BaseCredentials,
|
credentials: Credentials,
|
||||||
passphrase: String,
|
passphrase: String,
|
||||||
app_state: State<'_, AppState>
|
app_state: State<'_, AppState>
|
||||||
) -> Result<(), UnlockError> {
|
) -> Result<(), UnlockError> {
|
||||||
app_state.new_creds(credentials, &passphrase).await
|
app_state.save_creds(credentials, &passphrase).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn get_config(app_state: State<'_, AppState>) -> Result<AppConfig, ()> {
|
pub fn get_config(app_state: State<'_, AppState>) -> AppConfig {
|
||||||
let config = app_state.config.read().await;
|
let config = app_state.config.read().unwrap();
|
||||||
Ok(config.clone())
|
config.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn save_config(config: AppConfig, app_state: State<'_, AppState>) -> Result<(), String> {
|
pub fn save_config(config: AppConfig, app_state: State<'_, AppState>) {
|
||||||
app_state.update_config(config)
|
let mut prev_config = app_state.config.write().unwrap();
|
||||||
.await
|
*prev_config = config;
|
||||||
.map_err(|e| format!("Error saving config: {e}"))?;
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
pub mod app;
|
|
||||||
pub mod cli;
|
|
||||||
mod config;
|
|
||||||
mod credentials;
|
|
||||||
pub mod errors;
|
|
||||||
mod clientinfo;
|
|
||||||
mod ipc;
|
|
||||||
mod state;
|
|
||||||
mod server;
|
|
||||||
mod tray;
|
|
||||||
+89
-15
@@ -3,25 +3,99 @@
|
|||||||
windows_subsystem = "windows"
|
windows_subsystem = "windows"
|
||||||
)]
|
)]
|
||||||
|
|
||||||
use creddy::{
|
use tauri::{AppHandle, Manager, async_runtime as rt};
|
||||||
app,
|
use once_cell::sync::OnceCell;
|
||||||
cli,
|
|
||||||
errors::ErrorPopup,
|
|
||||||
};
|
|
||||||
|
|
||||||
|
mod config;
|
||||||
|
mod errors;
|
||||||
|
mod clientinfo;
|
||||||
|
mod ipc;
|
||||||
|
mod state;
|
||||||
|
mod server;
|
||||||
|
mod tray;
|
||||||
|
|
||||||
|
use crate::errors::*;
|
||||||
|
use state::AppState;
|
||||||
|
|
||||||
|
|
||||||
|
pub static APP: OnceCell<AppHandle> = OnceCell::new();
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let res = match cli::parser().get_matches().subcommand() {
|
let initial_state = match rt::block_on(state::AppState::load()) {
|
||||||
None | Some(("run", _)) => {
|
Ok(state) => state,
|
||||||
app::run().error_popup("Creddy failed to start");
|
Err(e) => {eprintln!("{}", e); return;}
|
||||||
Ok(())
|
|
||||||
},
|
|
||||||
Some(("show", m)) => cli::show(m),
|
|
||||||
Some(("exec", m)) => cli::exec(m),
|
|
||||||
_ => unreachable!(),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Err(e) = res {
|
tauri::Builder::default()
|
||||||
eprintln!("Error: {e}");
|
.manage(initial_state)
|
||||||
|
.system_tray(tray::create())
|
||||||
|
.on_system_tray_event(tray::handle_event)
|
||||||
|
.invoke_handler(tauri::generate_handler![
|
||||||
|
ipc::unlock,
|
||||||
|
ipc::respond,
|
||||||
|
ipc::get_session_status,
|
||||||
|
ipc::save_credentials,
|
||||||
|
ipc::get_config,
|
||||||
|
ipc::save_config,
|
||||||
|
])
|
||||||
|
.setup(|app| {
|
||||||
|
APP.set(app.handle()).unwrap();
|
||||||
|
let state = app.state::<AppState>();
|
||||||
|
let config = state.config.read().unwrap();
|
||||||
|
let addr = std::net::SocketAddrV4::new(config.listen_addr, config.listen_port);
|
||||||
|
tauri::async_runtime::spawn(server::serve(addr, app.handle()));
|
||||||
|
|
||||||
|
if !config.start_minimized {
|
||||||
|
app.get_window("main")
|
||||||
|
.ok_or(RequestError::NoMainWindow)?
|
||||||
|
.show()?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
.build(tauri::generate_context!())
|
||||||
|
.expect("error while running tauri application")
|
||||||
|
.run(|app, run_event| match run_event {
|
||||||
|
tauri::RunEvent::WindowEvent { label, event, .. } => match event {
|
||||||
|
tauri::WindowEvent::CloseRequested { api, .. } => {
|
||||||
|
let _ = app.get_window(&label).map(|w| w.hide());
|
||||||
|
api.prevent_close();
|
||||||
|
}
|
||||||
|
_ => ()
|
||||||
|
}
|
||||||
|
_ => ()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
macro_rules! get_state {
|
||||||
|
($prop:ident as $name:ident) => {
|
||||||
|
use tauri::Manager;
|
||||||
|
let app = crate::APP.get().unwrap(); // as long as the app is running, this is fine
|
||||||
|
let state = app.state::<crate::state::AppState>();
|
||||||
|
let $name = state.$prop.read().unwrap(); // only panics if another thread has already panicked
|
||||||
|
};
|
||||||
|
(config.$prop:ident as $name:ident) => {
|
||||||
|
use tauri::Manager;
|
||||||
|
let app = crate::APP.get().unwrap();
|
||||||
|
let state = app.state::<crate::state::AppState>();
|
||||||
|
let config = state.config.read().unwrap();
|
||||||
|
let $name = config.$prop;
|
||||||
|
};
|
||||||
|
|
||||||
|
(mut $prop:ident as $name:ident) => {
|
||||||
|
use tauri::Manager;
|
||||||
|
let app = crate::APP.get().unwrap();
|
||||||
|
let state = app.state::<crate::state::AppState>();
|
||||||
|
let $name = state.$prop.write().unwrap();
|
||||||
|
};
|
||||||
|
(mut config.$prop:ident as $name:ident) => {
|
||||||
|
use tauri::Manager;
|
||||||
|
let app = crate::APP.get().unwrap();
|
||||||
|
let state = app.state::<crate::state::AppState>();
|
||||||
|
let config = state.config.write().unwrap();
|
||||||
|
let $name = config.$prop;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub(crate) use get_state;
|
||||||
+38
-105
@@ -1,21 +1,12 @@
|
|||||||
use core::time::Duration;
|
use core::time::Duration;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::net::{
|
use std::net::{SocketAddr, SocketAddrV4};
|
||||||
Ipv4Addr,
|
use tokio::net::{TcpListener, TcpStream};
|
||||||
SocketAddr,
|
|
||||||
SocketAddrV4,
|
|
||||||
};
|
|
||||||
use tokio::net::{
|
|
||||||
TcpListener,
|
|
||||||
TcpStream,
|
|
||||||
};
|
|
||||||
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||||
use tokio::sync::oneshot;
|
use tokio::sync::oneshot;
|
||||||
use tokio::time::sleep;
|
use tokio::time::sleep;
|
||||||
|
|
||||||
use tauri::{AppHandle, Manager};
|
use tauri::{AppHandle, Manager};
|
||||||
use tauri::async_runtime as rt;
|
|
||||||
use tauri::async_runtime::JoinHandle;
|
|
||||||
|
|
||||||
use crate::{clientinfo, clientinfo::Client};
|
use crate::{clientinfo, clientinfo::Client};
|
||||||
use crate::errors::*;
|
use crate::errors::*;
|
||||||
@@ -31,10 +22,10 @@ struct Handler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Handler {
|
impl Handler {
|
||||||
async fn new(stream: TcpStream, app: AppHandle) -> Self {
|
fn new(stream: TcpStream, app: AppHandle) -> Self {
|
||||||
let state = app.state::<AppState>();
|
let state = app.state::<AppState>();
|
||||||
let (chan_send, chan_recv) = oneshot::channel();
|
let (chan_send, chan_recv) = oneshot::channel();
|
||||||
let request_id = state.register_request(chan_send).await;
|
let request_id = state.register_request(chan_send);
|
||||||
Handler {
|
Handler {
|
||||||
request_id,
|
request_id,
|
||||||
stream,
|
stream,
|
||||||
@@ -48,40 +39,28 @@ impl Handler {
|
|||||||
eprintln!("{e}");
|
eprintln!("{e}");
|
||||||
}
|
}
|
||||||
let state = self.app.state::<AppState>();
|
let state = self.app.state::<AppState>();
|
||||||
state.unregister_request(self.request_id).await;
|
state.unregister_request(self.request_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn try_handle(&mut self) -> Result<(), HandlerError> {
|
async fn try_handle(&mut self) -> Result<(), RequestError> {
|
||||||
let req_path = self.recv_request().await?;
|
let _ = self.recv_request().await?;
|
||||||
let clients = self.get_clients().await?;
|
let clients = self.get_clients()?;
|
||||||
if self.includes_banned(&clients).await {
|
if self.includes_banned(&clients) {
|
||||||
self.stream.write(b"HTTP/1.0 403 Access Denied\r\n\r\n").await?;
|
self.stream.write(b"HTTP/1.0 403 Access Denied\r\n\r\n").await?;
|
||||||
return Ok(())
|
return Ok(())
|
||||||
}
|
}
|
||||||
let base = req_path == b"/creddy/base-credentials";
|
|
||||||
|
|
||||||
let req = Request {id: self.request_id, clients, base};
|
let req = Request {id: self.request_id, clients};
|
||||||
self.app.emit_all("credentials-request", &req)?;
|
self.app.emit_all("credentials-request", &req)?;
|
||||||
let starting_visibility = self.show_window()?;
|
let starting_visibility = self.show_window()?;
|
||||||
|
|
||||||
match self.wait_for_response().await? {
|
match self.wait_for_response().await? {
|
||||||
Approval::Approved => {
|
Approval::Approved => self.send_credentials().await?,
|
||||||
let state = self.app.state::<AppState>();
|
|
||||||
let creds = if base {
|
|
||||||
state.serialize_base_creds().await?
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
state.serialize_session_creds().await?
|
|
||||||
};
|
|
||||||
self.send_body(creds.as_bytes()).await?;
|
|
||||||
},
|
|
||||||
Approval::Denied => {
|
Approval::Denied => {
|
||||||
let state = self.app.state::<AppState>();
|
let state = self.app.state::<AppState>();
|
||||||
for client in req.clients {
|
for client in req.clients {
|
||||||
state.add_ban(client).await;
|
state.add_ban(client, self.app.clone());
|
||||||
}
|
}
|
||||||
self.send_body(b"Denied!").await?;
|
|
||||||
self.stream.shutdown().await?;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,62 +68,51 @@ impl Handler {
|
|||||||
// and b) there are no other pending requests
|
// and b) there are no other pending requests
|
||||||
let state = self.app.state::<AppState>();
|
let state = self.app.state::<AppState>();
|
||||||
let delay = {
|
let delay = {
|
||||||
let config = state.config.read().await;
|
let config = state.config.read().unwrap();
|
||||||
Duration::from_millis(config.rehide_ms)
|
Duration::from_millis(config.rehide_ms)
|
||||||
};
|
};
|
||||||
sleep(delay).await;
|
sleep(delay).await;
|
||||||
|
|
||||||
if !starting_visibility && state.req_count().await == 0 {
|
if !starting_visibility && state.req_count() == 0 {
|
||||||
let window = self.app.get_window("main").ok_or(HandlerError::NoMainWindow)?;
|
let window = self.app.get_window("main").ok_or(RequestError::NoMainWindow)?;
|
||||||
window.hide()?;
|
window.hide()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn recv_request(&mut self) -> Result<Vec<u8>, HandlerError> {
|
async fn recv_request(&mut self) -> Result<Vec<u8>, RequestError> {
|
||||||
let mut buf = vec![0; 8192]; // it's what tokio's BufReader uses
|
let mut buf = vec![0; 8192]; // it's what tokio's BufReader uses
|
||||||
let mut n = 0;
|
let mut n = 0;
|
||||||
loop {
|
loop {
|
||||||
n += self.stream.read(&mut buf[n..]).await?;
|
n += self.stream.read(&mut buf[n..]).await?;
|
||||||
if n >= 4 && &buf[(n - 4)..n] == b"\r\n\r\n" {break;}
|
if n >= 4 && &buf[(n - 4)..n] == b"\r\n\r\n" {break;}
|
||||||
if n == buf.len() {return Err(HandlerError::RequestTooLarge);}
|
if n == buf.len() {return Err(RequestError::RequestTooLarge);}
|
||||||
}
|
}
|
||||||
|
|
||||||
let path = buf.split(|&c| &[c] == b" ")
|
if cfg!(debug_assertions) {
|
||||||
.skip(1)
|
|
||||||
.next()
|
|
||||||
.ok_or(HandlerError::BadRequest(buf.clone()))?;
|
|
||||||
|
|
||||||
#[cfg(debug_assertions)] {
|
|
||||||
println!("Path: {}", std::str::from_utf8(&path).unwrap());
|
|
||||||
println!("{}", std::str::from_utf8(&buf).unwrap());
|
println!("{}", std::str::from_utf8(&buf).unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(path.into())
|
Ok(buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_clients(&self) -> Result<Vec<Option<Client>>, HandlerError> {
|
fn get_clients(&self) -> Result<Vec<Option<Client>>, RequestError> {
|
||||||
let peer_addr = match self.stream.peer_addr()? {
|
let peer_addr = match self.stream.peer_addr()? {
|
||||||
SocketAddr::V4(addr) => addr,
|
SocketAddr::V4(addr) => addr,
|
||||||
_ => unreachable!(), // we only listen on IPv4
|
_ => unreachable!(), // we only listen on IPv4
|
||||||
};
|
};
|
||||||
let clients = clientinfo::get_clients(peer_addr.port()).await?;
|
let clients = clientinfo::get_clients(peer_addr.port())?;
|
||||||
Ok(clients)
|
Ok(clients)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn includes_banned(&self, clients: &Vec<Option<Client>>) -> bool {
|
fn includes_banned(&self, clients: &Vec<Option<Client>>) -> bool {
|
||||||
let state = self.app.state::<AppState>();
|
let state = self.app.state::<AppState>();
|
||||||
for client in clients {
|
clients.iter().any(|c| state.is_banned(c))
|
||||||
if state.is_banned(client).await {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn show_window(&self) -> Result<bool, HandlerError> {
|
fn show_window(&self) -> Result<bool, RequestError> {
|
||||||
let window = self.app.get_window("main").ok_or(HandlerError::NoMainWindow)?;
|
let window = self.app.get_window("main").ok_or(RequestError::NoMainWindow)?;
|
||||||
let starting_visibility = window.is_visible()?;
|
let starting_visibility = window.is_visible()?;
|
||||||
if !starting_visibility {
|
if !starting_visibility {
|
||||||
window.unminimize()?;
|
window.unminimize()?;
|
||||||
@@ -154,7 +122,7 @@ impl Handler {
|
|||||||
Ok(starting_visibility)
|
Ok(starting_visibility)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn wait_for_response(&mut self) -> Result<Approval, HandlerError> {
|
async fn wait_for_response(&mut self) -> Result<Approval, RequestError> {
|
||||||
self.stream.write(b"HTTP/1.0 200 OK\r\n").await?;
|
self.stream.write(b"HTTP/1.0 200 OK\r\n").await?;
|
||||||
self.stream.write(b"Content-Type: application/json\r\n").await?;
|
self.stream.write(b"Content-Type: application/json\r\n").await?;
|
||||||
self.stream.write(b"X-Creddy-delaying-tactic: ").await?;
|
self.stream.write(b"X-Creddy-delaying-tactic: ").await?;
|
||||||
@@ -177,62 +145,28 @@ impl Handler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn send_body(&mut self, body: &[u8]) -> Result<(), HandlerError> {
|
async fn send_credentials(&mut self) -> Result<(), RequestError> {
|
||||||
|
let state = self.app.state::<AppState>();
|
||||||
|
let creds = state.get_creds_serialized()?;
|
||||||
|
|
||||||
self.stream.write(b"\r\nContent-Length: ").await?;
|
self.stream.write(b"\r\nContent-Length: ").await?;
|
||||||
self.stream.write(body.len().to_string().as_bytes()).await?;
|
self.stream.write(creds.as_bytes().len().to_string().as_bytes()).await?;
|
||||||
|
self.stream.write(b"\r\n\r\n").await?;
|
||||||
|
self.stream.write(creds.as_bytes()).await?;
|
||||||
self.stream.write(b"\r\n\r\n").await?;
|
self.stream.write(b"\r\n\r\n").await?;
|
||||||
self.stream.write(body).await?;
|
|
||||||
self.stream.shutdown().await?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
pub async fn serve(addr: SocketAddrV4, app_handle: AppHandle) -> io::Result<()> {
|
||||||
pub struct Server {
|
let listener = TcpListener::bind(&addr).await?;
|
||||||
addr: Ipv4Addr,
|
println!("Listening on {addr}");
|
||||||
port: u16,
|
|
||||||
app_handle: AppHandle,
|
|
||||||
task: JoinHandle<()>,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
impl Server {
|
|
||||||
pub async fn new(addr: Ipv4Addr, port: u16, app_handle: AppHandle) -> io::Result<Server> {
|
|
||||||
let task = Self::start_server(addr, port, app_handle.app_handle()).await?;
|
|
||||||
Ok(Server { addr, port, app_handle, task})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn rebind(&mut self, addr: Ipv4Addr, port: u16) -> io::Result<()> {
|
|
||||||
if addr == self.addr && port == self.port {
|
|
||||||
return Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
let new_task = Self::start_server(addr, port, self.app_handle.app_handle()).await?;
|
|
||||||
self.task.abort();
|
|
||||||
|
|
||||||
self.addr = addr;
|
|
||||||
self.port = port;
|
|
||||||
self.task = new_task;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
// construct the listener before spawning the task so that we can return early if it fails
|
|
||||||
async fn start_server(addr: Ipv4Addr, port: u16, app_handle: AppHandle) -> io::Result<JoinHandle<()>> {
|
|
||||||
let sock_addr = SocketAddrV4::new(addr, port);
|
|
||||||
let listener = TcpListener::bind(&sock_addr).await?;
|
|
||||||
let task = rt::spawn(
|
|
||||||
Self::serve(listener, app_handle.app_handle())
|
|
||||||
);
|
|
||||||
Ok(task)
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn serve(listener: TcpListener, app_handle: AppHandle) {
|
|
||||||
loop {
|
loop {
|
||||||
match listener.accept().await {
|
match listener.accept().await {
|
||||||
Ok((stream, _)) => {
|
Ok((stream, _)) => {
|
||||||
let handler = Handler::new(stream, app_handle.app_handle()).await;
|
let handler = Handler::new(stream, app_handle.app_handle());
|
||||||
rt::spawn(handler.handle());
|
tauri::async_runtime::spawn(handler.handle());
|
||||||
},
|
},
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
eprintln!("Error accepting connection: {e}");
|
eprintln!("Error accepting connection: {e}");
|
||||||
@@ -240,4 +174,3 @@ impl Server {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
+203
-84
@@ -1,26 +1,59 @@
|
|||||||
|
use core::time::Duration;
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::time::Duration;
|
use std::sync::RwLock;
|
||||||
|
|
||||||
use tokio::{
|
use serde::{Serialize, Deserialize};
|
||||||
sync::oneshot::Sender,
|
use tokio::sync::oneshot::Sender;
|
||||||
sync::RwLock,
|
use tokio::time::sleep;
|
||||||
time::sleep,
|
use sqlx::{SqlitePool, sqlite::SqlitePoolOptions, sqlite::SqliteConnectOptions};
|
||||||
|
use sodiumoxide::crypto::{
|
||||||
|
pwhash,
|
||||||
|
pwhash::Salt,
|
||||||
|
secretbox,
|
||||||
|
secretbox::{Nonce, Key}
|
||||||
};
|
};
|
||||||
use sqlx::SqlitePool;
|
|
||||||
use tauri::async_runtime as runtime;
|
use tauri::async_runtime as runtime;
|
||||||
use tauri::Manager;
|
use tauri::Manager;
|
||||||
|
|
||||||
use crate::app::APP;
|
|
||||||
use crate::credentials::{
|
|
||||||
Session,
|
|
||||||
BaseCredentials,
|
|
||||||
SessionCredentials,
|
|
||||||
};
|
|
||||||
use crate::{config, config::AppConfig};
|
use crate::{config, config::AppConfig};
|
||||||
use crate::ipc::{self, Approval};
|
use crate::ipc;
|
||||||
use crate::clientinfo::Client;
|
use crate::clientinfo::Client;
|
||||||
use crate::errors::*;
|
use crate::errors::*;
|
||||||
use crate::server::Server;
|
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
#[serde(untagged)]
|
||||||
|
pub enum Credentials {
|
||||||
|
#[serde(rename_all = "PascalCase")]
|
||||||
|
LongLived {
|
||||||
|
access_key_id: String,
|
||||||
|
secret_access_key: String,
|
||||||
|
},
|
||||||
|
#[serde(rename_all = "PascalCase")]
|
||||||
|
ShortLived {
|
||||||
|
access_key_id: String,
|
||||||
|
secret_access_key: String,
|
||||||
|
token: String,
|
||||||
|
expiration: String,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct LockedCredentials {
|
||||||
|
access_key_id: String,
|
||||||
|
secret_key_enc: Vec<u8>,
|
||||||
|
salt: Salt,
|
||||||
|
nonce: Nonce,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Session {
|
||||||
|
Unlocked(Credentials),
|
||||||
|
Locked(LockedCredentials),
|
||||||
|
Empty,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -30,79 +63,117 @@ pub struct AppState {
|
|||||||
pub request_count: RwLock<u64>,
|
pub request_count: RwLock<u64>,
|
||||||
pub open_requests: RwLock<HashMap<u64, Sender<ipc::Approval>>>,
|
pub open_requests: RwLock<HashMap<u64, Sender<ipc::Approval>>>,
|
||||||
pub bans: RwLock<std::collections::HashSet<Option<Client>>>,
|
pub bans: RwLock<std::collections::HashSet<Option<Client>>>,
|
||||||
server: RwLock<Server>,
|
pool: SqlitePool,
|
||||||
pool: sqlx::SqlitePool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AppState {
|
impl AppState {
|
||||||
pub fn new(config: AppConfig, session: Session, server: Server, pool: SqlitePool) -> AppState {
|
pub async fn load() -> Result<Self, SetupError> {
|
||||||
AppState {
|
let conn_opts = SqliteConnectOptions::new()
|
||||||
config: RwLock::new(config),
|
.filename(config::get_or_create_db_path())
|
||||||
session: RwLock::new(session),
|
.create_if_missing(true);
|
||||||
|
let pool_opts = SqlitePoolOptions::new();
|
||||||
|
|
||||||
|
let pool: SqlitePool = pool_opts.connect_with(conn_opts).await?;
|
||||||
|
sqlx::migrate!().run(&pool).await?;
|
||||||
|
let creds = Self::load_creds(&pool).await?;
|
||||||
|
let conf = config::load(&pool).await?;
|
||||||
|
|
||||||
|
let state = AppState {
|
||||||
|
config: RwLock::new(conf),
|
||||||
|
session: RwLock::new(creds),
|
||||||
request_count: RwLock::new(0),
|
request_count: RwLock::new(0),
|
||||||
open_requests: RwLock::new(HashMap::new()),
|
open_requests: RwLock::new(HashMap::new()),
|
||||||
bans: RwLock::new(HashSet::new()),
|
bans: RwLock::new(HashSet::new()),
|
||||||
server: RwLock::new(server),
|
|
||||||
pool,
|
pool,
|
||||||
}
|
};
|
||||||
|
|
||||||
|
Ok(state)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn new_creds(&self, base_creds: BaseCredentials, passphrase: &str) -> Result<(), UnlockError> {
|
async fn load_creds(pool: &SqlitePool) -> Result<Session, SetupError> {
|
||||||
let locked = base_creds.encrypt(passphrase)?;
|
let res = sqlx::query!("SELECT * FROM credentials ORDER BY created_at desc")
|
||||||
|
.fetch_optional(pool)
|
||||||
|
.await?;
|
||||||
|
let row = match res {
|
||||||
|
Some(r) => r,
|
||||||
|
None => {return Ok(Session::Empty);}
|
||||||
|
};
|
||||||
|
|
||||||
|
let salt_buf: [u8; 32] = row.salt
|
||||||
|
.try_into()
|
||||||
|
.map_err(|_e| SetupError::InvalidRecord)?;
|
||||||
|
let nonce_buf: [u8; 24] = row.nonce
|
||||||
|
.try_into()
|
||||||
|
.map_err(|_e| SetupError::InvalidRecord)?;
|
||||||
|
|
||||||
|
let creds = LockedCredentials {
|
||||||
|
access_key_id: row.access_key_id,
|
||||||
|
secret_key_enc: row.secret_key_enc,
|
||||||
|
salt: Salt(salt_buf),
|
||||||
|
nonce: Nonce(nonce_buf),
|
||||||
|
};
|
||||||
|
Ok(Session::Locked(creds))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn save_creds(&self, creds: Credentials, passphrase: &str) -> Result<(), UnlockError> {
|
||||||
|
let (key_id, secret_key) = match creds {
|
||||||
|
Credentials::LongLived {access_key_id, secret_access_key} => {
|
||||||
|
(access_key_id, secret_access_key)
|
||||||
|
},
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
|
||||||
// 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(&key_id, &secret_key).await?;
|
||||||
locked.save(&self.pool).await?;
|
|
||||||
|
let salt = pwhash::gen_salt();
|
||||||
|
let mut key_buf = [0; secretbox::KEYBYTES];
|
||||||
|
pwhash::derive_key_interactive(&mut key_buf, passphrase.as_bytes(), &salt).unwrap();
|
||||||
|
let key = Key(key_buf);
|
||||||
|
// not sure we need both salt AND nonce given that we generate a
|
||||||
|
// fresh salt every time we encrypt, but better safe than sorry
|
||||||
|
let nonce = secretbox::gen_nonce();
|
||||||
|
let secret_key_enc = secretbox::seal(secret_key.as_bytes(), &nonce, &key);
|
||||||
|
|
||||||
|
|
||||||
|
sqlx::query(
|
||||||
|
"INSERT INTO credentials (access_key_id, secret_key_enc, salt, nonce, created_at)
|
||||||
|
VALUES (?, ?, ?, ?, strftime('%s'))"
|
||||||
|
)
|
||||||
|
.bind(&key_id)
|
||||||
|
.bind(&secret_key_enc)
|
||||||
|
.bind(&salt.0[0..])
|
||||||
|
.bind(&nonce.0[0..])
|
||||||
|
.execute(&self.pool)
|
||||||
|
.await?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn update_config(&self, new_config: AppConfig) -> Result<(), SetupError> {
|
pub fn register_request(&self, chan: Sender<ipc::Approval>) -> u64 {
|
||||||
let mut live_config = self.config.write().await;
|
|
||||||
|
|
||||||
if new_config.start_on_login != live_config.start_on_login {
|
|
||||||
config::set_auto_launch(new_config.start_on_login)?;
|
|
||||||
}
|
|
||||||
if new_config.listen_addr != live_config.listen_addr
|
|
||||||
|| new_config.listen_port != live_config.listen_port
|
|
||||||
{
|
|
||||||
let mut sv = self.server.write().await;
|
|
||||||
sv.rebind(new_config.listen_addr, new_config.listen_port).await?;
|
|
||||||
}
|
|
||||||
|
|
||||||
new_config.save(&self.pool).await?;
|
|
||||||
*live_config = new_config;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn register_request(&self, chan: Sender<ipc::Approval>) -> u64 {
|
|
||||||
let count = {
|
let count = {
|
||||||
let mut c = self.request_count.write().await;
|
let mut c = self.request_count.write().unwrap();
|
||||||
*c += 1;
|
*c += 1;
|
||||||
c
|
c
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut open_requests = self.open_requests.write().await;
|
let mut open_requests = self.open_requests.write().unwrap();
|
||||||
open_requests.insert(*count, chan); // `count` is the request id
|
open_requests.insert(*count, chan); // `count` is the request id
|
||||||
*count
|
*count
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn unregister_request(&self, id: u64) {
|
pub fn unregister_request(&self, id: u64) {
|
||||||
let mut open_requests = self.open_requests.write().await;
|
let mut open_requests = self.open_requests.write().unwrap();
|
||||||
open_requests.remove(&id);
|
open_requests.remove(&id);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn req_count(&self) -> usize {
|
pub fn req_count(&self) -> usize {
|
||||||
let open_requests = self.open_requests.read().await;
|
let open_requests = self.open_requests.read().unwrap();
|
||||||
open_requests.len()
|
open_requests.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn send_response(&self, response: ipc::RequestResponse) -> Result<(), SendResponseError> {
|
pub fn send_response(&self, response: ipc::RequestResponse) -> Result<(), SendResponseError> {
|
||||||
if let Approval::Approved = response.approval {
|
let mut open_requests = self.open_requests.write().unwrap();
|
||||||
let mut session = self.session.write().await;
|
|
||||||
session.renew_if_expired().await?;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut open_requests = self.open_requests.write().await;
|
|
||||||
let chan = open_requests
|
let chan = open_requests
|
||||||
.remove(&response.id)
|
.remove(&response.id)
|
||||||
.ok_or(SendResponseError::NotFound)
|
.ok_or(SendResponseError::NotFound)
|
||||||
@@ -112,57 +183,105 @@ impl AppState {
|
|||||||
.map_err(|_e| SendResponseError::Abandoned)
|
.map_err(|_e| SendResponseError::Abandoned)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn add_ban(&self, client: Option<Client>) {
|
pub fn add_ban(&self, client: Option<Client>, app: tauri::AppHandle) {
|
||||||
let mut bans = self.bans.write().await;
|
let mut bans = self.bans.write().unwrap();
|
||||||
bans.insert(client.clone());
|
bans.insert(client.clone());
|
||||||
|
|
||||||
runtime::spawn(async move {
|
runtime::spawn(async move {
|
||||||
sleep(Duration::from_secs(5)).await;
|
sleep(Duration::from_secs(5)).await;
|
||||||
let app = APP.get().unwrap();
|
|
||||||
let state = app.state::<AppState>();
|
let state = app.state::<AppState>();
|
||||||
let mut bans = state.bans.write().await;
|
let mut bans = state.bans.write().unwrap();
|
||||||
bans.remove(&client);
|
bans.remove(&client);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn is_banned(&self, client: &Option<Client>) -> bool {
|
pub fn is_banned(&self, client: &Option<Client>) -> bool {
|
||||||
self.bans.read().await.contains(&client)
|
self.bans.read().unwrap().contains(&client)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn unlock(&self, passphrase: &str) -> Result<(), UnlockError> {
|
pub async fn decrypt(&self, passphrase: &str) -> Result<(), UnlockError> {
|
||||||
let base_creds = match *self.session.read().await {
|
let (key_id, secret) = {
|
||||||
|
// do this all in a block so that we aren't holding a lock across an await
|
||||||
|
let session = self.session.read().unwrap();
|
||||||
|
let locked = match *session {
|
||||||
Session::Empty => {return Err(UnlockError::NoCredentials);},
|
Session::Empty => {return Err(UnlockError::NoCredentials);},
|
||||||
Session::Unlocked{..} => {return Err(UnlockError::NotLocked);},
|
Session::Unlocked(_) => {return Err(UnlockError::NotLocked);},
|
||||||
Session::Locked(ref locked) => locked.decrypt(passphrase)?,
|
Session::Locked(ref c) => c,
|
||||||
};
|
};
|
||||||
// Read lock is dropped here, so this doesn't deadlock
|
|
||||||
self.new_session(base_creds).await?;
|
let mut key_buf = [0; secretbox::KEYBYTES];
|
||||||
|
// pretty sure this only fails if we're out of memory
|
||||||
|
pwhash::derive_key_interactive(&mut key_buf, passphrase.as_bytes(), &locked.salt).unwrap();
|
||||||
|
let decrypted = secretbox::open(&locked.secret_key_enc, &locked.nonce, &Key(key_buf))
|
||||||
|
.map_err(|_e| UnlockError::BadPassphrase)?;
|
||||||
|
|
||||||
|
let secret_str = String::from_utf8(decrypted).map_err(|_e| UnlockError::InvalidUtf8)?;
|
||||||
|
(locked.access_key_id.clone(), secret_str)
|
||||||
|
};
|
||||||
|
|
||||||
|
self.new_session(&key_id, &secret).await?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn serialize_base_creds(&self) -> Result<String, GetCredentialsError> {
|
pub fn get_creds_serialized(&self) -> Result<String, GetCredentialsError> {
|
||||||
let session = self.session.read().await;
|
let session = self.session.read().unwrap();
|
||||||
match *session {
|
match *session {
|
||||||
Session::Unlocked{ref base, ..} => Ok(serde_json::to_string(base).unwrap()),
|
Session::Unlocked(ref creds) => Ok(serde_json::to_string(creds).unwrap()),
|
||||||
Session::Locked(_) => Err(GetCredentialsError::Locked),
|
Session::Locked(_) => Err(GetCredentialsError::Locked),
|
||||||
Session::Empty => Err(GetCredentialsError::Empty),
|
Session::Empty => Err(GetCredentialsError::Empty),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn serialize_session_creds(&self) -> Result<String, GetCredentialsError> {
|
async fn new_session(&self, key_id: &str, secret_key: &str) -> Result<(), GetSessionError> {
|
||||||
let session = self.session.read().await;
|
let creds = aws_sdk_sts::Credentials::new(
|
||||||
match *session {
|
key_id,
|
||||||
Session::Unlocked{ref session, ..} => Ok(serde_json::to_string(session).unwrap()),
|
secret_key,
|
||||||
Session::Locked(_) => Err(GetCredentialsError::Locked),
|
None, // token
|
||||||
Session::Empty => Err(GetCredentialsError::Empty),
|
None, // expiration
|
||||||
}
|
"creddy", // "provider name" apparently
|
||||||
|
);
|
||||||
|
let config = aws_config::from_env()
|
||||||
|
.credentials_provider(creds)
|
||||||
|
.load()
|
||||||
|
.await;
|
||||||
|
|
||||||
|
let client = aws_sdk_sts::Client::new(&config);
|
||||||
|
let resp = client.get_session_token()
|
||||||
|
.duration_seconds(43_200)
|
||||||
|
.send()
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
let aws_session = resp.credentials().ok_or(GetSessionError::NoCredentials)?;
|
||||||
|
|
||||||
|
let access_key_id = aws_session.access_key_id()
|
||||||
|
.ok_or(GetSessionError::NoCredentials)?
|
||||||
|
.to_string();
|
||||||
|
let secret_access_key = aws_session.secret_access_key()
|
||||||
|
.ok_or(GetSessionError::NoCredentials)?
|
||||||
|
.to_string();
|
||||||
|
let token = aws_session.session_token()
|
||||||
|
.ok_or(GetSessionError::NoCredentials)?
|
||||||
|
.to_string();
|
||||||
|
let expiration = aws_session.expiration()
|
||||||
|
.ok_or(GetSessionError::NoCredentials)?
|
||||||
|
.fmt(aws_smithy_types::date_time::Format::DateTime)
|
||||||
|
.unwrap(); // only fails if the d/t is out of range, which it can't be for this format
|
||||||
|
|
||||||
|
let mut app_session = self.session.write().unwrap();
|
||||||
|
let session_creds = Credentials::ShortLived {
|
||||||
|
access_key_id,
|
||||||
|
secret_access_key,
|
||||||
|
token,
|
||||||
|
expiration,
|
||||||
|
};
|
||||||
|
|
||||||
|
if cfg!(debug_assertions) {
|
||||||
|
println!("Got new session:\n{}", serde_json::to_string(&session_creds).unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn new_session(&self, base: BaseCredentials) -> Result<(), GetSessionError> {
|
*app_session = Session::Unlocked(session_creds);
|
||||||
let session = SessionCredentials::from_base(&base).await?;
|
|
||||||
let mut app_session = self.session.write().await;
|
|
||||||
*app_session = Session::Unlocked {base, session};
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -8,11 +8,11 @@
|
|||||||
},
|
},
|
||||||
"package": {
|
"package": {
|
||||||
"productName": "creddy",
|
"productName": "creddy",
|
||||||
"version": "0.2.3"
|
"version": "0.1.0"
|
||||||
},
|
},
|
||||||
"tauri": {
|
"tauri": {
|
||||||
"allowlist": {
|
"allowlist": {
|
||||||
"os": {"all": true}
|
"all": true
|
||||||
},
|
},
|
||||||
"bundle": {
|
"bundle": {
|
||||||
"active": true,
|
"active": true,
|
||||||
@@ -44,18 +44,11 @@
|
|||||||
"windows": {
|
"windows": {
|
||||||
"certificateThumbprint": null,
|
"certificateThumbprint": null,
|
||||||
"digestAlgorithm": "sha256",
|
"digestAlgorithm": "sha256",
|
||||||
"timestampUrl": "",
|
"timestampUrl": ""
|
||||||
"wix": {
|
|
||||||
"fragmentPaths": ["conf/cli.wxs"],
|
|
||||||
"componentRefs": ["CliBinary", "AddToPath"]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"security": {
|
"security": {
|
||||||
"csp": {
|
"csp": null
|
||||||
"default-src": ["'self'"],
|
|
||||||
"style-src": ["'self'", "'unsafe-inline'"]
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"updater": {
|
"updater": {
|
||||||
"active": false
|
"active": false
|
||||||
|
|||||||
+7
-8
@@ -1,22 +1,21 @@
|
|||||||
<script>
|
<script>
|
||||||
import { onMount } from 'svelte';
|
import { emit, listen } from '@tauri-apps/api/event';
|
||||||
import { listen } from '@tauri-apps/api/event';
|
|
||||||
import { invoke } from '@tauri-apps/api/tauri';
|
import { invoke } from '@tauri-apps/api/tauri';
|
||||||
|
|
||||||
import { appState, acceptRequest } from './lib/state.js';
|
import { appState } from './lib/state.js';
|
||||||
import { views, currentView, navigate } from './lib/routing.js';
|
import { navigate, currentView } from './lib/routing.js';
|
||||||
|
|
||||||
|
|
||||||
$views = import.meta.glob('./views/*.svelte', {eager: true});
|
|
||||||
navigate('Home');
|
|
||||||
|
|
||||||
invoke('get_config').then(config => $appState.config = config);
|
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);
|
||||||
});
|
});
|
||||||
|
|
||||||
acceptRequest();
|
// can't set this in routing.js directly for some reason
|
||||||
|
if (!$currentView) {
|
||||||
|
navigate('Home');
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,153 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
||||||
<!-- Generator: Adobe Illustrator 27.5.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
|
||||||
|
|
||||||
<svg
|
|
||||||
version="1.1"
|
|
||||||
id="Layer_1"
|
|
||||||
x="0px"
|
|
||||||
y="0px"
|
|
||||||
viewBox="0 0 273.45667 273.45667"
|
|
||||||
xml:space="preserve"
|
|
||||||
sodipodi:docname="vault_door.svg"
|
|
||||||
inkscape:version="1.2 (dc2aedaf03, 2022-05-15)"
|
|
||||||
width="273.45667"
|
|
||||||
height="273.45667"
|
|
||||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
|
||||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
xmlns:svg="http://www.w3.org/2000/svg"><defs
|
|
||||||
id="defs43" /><sodipodi:namedview
|
|
||||||
id="namedview41"
|
|
||||||
pagecolor="#ffffff"
|
|
||||||
bordercolor="#000000"
|
|
||||||
borderopacity="0.25"
|
|
||||||
inkscape:showpageshadow="2"
|
|
||||||
inkscape:pageopacity="0.0"
|
|
||||||
inkscape:pagecheckerboard="0"
|
|
||||||
inkscape:deskcolor="#d1d1d1"
|
|
||||||
showgrid="false"
|
|
||||||
inkscape:zoom="2.054"
|
|
||||||
inkscape:cx="209.83447"
|
|
||||||
inkscape:cy="63.291139"
|
|
||||||
inkscape:window-width="2560"
|
|
||||||
inkscape:window-height="1377"
|
|
||||||
inkscape:window-x="-8"
|
|
||||||
inkscape:window-y="-8"
|
|
||||||
inkscape:window-maximized="1"
|
|
||||||
inkscape:current-layer="Layer_1" />
|
|
||||||
<style
|
|
||||||
type="text/css"
|
|
||||||
id="style2">
|
|
||||||
.st0{fill:#FFFFFF;}
|
|
||||||
.st1{fill:#161616;}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<g
|
|
||||||
id="g38"
|
|
||||||
style="fill:#60697a;fill-opacity:1"
|
|
||||||
transform="matrix(-0.65108732,0,0,0.65108732,299.50017,-26.043493)">
|
|
||||||
<g
|
|
||||||
id="g36"
|
|
||||||
style="fill:#60697a;fill-opacity:1">
|
|
||||||
<path
|
|
||||||
class="st1"
|
|
||||||
d="m 102.88,181.03 c -3.49,0 -6.22,4.26 -6.22,9.7 v 118.53 c 0,5.44 2.73,9.7 6.22,9.7 3.49,0 6.22,-4.26 6.22,-9.7 V 190.73 c 0,-5.44 -2.73,-9.7 -6.22,-9.7 z m 2.99,128.24 c 0,3.64 -1.6,6.47 -2.98,6.47 -1.38,0 -2.99,-2.83 -2.99,-6.47 V 190.73 c 0,-3.64 1.61,-6.47 2.99,-6.47 1.38,0 2.98,2.83 2.98,6.47 z"
|
|
||||||
id="path6"
|
|
||||||
style="fill:#60697a;fill-opacity:1" />
|
|
||||||
<path
|
|
||||||
class="st1"
|
|
||||||
d="m 250,306.08 c 30.92,0 56.08,-25.16 56.08,-56.08 0,-30.92 -25.16,-56.08 -56.08,-56.08 -30.92,0 -56.08,25.16 -56.08,56.08 0,30.92 25.16,56.08 56.08,56.08 z m -6.47,-3.64 c -10.66,-1.31 -20.35,-5.8 -28.08,-12.49 l 23.33,-21.47 c 1.48,0.9 3.06,1.65 4.75,2.18 z M 231.6,250 c 0,-10.15 8.26,-18.4 18.4,-18.4 10.15,0 18.4,8.26 18.4,18.4 0,10.14 -8.26,18.4 -18.4,18.4 -10.15,0 -18.4,-8.25 -18.4,-18.4 z m 21.64,52.74 c -1.07,0.07 -2.15,0.11 -3.24,0.11 -1.08,0 -2.16,-0.04 -3.23,-0.11 v -31.37 c 1.06,0.16 2.13,0.27 3.23,0.27 1.1,0 2.18,-0.11 3.24,-0.27 z m 3.23,-0.31 v -31.79 c 1.58,-0.5 3.07,-1.18 4.46,-2.01 l 23.37,21.51 c -7.69,6.59 -17.28,11 -27.83,12.29 z m 30.24,-14.47 -23.04,-21.2 c 1.68,-1.37 3.14,-2.99 4.35,-4.79 l 23.06,21.23 c -1.36,1.67 -2.82,3.26 -4.37,4.76 z m 6.33,-7.36 -23.42,-21.55 c 0.57,-1.24 1.03,-2.54 1.36,-3.89 h 31.6 c -0.91,9.43 -4.32,18.12 -9.54,25.44 z m 9.8,-30.6 c 0,0.65 -0.03,1.29 -0.05,1.93 h -31.25 c 0.06,-0.64 0.1,-1.28 0.1,-1.93 0,-1.56 -0.17,-3.07 -0.49,-4.53 h 31.49 c 0.12,1.49 0.2,3 0.2,4.53 z m -0.57,-7.77 h -32.1 c -0.25,-0.64 -0.52,-1.27 -0.83,-1.88 l 23.33,-21.47 c 4.94,6.75 8.32,14.71 9.6,23.35 z m -11.59,-25.91 -23.04,21.2 c -1.26,-1.77 -2.77,-3.34 -4.49,-4.66 l 23.1,-21.26 c 1.57,1.48 3.06,3.05 4.43,4.72 z m -34.21,-18.75 c 10.33,1.27 19.75,5.52 27.35,11.87 l -23.45,21.58 c -1.23,-0.68 -2.54,-1.24 -3.9,-1.67 z m -9.7,-0.31 c 1.07,-0.06 2.15,-0.11 3.23,-0.11 1.09,0 2.16,0.04 3.24,0.11 v 31.37 c -1.06,-0.16 -2.13,-0.27 -3.24,-0.27 -1.1,0 -2.17,0.11 -3.23,0.27 z m -3.24,0.3 v 31.79 c -1.47,0.46 -2.87,1.09 -4.19,1.84 l -23.41,-21.54 c 7.66,-6.48 17.16,-10.81 27.6,-12.09 z m -30.01,14.26 23.07,21.23 c -1.7,1.35 -3.19,2.93 -4.42,4.72 l -23.05,-21.21 c 1.37,-1.67 2.84,-3.25 4.4,-4.74 z m -6.37,7.31 23.37,21.51 c -0.25,0.52 -0.48,1.05 -0.69,1.59 h -32.1 c 1.26,-8.53 4.58,-16.4 9.42,-23.1 z M 197.16,250 c 0,-1.53 0.08,-3.04 0.21,-4.53 h 31.49 c -0.31,1.46 -0.49,2.98 -0.49,4.53 0,0.65 0.04,1.3 0.1,1.93 H 197.2 c -0.02,-0.64 -0.04,-1.28 -0.04,-1.93 z m 0.25,5.17 h 31.6 c 0.31,1.24 0.71,2.45 1.22,3.59 l -23.45,21.59 c -5.12,-7.27 -8.46,-15.87 -9.37,-25.18 z m 34.41,6.52 c 1.18,1.83 2.62,3.47 4.27,4.86 l -23.03,21.19 c -1.54,-1.51 -2.99,-3.11 -4.34,-4.8 z"
|
|
||||||
id="path8"
|
|
||||||
style="fill:#60697a;fill-opacity:1" />
|
|
||||||
<path
|
|
||||||
class="st1"
|
|
||||||
d="m 438.65,157.85 5.34,-0.47 c 3.48,-0.31 6.31,-3.4 6.31,-6.89 V 100.67 97.44 57.41 c 0,-5.35 -4.35,-9.7 -9.7,-9.7 h -16.48 c -5.35,0 -9.7,4.35 -9.7,9.7 v 40.24 l -17.36,2.63 C 359.14,63.03 307.22,40 250,40 191.36,40 138.27,64.18 100.14,103.07 l -6.31,-5.81 6.68,-7.38 c 1.16,-1.28 1.75,-2.94 1.66,-4.66 -0.09,-1.73 -0.84,-3.31 -2.12,-4.47 L 84.46,66.63 c -1.19,-1.08 -2.73,-1.67 -4.34,-1.67 -1.83,0 -3.58,0.78 -4.8,2.13 L 68.83,74.26 58.01,64.3 c -0.31,-0.29 -0.73,-0.44 -1.16,-0.43 -0.43,0.02 -0.83,0.2 -1.12,0.52 l -6.57,7.14 c -0.6,0.66 -0.56,1.68 0.09,2.29 l 10.9,10.03 -6.53,7.22 c -2.39,2.65 -2.19,6.74 0.46,9.14 l 15.59,14.1 c 1.19,1.08 2.73,1.67 4.34,1.67 1.83,0 3.58,-0.78 4.8,-2.13 l 6.34,-7 6.21,5.72 C 59.39,149.43 40,197.49 40,250 c 0,52.28 19.22,100.15 50.95,136.95 l -5.99,5.52 -6.15,-6.79 c -1.22,-1.35 -2.97,-2.13 -4.8,-2.13 -1.61,0 -3.15,0.59 -4.34,1.67 l -15.59,14.1 c -2.65,2.39 -2.85,6.49 -0.46,9.14 l 6.34,7.01 -10.71,9.86 c -0.66,0.6 -0.7,1.63 -0.09,2.29 l 6.57,7.14 c 0.29,0.32 0.69,0.5 1.12,0.52 0.02,0 0.04,0 0.07,0 0.4,0 0.8,-0.15 1.09,-0.43 l 10.63,-9.78 6.68,7.38 c 1.22,1.35 2.97,2.13 4.8,2.13 1.61,0 3.15,-0.59 4.34,-1.67 l 15.59,-14.1 c 1.28,-1.16 2.03,-2.75 2.12,-4.47 0.09,-1.73 -0.51,-3.38 -1.66,-4.66 l -6.87,-7.59 6.07,-5.59 c 38.17,39.12 91.42,63.5 150.29,63.5 56.54,0 107.92,-22.48 145.71,-58.95 l 18.71,3.24 v 40.27 c 0,5.35 4.35,9.7 9.7,9.7 h 16.48 c 5.35,0 9.7,-4.35 9.7,-9.7 v -40.01 -3.23 -54.75 c 0,-3.49 -2.83,-6.58 -6.31,-6.89 L 440,339.33 c 12.81,-27.13 20,-57.4 20,-89.33 0,-33.04 -7.7,-64.31 -21.35,-92.15 z m -21,-100.44 c 0,-3.57 2.9,-6.47 6.47,-6.47 h 16.48 c 3.57,0 6.47,2.9 6.47,6.47 V 97.42 H 417.65 Z M 250,43.23 c 55.47,0 105.9,21.97 143.07,57.66 l -26.41,4 C 334.71,79.15 294.13,63.72 250,63.72 c -51.75,0 -98.62,21.23 -132.41,55.41 L 102.51,105.26 C 140.06,67.01 192.3,43.23 250,43.23 Z m 29.31,38.01 c 24.27,4.2 46.8,13.52 66.44,26.82 l -65.25,9.89 c 0.56,-1.31 0.91,-2.78 0.91,-4.35 V 87.72 c 0.01,-2.49 -0.79,-4.76 -2.1,-6.48 z m -11.85,-4.88 c -1.51,-3.4 -4.91,-5.79 -8.87,-5.79 h -16.48 c -3.92,0 -7.29,2.34 -8.82,5.69 -41.67,3.98 -79.11,22.68 -107.06,50.82 l -6.26,-5.76 C 153.17,87.78 199.19,66.95 250,66.95 c 42.27,0 81.2,14.45 112.22,38.61 l -11.79,1.79 C 326.49,90.45 298.14,79.42 267.46,76.36 Z m 10.73,11.36 v 25.88 c 0,2.02 -0.72,3.8 -1.83,4.98 l -8.06,1.22 V 81.25 h 4.95 c 2.72,0 4.94,2.91 4.94,6.47 z m -13.13,-7.44 v 39.79 H 235.64 V 80.28 c 0,-3.57 2.9,-6.47 6.47,-6.47 h 16.48 c 3.57,0 6.47,2.9 6.47,6.47 z m 84.7,312.81 11.62,2.01 c -30.88,23.76 -69.49,37.94 -111.38,37.94 -51.04,0 -97.25,-21 -130.48,-54.81 l 6.26,-5.76 c 28.09,28.49 65.87,47.38 107.94,51.29 1.68,2.9 4.81,4.85 8.39,4.85 h 16.48 c 3.61,0 6.76,-1.99 8.43,-4.92 30.56,-2.97 58.83,-13.87 82.74,-30.6 z m -81.47,26.15 v -0.32 -38.49 h 4.95 c 2.73,0 4.95,2.9 4.95,6.47 v 25.88 c 0,3.57 -2.22,6.47 -4.95,6.47 h -4.95 z m 11.4,-38.29 65.53,11.35 c -19.41,13.03 -41.62,22.19 -65.52,26.39 1.07,-1.64 1.72,-3.69 1.72,-5.92 v -25.88 c 0,-2.23 -0.65,-4.29 -1.73,-5.94 z m -57.18,31.82 v -25.88 c 0,-3.57 2.22,-6.47 4.95,-6.47 h 4.95 v 38.49 0.32 h -4.95 c -2.73,0.01 -4.95,-2.89 -4.95,-6.46 z m 42.55,6.14 c 0,3.57 -2.9,6.47 -6.47,6.47 h -16.48 c -3.57,0 -6.47,-2.9 -6.47,-6.47 V 378.9 h 29.42 z m -32.65,-76.39 v 33.14 1.53 h -4.95 c -4.51,0 -8.18,4.35 -8.18,9.7 v 25.88 c 0,2.28 0.67,4.38 1.79,6.04 -36.03,-6.16 -68.25,-23.58 -92.89,-48.54 l 7.62,-7.01 6.18,6.84 c 1.6,1.76 3.55,2.81 5.22,2.81 0.86,0 1.62,-0.28 2.2,-0.8 l 8.13,-7.36 c 0.96,-0.86 1.27,-2.27 0.86,-3.86 -0.32,-1.25 -1.08,-2.57 -2.12,-3.72 l -6.29,-6.96 54.75,-50.39 c 11.97,10.89 27.86,17.53 45.28,17.53 37.14,0 67.35,-30.21 67.35,-67.35 0,-37.14 -30.21,-67.35 -67.35,-67.35 -17.19,0 -32.88,6.48 -44.8,17.11 l -55.05,-50.66 6.11,-6.75 c 1.04,-1.15 1.79,-2.47 2.12,-3.72 0.41,-1.59 0.1,-3 -0.85,-3.86 l -8.13,-7.36 c -1.71,-1.54 -5.01,-0.65 -7.42,2.01 l -6,6.63 -7.36,-6.77 c 24.69,-24.82 56.89,-42.12 92.87,-48.18 -1.37,1.73 -2.21,4.06 -2.21,6.61 v 25.88 c 0,5.35 3.67,9.7 8.18,9.7 h 4.95 v 0.22 35.72 c 0,2.55 0.98,4.94 2.77,6.72 1.78,1.78 4.16,2.76 6.71,2.76 l 65.28,-1.8 c 12.68,-0.35 22.59,9.43 22.59,21.97 v 122.9 c 0,12.26 -9.97,22.24 -22.23,22.24 l -65.39,-1.08 h -0.16 c -5.29,0.01 -9.58,4.31 -9.58,9.58 z M 78.68,250 c 0,-42.42 15.5,-81.28 41.14,-111.23 l 7.48,6.88 -7.02,7.76 c -1.04,1.15 -1.79,2.47 -2.12,3.72 -0.41,1.59 -0.1,3 0.85,3.86 l 8.13,7.36 c 0.58,0.52 1.34,0.8 2.2,0.8 1.68,0 3.63,-1.05 5.22,-2.81 l 6.91,-7.64 54.94,50.56 c -8.63,11.32 -13.77,25.44 -13.77,40.74 0,15.07 4.98,29.01 13.38,40.24 l -54.73,50.37 -6.73,-7.43 c -2.41,-2.66 -5.71,-3.56 -7.42,-2.01 l -8.13,7.36 c -0.96,0.86 -1.27,2.27 -0.86,3.86 0.32,1.25 1.08,2.57 2.12,3.72 l 6.83,7.55 -7.7,7.09 C 94.02,330.87 78.68,292.19 78.68,250 Z m 38.35,112.94 -6.24,5.74 C 83.48,336.7 66.96,295.25 66.96,250 c 0,-45.48 16.69,-87.12 44.24,-119.17 l 6.25,5.75 c -26.17,30.53 -42,70.16 -42,113.42 0,43.04 15.66,82.48 41.58,112.94 z M 185.88,250 c 0,-35.36 28.76,-64.12 64.12,-64.12 35.36,0 64.12,28.76 64.12,64.12 0,35Line truncated
|
|
||||||
id="path10"
|
|
||||||
style="fill:#60697a;fill-opacity:1" />
|
|
||||||
<circle
|
|
||||||
class="st1"
|
|
||||||
cx="227.46001"
|
|
||||||
cy="88.870003"
|
|
||||||
r="2.8299999"
|
|
||||||
id="circle12"
|
|
||||||
style="fill:#60697a;fill-opacity:1" />
|
|
||||||
<circle
|
|
||||||
class="st1"
|
|
||||||
cx="227.46001"
|
|
||||||
cy="112.45"
|
|
||||||
r="2.8299999"
|
|
||||||
id="circle14"
|
|
||||||
style="fill:#60697a;fill-opacity:1" />
|
|
||||||
<circle
|
|
||||||
class="st1"
|
|
||||||
cx="227.46001"
|
|
||||||
cy="100.66"
|
|
||||||
r="2.8299999"
|
|
||||||
id="circle16"
|
|
||||||
style="fill:#60697a;fill-opacity:1" />
|
|
||||||
<circle
|
|
||||||
class="st1"
|
|
||||||
cx="272.73999"
|
|
||||||
cy="88.870003"
|
|
||||||
r="2.8299999"
|
|
||||||
id="circle18"
|
|
||||||
style="fill:#60697a;fill-opacity:1" />
|
|
||||||
<circle
|
|
||||||
class="st1"
|
|
||||||
cx="272.73999"
|
|
||||||
cy="112.45"
|
|
||||||
r="2.8299999"
|
|
||||||
id="circle20"
|
|
||||||
style="fill:#60697a;fill-opacity:1" />
|
|
||||||
<circle
|
|
||||||
class="st1"
|
|
||||||
cx="272.73999"
|
|
||||||
cy="100.66"
|
|
||||||
r="2.8299999"
|
|
||||||
id="circle22"
|
|
||||||
style="fill:#60697a;fill-opacity:1" />
|
|
||||||
<circle
|
|
||||||
class="st1"
|
|
||||||
cx="227.46001"
|
|
||||||
cy="388.04001"
|
|
||||||
r="2.8299999"
|
|
||||||
id="circle24"
|
|
||||||
style="fill:#60697a;fill-opacity:1" />
|
|
||||||
<circle
|
|
||||||
class="st1"
|
|
||||||
cx="227.46001"
|
|
||||||
cy="411.62"
|
|
||||||
r="2.8299999"
|
|
||||||
id="circle26"
|
|
||||||
style="fill:#60697a;fill-opacity:1" />
|
|
||||||
<circle
|
|
||||||
class="st1"
|
|
||||||
cx="227.46001"
|
|
||||||
cy="399.82999"
|
|
||||||
r="2.8299999"
|
|
||||||
id="circle28"
|
|
||||||
style="fill:#60697a;fill-opacity:1" />
|
|
||||||
<circle
|
|
||||||
class="st1"
|
|
||||||
cx="272.73999"
|
|
||||||
cy="388.04001"
|
|
||||||
r="2.8299999"
|
|
||||||
id="circle30"
|
|
||||||
style="fill:#60697a;fill-opacity:1" />
|
|
||||||
<circle
|
|
||||||
class="st1"
|
|
||||||
cx="272.73999"
|
|
||||||
cy="411.62"
|
|
||||||
r="2.8299999"
|
|
||||||
id="circle32"
|
|
||||||
style="fill:#60697a;fill-opacity:1" />
|
|
||||||
<circle
|
|
||||||
class="st1"
|
|
||||||
cx="272.73999"
|
|
||||||
cy="399.82999"
|
|
||||||
r="2.8299999"
|
|
||||||
id="circle34"
|
|
||||||
style="fill:#60697a;fill-opacity:1" />
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 14 KiB |
+8
-5
@@ -1,11 +1,14 @@
|
|||||||
import { writable, get } from 'svelte/store';
|
import { writable } from 'svelte/store';
|
||||||
|
|
||||||
|
|
||||||
export let views = writable();
|
const VIEWS = import.meta.glob('../views/*.svelte', {eager: true});
|
||||||
export let currentView = writable();
|
export let currentView = writable();
|
||||||
export let previousView = writable();
|
|
||||||
|
|
||||||
export function navigate(viewName) {
|
export function navigate(viewName) {
|
||||||
let v = get(views)[`./views/${viewName}.svelte`].default;
|
let view = VIEWS[`../views/${viewName}.svelte`].default;
|
||||||
currentView.set(v)
|
currentView.set(view);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getView(viewName) {
|
||||||
|
return VIEWS[`../views/${viewName}.svelte`].default;
|
||||||
}
|
}
|
||||||
+1
-25
@@ -1,33 +1,9 @@
|
|||||||
import { writable, get } from 'svelte/store';
|
import { writable } from 'svelte/store';
|
||||||
|
|
||||||
import queue from './queue.js';
|
import queue from './queue.js';
|
||||||
import { navigate, currentView, previousView } from './routing.js';
|
|
||||||
|
|
||||||
|
|
||||||
export let appState = writable({
|
export let appState = writable({
|
||||||
currentRequest: null,
|
currentRequest: null,
|
||||||
pendingRequests: queue(),
|
pendingRequests: queue(),
|
||||||
credentialStatus: 'locked',
|
credentialStatus: 'locked',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
export async function acceptRequest() {
|
|
||||||
let req = await get(appState).pendingRequests.get();
|
|
||||||
appState.update($appState => {
|
|
||||||
$appState.currentRequest = req;
|
|
||||||
return $appState;
|
|
||||||
});
|
|
||||||
previousView.set(get(currentView));
|
|
||||||
navigate('Approve');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export function completeRequest() {
|
|
||||||
appState.update($appState => {
|
|
||||||
$appState.currentRequest = null;
|
|
||||||
return $appState;
|
|
||||||
});
|
|
||||||
currentView.set(get(previousView));
|
|
||||||
previousView.set(null);
|
|
||||||
acceptRequest();
|
|
||||||
}
|
|
||||||
@@ -1,7 +1,3 @@
|
|||||||
@tailwind base;
|
@tailwind base;
|
||||||
@tailwind components;
|
@tailwind components;
|
||||||
@tailwind utilities;
|
@tailwind utilities;
|
||||||
|
|
||||||
.btn-alert-error {
|
|
||||||
@apply bg-transparent hover:bg-[#cd5a5a] border border-error-content text-error-content
|
|
||||||
}
|
|
||||||
@@ -2,8 +2,6 @@
|
|||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import { slide } from 'svelte/transition';
|
import { slide } from 'svelte/transition';
|
||||||
|
|
||||||
let extraClasses = "";
|
|
||||||
export {extraClasses as class};
|
|
||||||
export let slideDuration = 150;
|
export let slideDuration = 150;
|
||||||
let animationClass = "";
|
let animationClass = "";
|
||||||
|
|
||||||
@@ -51,7 +49,7 @@
|
|||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|
||||||
<div in:slide="{{duration: slideDuration}}" class="alert alert-error shadow-lg {animationClass} {extraClasses}">
|
<div in:slide="{{duration: slideDuration}}" class="alert alert-error shadow-lg {animationClass}">
|
||||||
<div>
|
<div>
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" class="stroke-current flex-shrink-0 h-6 w-6" fill="none" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z" /></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" class="stroke-current flex-shrink-0 h-6 w-6" fill="none" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z" /></svg>
|
||||||
<span>
|
<span>
|
||||||
|
|||||||
+6
-6
@@ -1,5 +1,5 @@
|
|||||||
<script>
|
<script>
|
||||||
import { navigate } from '../lib/routing.js';
|
import { navigate, currentView } from '../lib/routing.js';
|
||||||
|
|
||||||
export let target;
|
export let target;
|
||||||
export let hotkey = null;
|
export let hotkey = null;
|
||||||
@@ -7,9 +7,6 @@
|
|||||||
export let alt = false;
|
export let alt = false;
|
||||||
export let shift = false;
|
export let shift = false;
|
||||||
|
|
||||||
let classes = "";
|
|
||||||
export {classes as class};
|
|
||||||
|
|
||||||
function click() {
|
function click() {
|
||||||
if (typeof target === 'string') {
|
if (typeof target === 'string') {
|
||||||
navigate(target);
|
navigate(target);
|
||||||
@@ -29,7 +26,10 @@
|
|||||||
if (alt && !event.altKey) return;
|
if (alt && !event.altKey) return;
|
||||||
if (shift && !event.shiftKey) return;
|
if (shift && !event.shiftKey) return;
|
||||||
|
|
||||||
if (event.key === hotkey) {
|
if (event.code === hotkey) {
|
||||||
|
click();
|
||||||
|
}
|
||||||
|
else if (hotkey === 'Enter' && event.code === 'NumpadEnter') {
|
||||||
click();
|
click();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -38,6 +38,6 @@
|
|||||||
|
|
||||||
<svelte:window on:keydown={handleHotkey} />
|
<svelte:window on:keydown={handleHotkey} />
|
||||||
|
|
||||||
<a href="/{target}" on:click|preventDefault="{click}" class={classes}>
|
<a href="#" on:click="{click}">
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</a>
|
</a>
|
||||||
+4
-10
@@ -1,27 +1,21 @@
|
|||||||
<script>
|
<script>
|
||||||
import Link from './Link.svelte';
|
import Link from './Link.svelte';
|
||||||
import Icon from './Icon.svelte';
|
import Icon from './Icon.svelte';
|
||||||
|
|
||||||
export let position = "sticky";
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
<nav class="{position} top-0 bg-base-100 w-full flex justify-between items-center p-2">
|
<nav class="fixed top-0 grid grid-cols-2 w-full p-2">
|
||||||
<div>
|
<div>
|
||||||
<Link target="Home">
|
<Link target="Home">
|
||||||
<button class="btn btn-square btn-ghost align-middle">
|
<button class="btn btn-squre btn-ghost align-middle">
|
||||||
<Icon name="home" class="w-8 h-8 stroke-2" />
|
<Icon name="home" class="w-8 h-8 stroke-2" />
|
||||||
</button>
|
</button>
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{#if $$slots.title}
|
<div class="justify-self-end">
|
||||||
<slot name="title"></slot>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<Link target="Settings">
|
<Link target="Settings">
|
||||||
<button class="btn btn-square btn-ghost align-middle ">
|
<button class="align-middle btn btn-square btn-ghost">
|
||||||
<Icon name="cog-8-tooth" class="w-8 h-8 stroke-2" />
|
<Icon name="cog-8-tooth" class="w-8 h-8 stroke-2" />
|
||||||
</button>
|
</button>
|
||||||
</Link>
|
</Link>
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
<script>
|
||||||
|
export let title;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="divider"></div>
|
||||||
|
<div class="grid grid-cols-2 items-center">
|
||||||
|
<h3 class="text-lg font-bold">{title}</h3>
|
||||||
|
<slot name="input"></slot>
|
||||||
|
</div>
|
||||||
|
<p class="mt-3">
|
||||||
|
<slot name="description"></slot>
|
||||||
|
</p>
|
||||||
@@ -1,113 +0,0 @@
|
|||||||
<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>
|
|
||||||
@@ -1,80 +0,0 @@
|
|||||||
<script>
|
|
||||||
import { createEventDispatcher } from 'svelte';
|
|
||||||
|
|
||||||
import Setting from './Setting.svelte';
|
|
||||||
|
|
||||||
export let title;
|
|
||||||
export let value;
|
|
||||||
export let unit = '';
|
|
||||||
export let min = null;
|
|
||||||
export let max = null;
|
|
||||||
export let decimal = false;
|
|
||||||
|
|
||||||
const dispatch = createEventDispatcher();
|
|
||||||
|
|
||||||
$: localValue = value.toString();
|
|
||||||
let lastInputTime = null;
|
|
||||||
function debounce(event) {
|
|
||||||
lastInputTime = Date.now();
|
|
||||||
localValue = localValue.replace(/[^-0-9.]/g, '');
|
|
||||||
|
|
||||||
const eventTime = lastInputTime;
|
|
||||||
const pendingValue = localValue;
|
|
||||||
window.setTimeout(
|
|
||||||
() => {
|
|
||||||
// if no other inputs have occured since then
|
|
||||||
if (eventTime === lastInputTime) {
|
|
||||||
updateValue(pendingValue);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
500
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
let error = null;
|
|
||||||
function updateValue(newValue) {
|
|
||||||
// Don't update the value, but also don't error, if it's empty
|
|
||||||
// or if it could be the start of a negative or decimal number
|
|
||||||
if (newValue.match(/^$|^-$|^\.$/) !== null) {
|
|
||||||
error = null;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const num = parseFloat(newValue);
|
|
||||||
if (num % 1 !== 0 && !decimal) {
|
|
||||||
error = `${num} is not a whole number`;
|
|
||||||
}
|
|
||||||
else if (min !== null && num < min) {
|
|
||||||
error = `Too low (minimum ${min})`;
|
|
||||||
}
|
|
||||||
else if (max !== null && num > max) {
|
|
||||||
error = `Too large (maximum ${max})`
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
error = null;
|
|
||||||
value = num;
|
|
||||||
dispatch('update', {value})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<Setting {title}>
|
|
||||||
<div slot="input">
|
|
||||||
{#if unit}
|
|
||||||
<span class="mr-2">{unit}:</span>
|
|
||||||
{/if}
|
|
||||||
<div class="tooltip tooltip-error" class:tooltip-open={error !== null} data-tip="{error}">
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
class="input input-sm input-bordered text-right"
|
|
||||||
size="{Math.max(5, localValue.length)}"
|
|
||||||
class:input-error={error}
|
|
||||||
bind:value={localValue}
|
|
||||||
on:input="{debounce}"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<slot name="description" slot="description"></slot>
|
|
||||||
</Setting>
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
<script>
|
|
||||||
import { slide } from 'svelte/transition';
|
|
||||||
import ErrorAlert from '../ErrorAlert.svelte';
|
|
||||||
|
|
||||||
export let title;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<div class="divider"></div>
|
|
||||||
<div class="flex justify-between">
|
|
||||||
<h3 class="text-lg font-bold">{title}</h3>
|
|
||||||
<slot name="input"></slot>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{#if $$slots.description}
|
|
||||||
<p class="mt-3">
|
|
||||||
<slot name="description"></slot>
|
|
||||||
</p>
|
|
||||||
{/if}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
<script>
|
|
||||||
import { createEventDispatcher } from 'svelte';
|
|
||||||
|
|
||||||
import Setting from './Setting.svelte';
|
|
||||||
|
|
||||||
export let title;
|
|
||||||
export let value;
|
|
||||||
|
|
||||||
const dispatch = createEventDispatcher();
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<Setting {title}>
|
|
||||||
<input
|
|
||||||
slot="input"
|
|
||||||
type="checkbox"
|
|
||||||
class="toggle toggle-success"
|
|
||||||
bind:checked={value}
|
|
||||||
on:change={e => dispatch('update', {value: e.target.checked})}
|
|
||||||
/>
|
|
||||||
<slot name="description" slot="description"></slot>
|
|
||||||
</Setting>
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
export { default as Setting } from './Setting.svelte';
|
|
||||||
export { default as ToggleSetting } from './ToggleSetting.svelte';
|
|
||||||
export { default as NumericSetting } from './NumericSetting.svelte';
|
|
||||||
+11
-78
@@ -1,35 +1,16 @@
|
|||||||
<script>
|
<script>
|
||||||
import { onMount } from 'svelte';
|
|
||||||
import { invoke } from '@tauri-apps/api/tauri';
|
import { invoke } from '@tauri-apps/api/tauri';
|
||||||
|
|
||||||
import { navigate } from '../lib/routing.js';
|
import { navigate } from '../lib/routing.js';
|
||||||
import { appState, completeRequest } from '../lib/state.js';
|
import { appState } from '../lib/state.js';
|
||||||
import ErrorAlert from '../ui/ErrorAlert.svelte';
|
|
||||||
import Link from '../ui/Link.svelte';
|
import Link from '../ui/Link.svelte';
|
||||||
|
import Icon from '../ui/Icon.svelte';
|
||||||
|
|
||||||
|
|
||||||
// Send response to backend, display error if applicable
|
|
||||||
let error, alert;
|
|
||||||
async function respond() {
|
|
||||||
let {id, approval} = $appState.currentRequest;
|
|
||||||
try {
|
|
||||||
await invoke('respond', {response: {id, approval}});
|
|
||||||
navigate('ShowResponse');
|
|
||||||
}
|
|
||||||
catch (e) {
|
|
||||||
if (error) {
|
|
||||||
alert.shake();
|
|
||||||
}
|
|
||||||
error = e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Approval has one of several outcomes depending on current credential state
|
|
||||||
async function approve() {
|
async function approve() {
|
||||||
$appState.currentRequest.approval = 'Approved';
|
|
||||||
let status = await invoke('get_session_status');
|
let status = await invoke('get_session_status');
|
||||||
if (status === 'unlocked') {
|
if (status === 'unlocked') {
|
||||||
await respond();
|
navigate('ShowApproved');
|
||||||
}
|
}
|
||||||
else if (status === 'locked') {
|
else if (status === 'locked') {
|
||||||
navigate('Unlock');
|
navigate('Unlock');
|
||||||
@@ -39,81 +20,34 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Denial has only one
|
var appName = null;
|
||||||
async function deny() {
|
|
||||||
$appState.currentRequest.approval = 'Denied';
|
|
||||||
await respond();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extract executable name from full path
|
|
||||||
let appName = null;
|
|
||||||
if ($appState.currentRequest.clients.length === 1) {
|
if ($appState.currentRequest.clients.length === 1) {
|
||||||
let path = $appState.currentRequest.clients[0].exe;
|
let path = $appState.currentRequest.clients[0].exe;
|
||||||
let m = path.match(/\/([^/]+?$)|\\([^\\]+?$)/);
|
let m = path.match(/\/([^/]+?$)|\\([^\\]+?$)/);
|
||||||
appName = m[1] || m[2];
|
appName = m[1] || m[2];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Executable paths can be long, so ensure they only break on \ or /
|
|
||||||
function breakPath(client) {
|
|
||||||
return client.exe.replace(/(\\|\/)/g, '$1<wbr>');
|
|
||||||
}
|
|
||||||
|
|
||||||
// if the request has already been approved/denied, send response immediately
|
|
||||||
onMount(async () => {
|
|
||||||
if ($appState.currentRequest.approval) {
|
|
||||||
await respond();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
<!-- Don't render at all if we're just going to immediately proceed to the next screen -->
|
<div class="flex flex-col space-y-4 p-4 m-auto max-w-max h-screen justify-center">
|
||||||
{#if error || !$appState.currentRequest.approval}
|
<!-- <div class="p-4 rounded-box border-2 border-neutral-content"> -->
|
||||||
<div class="flex flex-col space-y-4 p-4 m-auto max-w-xl h-screen items-center justify-center">
|
|
||||||
{#if error}
|
|
||||||
<ErrorAlert bind:this={alert}>
|
|
||||||
{error}
|
|
||||||
<svelte:fragment slot="buttons">
|
|
||||||
<button class="btn btn-sm btn-alert-error" on:click={completeRequest}>Cancel</button>
|
|
||||||
<button class="btn btn-sm btn-alert-error" on:click={respond}>Retry</button>
|
|
||||||
</svelte:fragment>
|
|
||||||
</ErrorAlert>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
{#if $appState.currentRequest.base}
|
|
||||||
<div class="alert alert-warning shadow-lg">
|
|
||||||
<div>
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" class="stroke-current flex-shrink-0 h-6 w-6" fill="none" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" /></svg>
|
|
||||||
<span>
|
|
||||||
WARNING: This application is requesting your base (long-lived) AWS credentials.
|
|
||||||
These credentials are less secure than session credentials, since they don't expire automatically.
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
<div class="space-y-1 mb-4">
|
<div class="space-y-1 mb-4">
|
||||||
<h2 class="text-xl font-bold">{appName ? `"${appName}"` : 'An appplication'} would like to access your AWS credentials.</h2>
|
<h2 class="text-xl font-bold">{appName ? `"${appName}"` : 'An appplication'} would like to access your AWS credentials.</h2>
|
||||||
|
|
||||||
<div class="grid grid-cols-[auto_1fr] gap-x-3">
|
|
||||||
{#each $appState.currentRequest.clients as client}
|
{#each $appState.currentRequest.clients as client}
|
||||||
<div class="text-right">Path:</div>
|
<p>Path: {client ? client.exe : 'Unknown'}</p>
|
||||||
<code class="">{@html client ? breakPath(client) : 'Unknown'}</code>
|
<p>PID: {client ? client.pid : 'Unknown'}</p>
|
||||||
<div class="text-right">PID:</div>
|
|
||||||
<code>{client ? client.pid : 'Unknown'}</code>
|
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="w-full flex justify-between">
|
<div class="grid grid-cols-2">
|
||||||
<Link target={deny} hotkey="Escape">
|
<Link target="ShowDenied" hotkey="Escape">
|
||||||
<button class="btn btn-error justify-self-start">
|
<button class="btn btn-error justify-self-start">
|
||||||
Deny
|
Deny
|
||||||
<kbd class="ml-2 normal-case px-1 py-0.5 rounded border border-neutral">Esc</kbd>
|
<kbd class="ml-2 normal-case px-1 py-0.5 rounded border border-neutral">Esc</kbd>
|
||||||
</button>
|
</button>
|
||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
<Link target={approve} hotkey="Enter" shift="{true}">
|
<Link target="{approve}" hotkey="Enter" shift="{true}">
|
||||||
<button class="btn btn-success justify-self-end">
|
<button class="btn btn-success justify-self-end">
|
||||||
Approve
|
Approve
|
||||||
<kbd class="ml-2 normal-case px-1 py-0.5 rounded border border-neutral">Shift</kbd>
|
<kbd class="ml-2 normal-case px-1 py-0.5 rounded border border-neutral">Shift</kbd>
|
||||||
@@ -123,4 +57,3 @@
|
|||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
|
||||||
@@ -7,32 +7,20 @@
|
|||||||
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;
|
||||||
let alert;
|
let alert;
|
||||||
let AccessKeyId, SecretAccessKey, passphrase, confirmPassphrase
|
let AccessKeyId, SecretAccessKey, passphrase
|
||||||
|
|
||||||
function confirm() {
|
|
||||||
if (passphrase !== confirmPassphrase) {
|
|
||||||
errorMsg = 'Passphrases do not match.'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let saving = false;
|
|
||||||
async function save() {
|
async function save() {
|
||||||
if (passphrase !== confirmPassphrase) {
|
console.log('Saving credentials.');
|
||||||
alert.shake();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
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('ShowApproved');
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
navigate('Home');
|
navigate('Home');
|
||||||
@@ -50,8 +38,6 @@
|
|||||||
if (alert) {
|
if (alert) {
|
||||||
alert.shake();
|
alert.shake();
|
||||||
}
|
}
|
||||||
|
|
||||||
saving = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
@@ -68,15 +54,8 @@
|
|||||||
<input type="text" placeholder="AWS Access Key ID" bind:value="{AccessKeyId}" class="input input-bordered" />
|
<input type="text" placeholder="AWS Access Key ID" bind:value="{AccessKeyId}" class="input input-bordered" />
|
||||||
<input type="password" placeholder="AWS Secret Access Key" bind:value="{SecretAccessKey}" class="input input-bordered" />
|
<input type="password" placeholder="AWS Secret Access Key" bind:value="{SecretAccessKey}" class="input input-bordered" />
|
||||||
<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} />
|
|
||||||
|
|
||||||
<button type="submit" class="btn btn-primary">
|
<input 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>
|
||||||
|
|||||||
+14
-21
@@ -8,41 +8,34 @@
|
|||||||
import Icon from '../ui/Icon.svelte';
|
import Icon from '../ui/Icon.svelte';
|
||||||
import Link from '../ui/Link.svelte';
|
import Link from '../ui/Link.svelte';
|
||||||
|
|
||||||
import vaultDoorSvg from '../assets/vault_door.svg?raw';
|
|
||||||
|
|
||||||
|
onMount(async () => {
|
||||||
// onMount(async () => {
|
// will block until a request comes in
|
||||||
// // will block until a request comes in
|
let req = await $appState.pendingRequests.get();
|
||||||
// let req = await $appState.pendingRequests.get();
|
$appState.currentRequest = req;
|
||||||
// $appState.currentRequest = req;
|
navigate('Approve');
|
||||||
// navigate('Approve');
|
});
|
||||||
// });
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
<Nav position="fixed">
|
<Nav />
|
||||||
<h2 slot="title" class="text-3xl font-bold">Creddy</h2>
|
|
||||||
</Nav>
|
|
||||||
|
|
||||||
<div class="flex flex-col h-screen items-center justify-center p-4 space-y-4">
|
<div class="flex flex-col h-screen justify-center items-center space-y-4">
|
||||||
{#await invoke('get_session_status') then status}
|
{#await invoke('get_session_status') then status}
|
||||||
{#if status === 'locked'}
|
{#if status === 'locked'}
|
||||||
|
<img src="/static/padlock-closed.svg" alt="A locked padlock" class="w-32" />
|
||||||
{@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">
|
||||||
<button class="btn btn-primary w-full">Unlock</button>
|
<button class="btn btn-primary">Unlock</button>
|
||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
{:else if status === 'unlocked'}
|
{:else if status === 'unlocked'}
|
||||||
{@html vaultDoorSvg}
|
<img src="/static/padlock-open.svg" alt="An unlocked padlock" class="w-24" />
|
||||||
<h2 class="text-2xl font-bold">Waiting for requests</h2>
|
<h2 class="text-2xl font-bold">Waiting for requests</h2>
|
||||||
|
|
||||||
{:else if status === 'empty'}
|
{:else if status === 'empty'}
|
||||||
{@html vaultDoorSvg}
|
<Link target="EnterCredentials">
|
||||||
<h2 class="text-2xl font-bold">No credentials found</h2>
|
<button class="btn btn-primary">Enter Credentials</button>
|
||||||
<Link target="EnterCredentials" hotkey="Enter" class="w-64">
|
|
||||||
<button class="btn btn-primary w-full">Enter Credentials</button>
|
|
||||||
</Link>
|
</Link>
|
||||||
{/if}
|
{/if}
|
||||||
{/await}
|
{/await}
|
||||||
|
|||||||
+35
-64
@@ -1,94 +1,65 @@
|
|||||||
<script>
|
<script>
|
||||||
import { invoke } from '@tauri-apps/api/tauri';
|
import { invoke } from '@tauri-apps/api/tauri';
|
||||||
import { type } from '@tauri-apps/api/os';
|
window.invoke = invoke;
|
||||||
|
|
||||||
import { appState } from '../lib/state.js';
|
import { appState } from '../lib/state.js';
|
||||||
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 Setting from '../ui/Setting.svelte';
|
||||||
import ErrorAlert from '../ui/ErrorAlert.svelte';
|
import ErrorAlert from '../ui/ErrorAlert.svelte';
|
||||||
import { Setting, ToggleSetting, NumericSetting } from '../ui/settings';
|
|
||||||
|
|
||||||
import { fly } from 'svelte/transition';
|
|
||||||
import { backInOut } from 'svelte/easing';
|
|
||||||
|
|
||||||
|
|
||||||
let error = null;
|
|
||||||
async function save() {
|
async function save() {
|
||||||
try {
|
try {
|
||||||
await invoke('save_config', {config: $appState.config});
|
await invoke('save_config', {config: $appState.config});
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
error = e;
|
|
||||||
$appState.config = await invoke('get_config');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let osType = '';
|
}
|
||||||
type().then(t => osType = t);
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
<Nav>
|
<Nav />
|
||||||
<h2 slot="title" class="text-2xl font-bold">Settings</h2>
|
|
||||||
</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="mx-auto mt-3 max-w-md">
|
||||||
<!-- <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}>
|
<Setting title="Start minimized">
|
||||||
<svelte:fragment slot="description">
|
<input slot="input" type="checkbox" bind:checked="{$appState.config.start_minimized}" class="justify-self-end toggle toggle-success" />
|
||||||
Start Creddy when you log in to your computer.
|
<svelte:fragment slot="description">Minimize to the system tray at startup.</svelte:fragment>
|
||||||
</svelte:fragment>
|
</Setting>
|
||||||
</ToggleSetting>
|
|
||||||
|
|
||||||
<ToggleSetting title="Start minimized" bind:value={$appState.config.start_minimized} on:update={save}>
|
<div class="divider"></div>
|
||||||
<svelte:fragment slot="description">
|
<div class="grid grid-cols-2 items-center">
|
||||||
Minimize to the system tray at startup.
|
<h3 class="text-lg font-bold">Start minimized</h3>
|
||||||
</svelte:fragment>
|
<input type="checkbox" bind:checked="{$appState.config.start_minimized}" class="justify-self-end toggle toggle-success" />
|
||||||
</ToggleSetting>
|
</div>
|
||||||
|
<p class="mt-3">Minimize to the system tray at startup.</p>
|
||||||
|
|
||||||
<NumericSetting title="Re-hide delay" bind:value={$appState.config.rehide_ms} min={0} unit="Milliseconds" on:update={save}>
|
<div class="divider"></div>
|
||||||
<svelte:fragment slot="description">
|
<div class="grid grid-cols-2 items-center">
|
||||||
|
<h3 class="text-lg font-bold">Re-hide delay</h3>
|
||||||
|
<div class="justify-self-end">
|
||||||
|
<span class="mr-2">(Milliseconds)</span>
|
||||||
|
<input type="text" bind:value="{$appState.config.rehide_ms}" class="input input-sm input-bordered text-right max-w-[4rem]" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p class="mt-3">
|
||||||
How long to wait after a request is approved/denied before minimizing
|
How long to wait after a request is approved/denied before minimizing
|
||||||
the window to tray. Only applicable if the window was minimized
|
the window to tray. Only applicable if the window was minimized
|
||||||
to tray before the request was received.
|
to tray before the request was received.
|
||||||
</svelte:fragment>
|
</p>
|
||||||
</NumericSetting>
|
|
||||||
|
|
||||||
<NumericSetting
|
<div class="divider"></div>
|
||||||
title="Listen port"
|
<div class="grid grid-cols-2 items-center">
|
||||||
bind:value={$appState.config.listen_port}
|
<h3 class="text-lg font-bold">Update credentials</h3>
|
||||||
min={osType === 'Windows_NT' ? 1 : 0}
|
<div class="justify-self-end">
|
||||||
on:update={save}
|
<Link target="EnterCredentials">
|
||||||
>
|
|
||||||
<svelte:fragment slot="description">
|
|
||||||
Listen for credentials requests on this port.
|
|
||||||
(Should be used with <code>$AWS_CONTAINER_CREDENTIALS_FULL_URI</code>)
|
|
||||||
</svelte:fragment>
|
|
||||||
</NumericSetting>
|
|
||||||
|
|
||||||
<Setting title="Update credentials">
|
|
||||||
<Link slot="input" target="EnterCredentials">
|
|
||||||
<button class="btn btn-sm btn-primary">Update</button>
|
<button class="btn btn-sm btn-primary">Update</button>
|
||||||
</Link>
|
</Link>
|
||||||
<svelte:fragment slot="description">
|
</div>
|
||||||
Update or re-enter your encrypted credentials.
|
</div>
|
||||||
</svelte:fragment>
|
<p class="mt-3">Update or re-enter your encrypted credentials.</p>
|
||||||
</Setting>
|
|
||||||
</div>
|
</div>
|
||||||
{/await}
|
{/await}
|
||||||
|
|
||||||
{#if error}
|
|
||||||
<div transition:fly={{y: 100, easing: backInOut, duration: 400}} class="toast">
|
|
||||||
<div class="alert alert-error no-animation">
|
|
||||||
<div>
|
|
||||||
<span>{error}</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<button class="btn btn-sm btn-alert-error" on:click={() => error = null}>Ok</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
<script>
|
||||||
|
import { onMount } from 'svelte';
|
||||||
|
import { draw, fade } from 'svelte/transition';
|
||||||
|
import { emit } from '@tauri-apps/api/event';
|
||||||
|
import { invoke } from '@tauri-apps/api/tauri';
|
||||||
|
|
||||||
|
import { appState } from '../lib/state.js';
|
||||||
|
import { navigate } from '../lib/routing.js';
|
||||||
|
import ErrorAlert from '../ui/ErrorAlert.svelte';
|
||||||
|
import Icon from '../ui/Icon.svelte';
|
||||||
|
import Link from '../ui/Link.svelte';
|
||||||
|
|
||||||
|
let success = false;
|
||||||
|
let error = null;
|
||||||
|
|
||||||
|
async function respond() {
|
||||||
|
let response = {
|
||||||
|
id: $appState.currentRequest.id,
|
||||||
|
approval: 'Approved',
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
await invoke('respond', {response});
|
||||||
|
success = true;
|
||||||
|
$appState.currentRequest = null;
|
||||||
|
window.setTimeout(() => navigate('Home'), 1000);
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
error = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onMount(respond);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
:global(body) {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
{#if error}
|
||||||
|
<div class="flex flex-col h-screen items-center justify-center m-auto max-w-lg">
|
||||||
|
<ErrorAlert>
|
||||||
|
{error}
|
||||||
|
<svelte:fragment slot="buttons">
|
||||||
|
<Link target="Home">
|
||||||
|
<button class="btn btn-sm bg-transparent hover:bg-[#cd5a5a] border border-error-content text-error-content">
|
||||||
|
Ok
|
||||||
|
</button>
|
||||||
|
</Link>
|
||||||
|
</svelte:fragment>
|
||||||
|
</ErrorAlert>
|
||||||
|
</div>
|
||||||
|
{:else if success}
|
||||||
|
<div class="flex flex-col h-screen items-center justify-center max-w-max m-auto">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="w-36 h-36" fill="none" viewBox="0 0 24 24" stroke-width="1" stroke="currentColor">
|
||||||
|
<path in:draw="{{duration: 500}}" stroke-linecap="round" stroke-linejoin="round" d="M9 12.75L11.25 15 15 9.75M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
|
||||||
|
<div in:fade="{{delay: 200, duration: 300}}" class="text-2xl font-bold">Approved!</div>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
{#if error}
|
||||||
|
<div class="text-red-400">{error}</div>
|
||||||
|
{:else}
|
||||||
|
<h1 class="text-4xl text-gray-300">Approved!</h1>
|
||||||
|
{/if}
|
||||||
|
-->
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
<script>
|
||||||
|
import { onMount } from 'svelte';
|
||||||
|
import { draw, fade } from 'svelte/transition';
|
||||||
|
import { emit } from '@tauri-apps/api/event';
|
||||||
|
import { invoke } from '@tauri-apps/api/tauri';
|
||||||
|
|
||||||
|
import { appState } from '../lib/state.js';
|
||||||
|
import { navigate } from '../lib/routing.js';
|
||||||
|
import ErrorAlert from '../ui/ErrorAlert.svelte';
|
||||||
|
import Icon from '../ui/Icon.svelte';
|
||||||
|
import Link from '../ui/Link.svelte';
|
||||||
|
|
||||||
|
let error = null;
|
||||||
|
|
||||||
|
async function respond() {
|
||||||
|
let response = {
|
||||||
|
id: $appState.currentRequest.id,
|
||||||
|
approval: 'Denied',
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await invoke('respond', {response});
|
||||||
|
$appState.currentRequest = null;
|
||||||
|
window.setTimeout(() => navigate('Home'), 1000);
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
error = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onMount(respond);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if error}
|
||||||
|
<div class="flex flex-col h-screen items-center justify-center m-auto max-w-lg">
|
||||||
|
<ErrorAlert>
|
||||||
|
{error}
|
||||||
|
<svelte:fragment slot="buttons">
|
||||||
|
<Link target="Home">
|
||||||
|
<button class="btn btn-sm bg-transparent hover:bg-[#cd5a5a] border border-error-content text-error-content" on:click="{() => navigate('Home')}">
|
||||||
|
Ok
|
||||||
|
</button>
|
||||||
|
</Link>
|
||||||
|
</svelte:fragment>
|
||||||
|
</ErrorAlert>
|
||||||
|
</div>
|
||||||
|
{:else}
|
||||||
|
<div class="flex flex-col items-center justify-center h-screen max-w-max m-auto">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="w-36 h-36" fill="none" viewBox="0 0 24 24" stroke-width="1" stroke="currentColor">
|
||||||
|
<path in:draw="{{duration: 500}}" stroke-linecap="round" stroke-linejoin="round" d="M9.75 9.75l4.5 4.5m0-4.5l-4.5 4.5M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
<div in:fade="{{delay: 200, duration: 300}}" class="text-2xl font-bold">Denied!</div>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
<script>
|
|
||||||
import { onMount } from 'svelte';
|
|
||||||
import { draw, fade } from 'svelte/transition';
|
|
||||||
|
|
||||||
import { appState, completeRequest } from '../lib/state.js';
|
|
||||||
|
|
||||||
let success = false;
|
|
||||||
let error = null;
|
|
||||||
|
|
||||||
let drawDuration = $appState.config.rehide_ms >= 750 ? 500 : 0;
|
|
||||||
let fadeDuration = drawDuration * 0.6;
|
|
||||||
let fadeDelay = drawDuration * 0.4;
|
|
||||||
|
|
||||||
onMount(() => {
|
|
||||||
window.setTimeout(
|
|
||||||
completeRequest,
|
|
||||||
// Extra 50ms so the window can finish disappearing before the redraw
|
|
||||||
Math.min(5000, $appState.config.rehide_ms + 50),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<div class="flex flex-col h-screen items-center justify-center max-w-max m-auto">
|
|
||||||
{#if $appState.currentRequest.approval === 'Approved'}
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-36 h-36" fill="none" viewBox="0 0 24 24" stroke-width="1" stroke="currentColor">
|
|
||||||
<path in:draw="{{duration: drawDuration}}" stroke-linecap="round" stroke-linejoin="round" d="M9 12.75L11.25 15 15 9.75M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
|
||||||
</svg>
|
|
||||||
{:else}
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-36 h-36" fill="none" viewBox="0 0 24 24" stroke-width="1" stroke="currentColor">
|
|
||||||
<path in:draw="{{duration: 500}}" stroke-linecap="round" stroke-linejoin="round" d="M9.75 9.75l4.5 4.5m0-4.5l-4.5 4.5M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
|
||||||
</svg>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
<div in:fade="{{duration: fadeDuration, delay: fadeDelay}}" class="text-2xl font-bold">
|
|
||||||
{$appState.currentRequest.approval}!
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
+3
-28
@@ -1,39 +1,29 @@
|
|||||||
<script>
|
<script>
|
||||||
import { invoke } from '@tauri-apps/api/tauri';
|
import { invoke } from '@tauri-apps/api/tauri';
|
||||||
import { onMount } from 'svelte';
|
|
||||||
|
|
||||||
import { appState } from '../lib/state.js';
|
import { appState } from '../lib/state.js';
|
||||||
import { navigate } from '../lib/routing.js';
|
import { navigate } from '../lib/routing.js';
|
||||||
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 saving = false;
|
|
||||||
async function unlock() {
|
async function unlock() {
|
||||||
// The hotkey for navigating here from homepage is Enter, which also
|
|
||||||
// happens to trigger the form submit event
|
|
||||||
if (Date.now() - loadTime < 10) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
||||||
navigate('Approve');
|
navigate('ShowApproved');
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
navigate('Home');
|
navigate('Home');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
|
window.error = e;
|
||||||
if (e.code === 'GetSession') {
|
if (e.code === 'GetSession') {
|
||||||
let root = getRootCause(e);
|
let root = getRootCause(e);
|
||||||
errorMsg = `Error response from AWS (${root.code}): ${root.msg}`;
|
errorMsg = `Error response from AWS (${root.code}): ${root.msg}`;
|
||||||
@@ -42,18 +32,11 @@
|
|||||||
errorMsg = e.msg;
|
errorMsg = e.msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if the alert already existed, shake it
|
|
||||||
if (alert) {
|
if (alert) {
|
||||||
alert.shake();
|
alert.shake();
|
||||||
}
|
}
|
||||||
|
|
||||||
saving = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onMount(() => {
|
|
||||||
loadTime = Date.now();
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
@@ -64,17 +47,9 @@
|
|||||||
<ErrorAlert bind:this="{alert}">{errorMsg}</ErrorAlert>
|
<ErrorAlert bind:this="{alert}">{errorMsg}</ErrorAlert>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<!-- 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" />
|
||||||
|
|
||||||
<button type="submit" class="btn btn-primary">
|
<input 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>
|
||||||
|
|||||||
@@ -0,0 +1,430 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
width="96.957397mm"
|
||||||
|
height="136.61758mm"
|
||||||
|
viewBox="0 0 96.957397 136.61758"
|
||||||
|
version="1.1"
|
||||||
|
id="svg671"
|
||||||
|
inkscape:version="1.2 (dc2aedaf03, 2022-05-15)"
|
||||||
|
sodipodi:docname="padlock-closed.svg"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg">
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="namedview673"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#000000"
|
||||||
|
borderopacity="0.25"
|
||||||
|
inkscape:showpageshadow="2"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pagecheckerboard="0"
|
||||||
|
inkscape:deskcolor="#d1d1d1"
|
||||||
|
inkscape:document-units="mm"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="1.829812"
|
||||||
|
inkscape:cx="290.74025"
|
||||||
|
inkscape:cy="242.64788"
|
||||||
|
inkscape:window-width="2560"
|
||||||
|
inkscape:window-height="1377"
|
||||||
|
inkscape:window-x="-8"
|
||||||
|
inkscape:window-y="-8"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="layer1" />
|
||||||
|
<defs
|
||||||
|
id="defs668">
|
||||||
|
<filter
|
||||||
|
id="aa"
|
||||||
|
x="-0.074089691"
|
||||||
|
y="-0.050412808"
|
||||||
|
width="1.1481794"
|
||||||
|
height="1.1008256">
|
||||||
|
<feGaussianBlur
|
||||||
|
stdDeviation="9.8527"
|
||||||
|
id="feGaussianBlur11" />
|
||||||
|
</filter>
|
||||||
|
<radialGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#e"
|
||||||
|
id="radialGradient447"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(1,0,0,0.83226,1.428,126.14)"
|
||||||
|
cx="207.08"
|
||||||
|
cy="608.71997"
|
||||||
|
r="156.57001" />
|
||||||
|
<linearGradient
|
||||||
|
id="e">
|
||||||
|
<stop
|
||||||
|
stop-color="#d3bc5f"
|
||||||
|
offset="0"
|
||||||
|
id="stop49" />
|
||||||
|
<stop
|
||||||
|
stop-color="#c8ab37"
|
||||||
|
offset="1"
|
||||||
|
id="stop51" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#d"
|
||||||
|
id="linearGradient449"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
x1="201.44"
|
||||||
|
y1="1021.9"
|
||||||
|
x2="201.78"
|
||||||
|
y2="727.78003" />
|
||||||
|
<linearGradient
|
||||||
|
id="d">
|
||||||
|
<stop
|
||||||
|
stop-color="#806600"
|
||||||
|
offset="0"
|
||||||
|
id="stop44" />
|
||||||
|
<stop
|
||||||
|
stop-color="#806600"
|
||||||
|
stop-opacity="0"
|
||||||
|
offset="1"
|
||||||
|
id="stop46" />
|
||||||
|
</linearGradient>
|
||||||
|
<mask
|
||||||
|
id="b"
|
||||||
|
maskUnits="userSpaceOnUse">
|
||||||
|
<path
|
||||||
|
d="m -6.2978,665.08 h 288.15 a 12.498,12.498 0 0 1 12.498,12.498 v 235.62 a 12.498,12.498 0 0 1 -12.498,12.498 h -288.15 a 12.498,12.498 0 0 1 -12.498,-12.498 v -235.62 a 12.498,12.498 0 0 1 12.498,-12.498"
|
||||||
|
fill="#ffffff"
|
||||||
|
id="path81" />
|
||||||
|
</mask>
|
||||||
|
<filter
|
||||||
|
id="c"
|
||||||
|
x="-0.021572628"
|
||||||
|
y="-0.025823718"
|
||||||
|
width="1.0431453"
|
||||||
|
height="1.0516474">
|
||||||
|
<feGaussianBlur
|
||||||
|
stdDeviation="2.8688"
|
||||||
|
id="feGaussianBlur2" />
|
||||||
|
</filter>
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#a"
|
||||||
|
id="linearGradient451"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
x1="59.094002"
|
||||||
|
x2="357.94" />
|
||||||
|
<linearGradient
|
||||||
|
id="a"
|
||||||
|
x1="59.094002"
|
||||||
|
x2="357.94"
|
||||||
|
gradientUnits="userSpaceOnUse">
|
||||||
|
<stop
|
||||||
|
stop-color="#d4aa00"
|
||||||
|
offset="0"
|
||||||
|
id="stop54" />
|
||||||
|
<stop
|
||||||
|
stop-color="#fea"
|
||||||
|
offset=".5763"
|
||||||
|
id="stop56" />
|
||||||
|
<stop
|
||||||
|
stop-color="#d4aa00"
|
||||||
|
offset="1"
|
||||||
|
id="stop58" />
|
||||||
|
</linearGradient>
|
||||||
|
<filter
|
||||||
|
id="n"
|
||||||
|
x="-0.0021757265"
|
||||||
|
y="-0.0026762109"
|
||||||
|
width="1.0043515"
|
||||||
|
height="1.0053524">
|
||||||
|
<feGaussianBlur
|
||||||
|
stdDeviation=".2656"
|
||||||
|
id="feGaussianBlur5" />
|
||||||
|
</filter>
|
||||||
|
<radialGradient
|
||||||
|
id="t"
|
||||||
|
cx="207.08"
|
||||||
|
cy="608.71997"
|
||||||
|
r="156.57001"
|
||||||
|
gradientTransform="matrix(0.26458333,0,0,0.22020212,24.14876,-37.223301)"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
xlink:href="#e" />
|
||||||
|
<linearGradient
|
||||||
|
id="x"
|
||||||
|
x1="516.13"
|
||||||
|
x2="516.47998"
|
||||||
|
y1="1025.9"
|
||||||
|
y2="731.82001"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
xlink:href="#d"
|
||||||
|
gradientTransform="matrix(0.26458333,0,0,0.26458333,-59.491322,-71.669405)" />
|
||||||
|
<mask
|
||||||
|
id="mask602"
|
||||||
|
maskUnits="userSpaceOnUse">
|
||||||
|
<path
|
||||||
|
d="m -6.2978,665.08 h 288.15 a 12.498,12.498 0 0 1 12.498,12.498 v 235.62 a 12.498,12.498 0 0 1 -12.498,12.498 h -288.15 a 12.498,12.498 0 0 1 -12.498,-12.498 v -235.62 a 12.498,12.498 0 0 1 12.498,-12.498"
|
||||||
|
fill="#ffffff"
|
||||||
|
id="path600" />
|
||||||
|
</mask>
|
||||||
|
<filter
|
||||||
|
id="filter606"
|
||||||
|
x="-0.021572627"
|
||||||
|
y="-0.025823718"
|
||||||
|
width="1.0431453"
|
||||||
|
height="1.0516474">
|
||||||
|
<feGaussianBlur
|
||||||
|
stdDeviation="2.8688"
|
||||||
|
id="feGaussianBlur604" />
|
||||||
|
</filter>
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#k"
|
||||||
|
id="linearGradient453"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
x1="-692.91998"
|
||||||
|
y1="1521.9"
|
||||||
|
x2="-710.91998"
|
||||||
|
y2="1295.6" />
|
||||||
|
<linearGradient
|
||||||
|
id="k">
|
||||||
|
<stop
|
||||||
|
stop-color="#ccc"
|
||||||
|
offset="0"
|
||||||
|
id="stop37" />
|
||||||
|
<stop
|
||||||
|
stop-color="#fff"
|
||||||
|
offset=".6899"
|
||||||
|
id="stop39" />
|
||||||
|
<stop
|
||||||
|
stop-color="#e6e6e6"
|
||||||
|
offset="1"
|
||||||
|
id="stop41" />
|
||||||
|
</linearGradient>
|
||||||
|
<filter
|
||||||
|
id="l"
|
||||||
|
x="-0.063578956"
|
||||||
|
y="-0.35844691"
|
||||||
|
width="1.1271579"
|
||||||
|
height="1.7168938">
|
||||||
|
<feGaussianBlur
|
||||||
|
stdDeviation="3.4308"
|
||||||
|
id="feGaussianBlur34" />
|
||||||
|
</filter>
|
||||||
|
<filter
|
||||||
|
id="p"
|
||||||
|
x="-0.037389143"
|
||||||
|
y="-0.020053786"
|
||||||
|
width="1.0747783"
|
||||||
|
height="1.0401076">
|
||||||
|
<feGaussianBlur
|
||||||
|
result="result8"
|
||||||
|
stdDeviation="4"
|
||||||
|
id="feGaussianBlur20" />
|
||||||
|
<feComposite
|
||||||
|
in="result8"
|
||||||
|
in2="result8"
|
||||||
|
operator="xor"
|
||||||
|
result="result6"
|
||||||
|
id="feComposite22" />
|
||||||
|
<feDisplacementMap
|
||||||
|
in="result6"
|
||||||
|
in2="result6"
|
||||||
|
result="result4"
|
||||||
|
scale="80"
|
||||||
|
id="feDisplacementMap24"
|
||||||
|
xChannelSelector="A"
|
||||||
|
yChannelSelector="A" />
|
||||||
|
<feComposite
|
||||||
|
in="result8"
|
||||||
|
in2="result4"
|
||||||
|
k1="3"
|
||||||
|
operator="arithmetic"
|
||||||
|
result="result2"
|
||||||
|
id="feComposite26"
|
||||||
|
k2="0"
|
||||||
|
k3="0"
|
||||||
|
k4="0" />
|
||||||
|
<feComposite
|
||||||
|
in="result2"
|
||||||
|
in2="result2"
|
||||||
|
operator="in"
|
||||||
|
result="fbSourceGraphic"
|
||||||
|
id="feComposite28" />
|
||||||
|
</filter>
|
||||||
|
<mask
|
||||||
|
id="h"
|
||||||
|
maskUnits="userSpaceOnUse">
|
||||||
|
<path
|
||||||
|
d="m 1242.1,323.25 c -46.21,0.1434 -97.408,19.082 -119.06,62.688 -13.801,27.856 -8.4155,59.986 -10.594,89.938 -0.3932,36.847 -0.6396,73.715 -0.031,110.56 l 21.781,-1.5 -21.219,26.812 c 0.041,1.428 0.081,2.8534 0.125,4.2812 0.1398,29.944 38.758,3.7481 39.438,-16.312 -0.522,-60.445 -1.3603,-121 1.9063,-181.38 6.1489,-28.89 33.689,-48.001 61.812,-51.906 31.318,-5.1896 67.758,-3.053 92.781,18.562 17.831,14.267 21.591,37.115 19.031,58.469 -0.9481,114.24 -1.5396,228.53 -0.6875,342.75 7.8425,31.35 50.552,10.639 39.656,-16.625 -0.048,-118.23 -0.024,-236.48 1.2188,-354.69 -4.9781,-40.123 -37.945,-73.15 -76.125,-84 -16.133,-5.1758 -33.097,-7.6894 -50.031,-7.6562 z"
|
||||||
|
fill="#cccccc"
|
||||||
|
id="path78" />
|
||||||
|
</mask>
|
||||||
|
<filter
|
||||||
|
id="o"
|
||||||
|
x="-0.14145334"
|
||||||
|
y="-0.072653391"
|
||||||
|
width="1.2829067"
|
||||||
|
height="1.1453068">
|
||||||
|
<feGaussianBlur
|
||||||
|
stdDeviation="13.8123"
|
||||||
|
id="feGaussianBlur31" />
|
||||||
|
</filter>
|
||||||
|
<mask
|
||||||
|
id="g"
|
||||||
|
maskUnits="userSpaceOnUse">
|
||||||
|
<path
|
||||||
|
d="m -125.64,141.27 c -46.21,0.12373 -97.408,16.465 -119.06,54.089 -13.801,24.035 -8.4155,51.758 -10.594,77.602 -0.3932,31.793 -0.6396,63.604 -0.031,95.398 l 21.781,-1.2943 -21.219,23.135 c 0.041,1.2321 0.081,2.462 0.125,3.694 0.1398,25.837 38.758,3.234 39.437,-14.075 -0.522,-52.154 -1.3603,-104.4 1.9063,-156.5 6.1489,-24.928 33.689,-41.417 61.812,-44.787 31.318,-4.4778 67.758,-2.6342 92.781,16.016 17.831,12.31 21.591,32.024 19.031,50.449 -0.9481,98.57 -1.5396,197.19 -0.6875,295.74 7.8425,27.05 50.552,9.1799 39.656,-14.345 -0.048,-102.01 -0.024,-204.04 1.2188,-306.04 -4.9781,-34.62 -37.945,-63.117 -76.125,-72.479 -16.133,-4.4659 -33.097,-6.6347 -50.031,-6.6061 z"
|
||||||
|
fill="url(#y)"
|
||||||
|
id="path84" />
|
||||||
|
</mask>
|
||||||
|
<linearGradient
|
||||||
|
id="y"
|
||||||
|
x1="-100.13"
|
||||||
|
x2="-118.13"
|
||||||
|
y1="380.12"
|
||||||
|
y2="153.84"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
xlink:href="#k" />
|
||||||
|
<filter
|
||||||
|
id="m"
|
||||||
|
x="-0.03714728"
|
||||||
|
y="-0.023091114"
|
||||||
|
width="1.0742253"
|
||||||
|
height="1.0461927">
|
||||||
|
<feGaussianBlur
|
||||||
|
stdDeviation="3.3491"
|
||||||
|
id="feGaussianBlur8" />
|
||||||
|
</filter>
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#a"
|
||||||
|
id="linearGradient455"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
x1="59.094002"
|
||||||
|
x2="357.94"
|
||||||
|
gradientTransform="matrix(0.26458333,0,0,0.26458333,23.770406,-70.632556)" />
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient645"
|
||||||
|
x1="59.094002"
|
||||||
|
x2="357.94"
|
||||||
|
gradientUnits="userSpaceOnUse">
|
||||||
|
<stop
|
||||||
|
stop-color="#d4aa00"
|
||||||
|
offset="0"
|
||||||
|
id="stop639" />
|
||||||
|
<stop
|
||||||
|
stop-color="#fea"
|
||||||
|
offset=".5763"
|
||||||
|
id="stop641" />
|
||||||
|
<stop
|
||||||
|
stop-color="#d4aa00"
|
||||||
|
offset="1"
|
||||||
|
id="stop643" />
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(-28.735516,-33.775921)">
|
||||||
|
<g
|
||||||
|
transform="matrix(0.26458333,0,0,0.26458333,23.770406,-70.60033)"
|
||||||
|
id="g114">
|
||||||
|
<path
|
||||||
|
d="m 64.433,623.66 h 288.15 a 12.498,12.498 0 0 1 12.498,12.498 v 235.62 a 12.498,12.498 0 0 1 -12.498,12.498 H 64.433 A 12.498,12.498 0 0 1 51.935,871.778 V 636.158 A 12.498,12.498 0 0 1 64.433,623.66"
|
||||||
|
fill="url(#f)"
|
||||||
|
id="path104"
|
||||||
|
style="fill:url(#radialGradient447)" />
|
||||||
|
<path
|
||||||
|
d="m 64.433,623.66 h 288.15 a 12.498,12.498 0 0 1 12.498,12.498 v 235.62 a 12.498,12.498 0 0 1 -12.498,12.498 H 64.433 A 12.498,12.498 0 0 1 51.935,871.778 V 636.158 A 12.498,12.498 0 0 1 64.433,623.66"
|
||||||
|
fill="url(#j)"
|
||||||
|
id="path106"
|
||||||
|
style="fill:url(#linearGradient449)" />
|
||||||
|
<path
|
||||||
|
transform="translate(70.731,-41.416)"
|
||||||
|
d="m -6.2998,662.08 c -8.5337,0 -15.5,6.9663 -15.5,15.5 V 913.2 c 0,8.5337 6.9663,15.5 15.5,15.5 h 288.16 c 8.5337,0 15.5,-6.9663 15.5,-15.5 V 677.58 c 0,-8.5337 -6.9663,-15.5 -15.5,-15.5 z m 0,6 h 288.16 c 5.3135,0 9.5,4.1865 9.5,9.5 V 913.2 c 0,5.3135 -4.1865,9.5 -9.5,9.5 h -288.16 c -5.3135,0 -9.5,-4.1865 -9.5,-9.5 V 677.58 c 0,-5.3135 4.1865,-9.5 9.5,-9.5 z"
|
||||||
|
fill="#ffffff"
|
||||||
|
filter="url(#c)"
|
||||||
|
mask="url(#b)"
|
||||||
|
id="path108" />
|
||||||
|
<path
|
||||||
|
d="m 64.438,630.81 c -3.0883,0 -5.3438,2.2554 -5.3438,5.3438 v 235.62 c 0,3.0883 2.2554,5.3438 5.3438,5.3438 h 288.16 c 3.0883,0 5.3438,-2.2554 5.3438,-5.3438 v -235.62 c 0,-3.0883 -2.2554,-5.3438 -5.3438,-5.3438 z"
|
||||||
|
fill="url(#a)"
|
||||||
|
id="path110"
|
||||||
|
style="fill:url(#linearGradient451)" />
|
||||||
|
<path
|
||||||
|
d="m 65.691,637.37 c -0.0543,0.2253 -0.0937,0.4551 -0.0937,0.7188 v 1.3124 c 97.654,-0.4644 195.31,-0.674 292.97,-0.6562 v -0.6562 c 0,-0.033 8.7e-4,-0.0614 0,-0.0938 -97.624,0.0192 -195.25,-0.1507 -292.88,-0.625 z m -0.0937,9.5 v 1.9375 c 34.054,-0.1333 68.102,-0.2451 102.16,-0.3437 63.603,-0.1703 127.21,-0.2222 190.81,-0.1876 v -0.8437 c -63.054,0.0306 -126.1,-0.0178 -189.16,-0.1875 -34.601,-0.1011 -69.213,-0.237 -103.81,-0.375 z m 0,8.0938 v 2.0312 c 97.654,-0.4634 195.31,-0.6454 292.97,-0.625 v -0.75 c -97.655,0.0166 -195.31,-0.1808 -292.97,-0.6562 z m 0,9.5312 v 1.9062 c 34.054,-0.1319 68.102,-0.245 102.16,-0.3437 63.603,-0.1703 127.21,-0.2196 190.81,-0.1875 v -0.8438 c -63.054,0.0332 -126.1,-0.0178 -189.16,-0.1874 -34.601,-0.1011 -69.213,-0.2058 -103.81,-0.3438 z m 0,8.2188 v 1.75 c 97.654,-0.4031 195.31,-0.5301 292.97,-0.4688 v -0.8125 c -97.653,0.0582 -195.32,-0.0547 -292.97,-0.4687 z m 0,9.5 v 1.6874 c 23.617,-0.0835 47.258,-0.1815 70.875,-0.25 74.041,-0.1982 148.05,-0.2323 222.09,-0.1562 v -0.875 c -73.479,0.074 -146.96,0.0415 -220.44,-0.1562 -24.173,-0.0707 -48.358,-0.1632 -72.531,-0.25 z m 0,6.125 v 1.8124 c 97.655,-0.4141 195.31,-0.5537 292.97,-0.5 v -0.8124 c -97.659,0.0505 -195.31,-0.0746 -292.97,-0.5 z m 0,9.5312 v 1.6875 c 25.574,-0.0921 51.145,-0.1759 76.719,-0.25 72.082,-0.1929 144.17,-0.2239 216.25,-0.1563 v -0.875 c -71.532,0.0657 -143.06,0.0363 -214.59,-0.1562 -26.13,-0.0763 -52.245,-0.1543 -78.375,-0.25 z m 0,8.125 v 1.7188 c 97.656,-0.4013 195.31,-0.5308 292.97,-0.4688 v -0.8125 c -97.662,0.0626 -195.31,-0.029 -292.97,-0.4375 z m 0,9.4688 v 1.6562 c 22.961,-0.0807 45.945,-0.1522 68.906,-0.2188 74.686,-0.1999 149.37,-0.2352 224.06,-0.1562 v -0.875 c -74.138,0.0739 -148.27,0.0433 -222.41,-0.1562 -23.517,-0.0687 -47.047,-0.1668 -70.563,-0.25 z m 0,8 v 1.9687 c 97.657,-0.4569 195.31,-0.6169 292.97,-0.5937 v -0.7813 c -97.651,0.0245 -195.32,-0.127 -292.97,-0.5937 z m 0,9.5 v 1.9062 c 32.741,-0.1265 65.509,-0.2489 98.25,-0.3438 64.916,-0.1738 129.8,-0.2268 194.72,-0.1874 v -0.8438 c -64.356,0.0352 -128.71,-0.0143 -193.06,-0.1875 -33.298,-0.0973 -66.609,-0.2127 -99.906,-0.3437 z m 0,8.0937 v 2 c 97.657,-0.4557 195.31,-0.6507 292.97,-0.625 v -0.75 c -97.651,0.0219 -195.32,-0.1574 -292.97,-0.625 z m 0,9.5313 v 1.875 c 32.741,-0.1253 65.509,-0.2489 98.25,-0.3438 64.916,-0.1738 129.8,-0.2243 194.72,-0.1875 V 751.12 c -64.356,0.0377 -128.71,-0.0143 -193.06,-0.1875 -33.298,-0.0973 -66.609,-0.2127 -99.906,-0.3437 z m 0,8.1874 v 1.75 c 97.659,-0.3956 195.31,-0.5349 292.97,-0.4687 v -0.8125 c -97.659,0.0632 -195.31,-0.0622 -292.97,-0.4688 z m 0,9.5313 v 1.625 c 22.314,-0.078 44.624,-0.1541 66.938,-0.2187 75.343,-0.2018 150.69,-0.2383 226.03,-0.1563 v -0.875 c -74.789,0.0797 -149.58,0.045 -224.38,-0.1563 -22.869,-0.0668 -45.725,-0.1375 -68.594,-0.2187 z m 0,10.125 v 1.5313 c 97.659,-0.3484 195.31,-0.4415 292.97,-0.3438 v -0.8125 c -97.656,0.0952 -195.31,-0.0166 -292.97,-0.375 z m 0,9.5 v 1.4687 l 41.531,-0.125 c 83.822,-0.2244 167.62,-0.2482 251.44,-0.125 v -0.9374 c -83.264,0.1203 -166.52,0.099 -249.78,-0.125 -14.393,-0.0421 -28.794,-0.1091 -43.188,-0.1563 z m 0,8.1563 v 1.4687 c 97.65,-0.3367 195.32,-0.4189 292.97,-0.3125 v -0.875 c -97.657,0.1055 -195.31,0.0599 -292.97,-0.2812 z m 0,9.4687 v 1.4375 c 11.23,-0.0355 22.458,-0.0925 33.688,-0.125 86.426,-0.2314 172.85,-0.2308 259.28,-0.0938 v -1 c -85.874,0.1309 -171.75,0.1374 -257.63,-0.0937 -11.784,-0.0344 -23.56,-0.0874 -35.344,-0.125 z m 0,8.0313 v 1.6874 c 97.653,-0.3903 195.31,-0.507 292.97,-0.4374 v -0.8438 c -97.656,0.0699 -195.31,-0.009 -292.97,-0.4062 z m 0,9.4687 v 1.6563 c 21.011,-0.0726 42.02,-0.1579 63.031,-0.2188 76.645,-0.2052 153.29,-0.2442 229.94,-0.1562 v -0.9063 c -76.094,0.0826 -152.19,0.0485 -228.28,-0.1563 -21.567,-0.0629 -43.121,-0.1431 -64.688,-0.2187 z m 0,8.125 v 1.6875 c 97.653,-0.3882 195.31,-0.5087 292.97,-0.4375 V 831.62 c -97.656,0.0682 -195.31,-0.0385 -292.97,-0.4375 z m 0,9.5 v 1.625 c 21.011,-0.0719 42.02,-0.1579 63.031,-0.2187 76.645,-0.2053 153.29,-0.2412 229.94,-0.1563 v -0.875 c -76.094,0.0856 -152.19,0.0485 -228.28,-0.1563 -21.567,-0.0629 -43.121,-0.1431 -64.688,-0.2187 z m 0,8.2187 v 1.4376 c 97.66,-0.3305 195.31,-0.3594 292.97,-0.25 v -0.9063 c -97.657,0.1072 -195.31,0.059 -292.97,-0.2813 z m 0,9.4688 v 1.4062 l 31.75,-0.0937 c 87.078,-0.2331 174.14,-0.2344 261.22,-0.0937 v -1 c -86.522,0.1374 -173.04,0.1391 -259.56,-0.0938 -11.133,-0.0325 -22.273,-0.0895 -33.406,-0.125 z m 0,6.0312 v 1.75 c 97.654,-0.3955 195.31,-0.5349 292.97,-0.4687 V 864.87 c -97.659,0.0632 -195.31,-0.0622 -292.97,-0.4688 z m 0,9.5313 c 0.0444,0.6929 0.3272,1.2501 0.75,1.625 22.064,-0.0769 44.124,-0.1548 66.188,-0.2187 75.207,-0.2014 150.42,-0.2376 225.62,-0.1563 0.16038,-0.2431 0.28202,-0.5509 0.34375,-0.875 -74.771,0.0796 -149.54,0.045 -224.31,-0.1563 -22.869,-0.0668 -45.725,-0.1375 -68.594,-0.2187 z"
|
||||||
|
filter="url(#n)"
|
||||||
|
opacity="0.2202"
|
||||||
|
id="path112" />
|
||||||
|
</g>
|
||||||
|
<path
|
||||||
|
d="m 40.820156,94.409551 h 76.239684 a 3.3067625,3.3067625 0 0 1 3.30676,3.306763 v 62.341126 a 3.3067625,3.3067625 0 0 1 -3.30676,3.30676 H 40.820156 a 3.3067625,3.3067625 0 0 1 -3.306763,-3.30676 V 97.716314 a 3.3067625,3.3067625 0 0 1 3.306763,-3.306763"
|
||||||
|
fill="url(#t)"
|
||||||
|
id="path116"
|
||||||
|
style="fill:url(#t);stroke-width:0.264583" />
|
||||||
|
<path
|
||||||
|
d="m 40.820156,94.409551 h 76.239684 a 3.3067625,3.3067625 0 0 1 3.30676,3.306763 v 62.341126 a 3.3067625,3.3067625 0 0 1 -3.30676,3.30676 H 40.820156 a 3.3067625,3.3067625 0 0 1 -3.306763,-3.30676 V 97.716314 a 3.3067625,3.3067625 0 0 1 3.306763,-3.306763"
|
||||||
|
fill="url(#x)"
|
||||||
|
id="path118"
|
||||||
|
style="fill:url(#x);stroke-width:0.264583" />
|
||||||
|
<path
|
||||||
|
transform="matrix(0.26458333,0,0,0.26458333,42.487031,-81.558472)"
|
||||||
|
d="m -6.2998,662.08 c -8.5337,0 -15.5,6.9663 -15.5,15.5 V 913.2 c 0,8.5337 6.9663,15.5 15.5,15.5 h 288.16 c 8.5337,0 15.5,-6.9663 15.5,-15.5 V 677.58 c 0,-8.5337 -6.9663,-15.5 -15.5,-15.5 z m 0,6 h 288.16 c 5.3135,0 9.5,4.1865 9.5,9.5 V 913.2 c 0,5.3135 -4.1865,9.5 -9.5,9.5 h -288.16 c -5.3135,0 -9.5,-4.1865 -9.5,-9.5 V 677.58 c 0,-5.3135 4.1865,-9.5 9.5,-9.5 z"
|
||||||
|
fill="#ffffff"
|
||||||
|
filter="url(#c)"
|
||||||
|
mask="url(#b)"
|
||||||
|
id="path120" />
|
||||||
|
<g
|
||||||
|
transform="matrix(0.26458333,0,0,0.26458333,268.30097,-298.58136)"
|
||||||
|
id="g126">
|
||||||
|
<path
|
||||||
|
d="m -718.43,1283 c -46.21,0.1238 -97.408,16.465 -119.06,54.089 -13.801,24.035 -8.4155,51.758 -10.594,77.602 -0.3932,31.793 -0.6396,63.604 -0.031,95.398 l 21.781,-1.2943 -21.219,23.135 c 0.041,1.2322 0.081,2.4621 0.125,3.694 0.1398,25.837 38.758,3.234 39.437,-14.075 -0.522,-52.154 -1.3603,-104.4 1.9063,-156.5 6.1489,-24.928 33.689,-41.417 61.812,-44.787 31.318,-4.4778 67.758,-2.6342 92.781,16.016 17.831,12.31 21.591,32.024 19.031,50.449 -0.9481,98.57 -1.5396,197.19 -0.6875,295.74 7.8425,27.05 50.552,9.1799 39.656,-14.345 -0.048,-102.01 -0.024,-204.04 1.2188,-306.04 -4.9781,-34.62 -37.945,-63.117 -76.125,-72.479 -16.133,-4.4659 -33.097,-6.6347 -50.031,-6.6061 z"
|
||||||
|
fill="url(#i)"
|
||||||
|
id="path122"
|
||||||
|
style="fill:url(#linearGradient453)" />
|
||||||
|
<path
|
||||||
|
d="m -719.39,1290.2 c -35.758,0 -64.743,5.9938 -64.743,13.383 0,3.7664 7.5446,7.1567 19.665,9.5881 11.739,-2.4569 28.043,-3.9782 46.071,-3.9782 17.531,0 33.42,1.4562 45.078,3.7949 11.544,-2.4162 18.693,-5.7411 18.693,-9.4048 0,-7.3892 -29.006,-13.383 -64.764,-13.383 z"
|
||||||
|
fill="#ffffff"
|
||||||
|
filter="url(#l)"
|
||||||
|
opacity="0.7278"
|
||||||
|
id="path124" />
|
||||||
|
</g>
|
||||||
|
<path
|
||||||
|
transform="matrix(0.26458333,0,0,0.22829308,-380.69548,-36.699426)"
|
||||||
|
d="m 1734.4,339.23 c -46.21,0.1434 -97.408,19.082 -119.06,62.688 -13.801,27.856 -8.4155,59.986 -10.594,89.938 -0.3932,36.847 -0.6396,73.715 -0.031,110.56 l 21.781,-1.5 -21.219,26.812 c 0.041,1.428 0.081,2.8534 0.125,4.2812 0.1398,29.944 38.758,3.7481 39.438,-16.312 -0.522,-60.445 -1.3603,-121 1.9063,-181.38 6.1489,-28.89 33.689,-48.001 61.812,-51.906 31.318,-5.1896 67.758,-3.053 92.781,18.562 17.831,14.267 21.591,37.115 19.031,58.469 -0.9481,114.24 -1.5396,228.53 -0.6875,342.75 7.8425,31.35 50.552,10.639 39.656,-16.625 -0.048,-118.23 -0.024,-236.48 1.2188,-354.69 -4.9781,-40.123 -37.945,-73.15 -76.125,-84 -16.134,-5.1758 -33.097,-7.6894 -50.031,-7.6562 z"
|
||||||
|
fill="#cccccc"
|
||||||
|
filter="url(#p)"
|
||||||
|
id="path128" />
|
||||||
|
<path
|
||||||
|
transform="matrix(0.26458333,0,0,0.22817402,-250.41994,-32.98203)"
|
||||||
|
d="m 1242.1,334.47 c -43.163,0.13395 -89.956,17.995 -109.06,56.438 v 0.0312 c -11.662,23.566 -7.2063,53.469 -9.4062,85.062 -0.3508,32.868 -0.5102,65.68 -0.125,98.438 l 9.875,-0.6875 a 11.211,11.211 0 0 1 7.7812,2.4375 c -0.4624,-52.634 -0.8032,-105.47 2.0625,-158.44 a 11.211,11.211 0 0 1 0.2187,-1.75 c 7.3342,-34.459 38.973,-56.043 70.938,-60.594 v -0.0312 c 0.1012,-0.0168 0.2111,-0.0146 0.3124,-0.0312 33.012,-5.4196 72.604,-3.6311 101.31,20.938 v -0.0312 c 0.077,0.0618 0.1419,0.12544 0.2187,0.1875 l 0.094,0.0937 c 21.121,17.144 25.459,43.852 22.938,67.031 -3e-4,0.0312 2e-4,0.0625 0,0.0937 -0.9432,113.66 -1.5218,227.34 -0.6876,340.91 1.2462,4.1697 2.7143,5.1796 4.0938,5.75 1.505,0.62221 4.0586,0.66583 6.9062,-0.625 2.8476,-1.29083 5.5447,-3.8207 6.875,-6.5312 1.3303,-2.7105 1.7621,-5.3878 0.1563,-9.4062 a 11.211,11.211 0 0 1 -0.8125,-4.1562 c -0.048,-117.93 -0.015,-235.92 1.2188,-353.91 -4.5894,-34.613 -34.106,-64.377 -67.969,-74 a 11.211,11.211 0 0 1 -0.375,-0.0937 c -14.962,-4.8001 -30.752,-7.156 -46.562,-7.125 z m -100.84,259.56 -16.969,21.469 v 0.1875 a 11.211,11.211 0 0 1 0,0.28125 c 0.01,1.215 0.1339,1.1748 0.25,1.7812 0.7478,-0.19089 1.4986,-0.32129 2.6875,-0.96875 3.2667,-1.779 7.2221,-5.135 9.9687,-8.6875 2.7466,-3.5525 4.0428,-7.2429 4.0938,-8.75 -0.015,-1.7663 -0.015,-3.5455 -0.031,-5.3125 z"
|
||||||
|
fill="#ffffff"
|
||||||
|
filter="url(#o)"
|
||||||
|
mask="url(#h)"
|
||||||
|
opacity="0.7"
|
||||||
|
id="path130" />
|
||||||
|
<path
|
||||||
|
transform="matrix(0.26458333,0,0,0.26458333,111.46126,3.3690732)"
|
||||||
|
d="m -125.64,141.27 c -46.21,0.12373 -97.408,16.465 -119.06,54.089 -13.801,24.035 -8.4155,51.758 -10.594,77.602 -0.3932,31.793 -0.6396,63.604 -0.031,95.398 l 21.781,-1.2943 -21.219,23.135 c 0.041,1.2321 0.081,2.462 0.125,3.694 0.1398,25.837 38.758,3.234 39.437,-14.075 -0.522,-52.154 -1.3603,-104.4 1.9063,-156.5 6.1489,-24.928 33.689,-41.417 61.812,-44.787 31.318,-4.4778 67.758,-2.6342 92.781,16.016 17.831,12.31 21.591,32.024 19.031,50.449 -0.9481,98.57 -1.5396,197.19 -0.6875,295.74 7.8425,27.05 50.552,9.1799 39.656,-14.345 -0.048,-102.01 -0.024,-204.04 1.2188,-306.04 -4.9781,-34.62 -37.945,-63.117 -76.125,-72.479 -16.133,-4.4659 -33.097,-6.6347 -50.031,-6.6061 z"
|
||||||
|
fill="none"
|
||||||
|
filter="url(#m)"
|
||||||
|
mask="url(#g)"
|
||||||
|
stroke="#000000"
|
||||||
|
stroke-width="3"
|
||||||
|
id="path132" />
|
||||||
|
<path
|
||||||
|
d="m 40.819627,96.269254 c -0.817113,0 -1.413881,0.596742 -1.413881,1.413881 v 62.341125 c 0,0.81711 0.596741,1.41388 1.413881,1.41388 h 76.242333 c 0.81711,0 1.41388,-0.59674 1.41388,-1.41388 V 97.683135 c 0,-0.817113 -0.59674,-1.413881 -1.41388,-1.413881 z"
|
||||||
|
fill="url(#a)"
|
||||||
|
id="path134"
|
||||||
|
style="fill:url(#linearGradient455);stroke-width:0.264583" />
|
||||||
|
<path
|
||||||
|
d="m 113.59909,95.780093 c 1.06101,0.0093 2.12225,0.01588 3.1832,0.02482 -0.0816,-0.0131 -0.16098,-0.02482 -0.24804,-0.02482 h -2.93529 z m -74.339976,0.421693 c -0.02551,0.0264 -0.05116,0.05416 -0.07441,0.08268 7.481888,0.180472 14.965892,0.371105 22.448308,0.529167 14.260513,0.301254 17.355608,0.327263 31.675917,0.553958 17.771791,0.212963 14.241191,0.190791 24.639321,0.23151 v -0.0083 C 107.5742,97.550235 111.08654,97.563914 93.325593,97.351083 78.653389,97.118779 76.274785,97.112878 61.676135,96.780562 54.203773,96.610461 46.732469,96.403213 39.2609,96.201786 Z m 69.725646,2.265495 c -23.368794,0.01275 -46.738646,0.205316 -70.106646,0.471302 v 0.0744 C 65.232995,98.645795 91.591051,98.480192 117.9462,98.616109 v -0.140547 c -2.98821,-0.0042 -5.97456,-0.0099 -8.96276,-0.0083 z m 8.96276,1.620569 c -11.68215,0.0338 -23.367206,0.0883 -35.049354,0.19844 -22.163352,0.26083 -15.260373,0.13867 -37.380333,0.56224 -2.212605,0.0424 -4.426744,0.0875 -6.639454,0.13229 v 0.0165 c 8.422746,-0.17489 16.844698,-0.34459 25.267708,-0.47128 6.243108,-0.0939 12.492566,-0.14975 18.735675,-0.22325 11.687968,-0.0939 23.377528,-0.1646 35.065228,-0.2067 v -0.008 z m -79.068083,3.23295 v 0.0331 c 16.594402,0.0845 33.189333,0.14893 49.784,0.2894 4.524639,0.0315 9.043458,0.0672 13.568093,0.091 4.22884,0.0222 10.1653,0.0393 15.71784,0.0413 v -0.14054 c -9.73111,0.0371 -19.4646,-0.008 -29.194123,-0.0661 -16.624564,-0.1157 -33.250187,-0.16804 -49.873958,-0.24807 z m 0,0.43823 v 0.0165 c 26.348531,0.83103 52.710291,1.1253 79.068083,1.33946 v -0.0662 c -26.361761,-0.13425 -52.718229,-0.46022 -79.068083,-1.28984 z m 0,1.77765 v 0.0744 c 6.776244,0.16415 13.554869,0.33639 20.331642,0.47956 14.260512,0.30123 17.355608,0.32726 31.675916,0.55398 18.952895,0.22704 13.686365,0.18555 27.061585,0.23977 v -0.008 c -13.35326,-0.0541 -8.10075,-0.0208 -27.04571,-0.24807 -14.672204,-0.23228 -17.050808,-0.23813 -31.649458,-0.5705 -6.79159,-0.15459 -13.582121,-0.338 -20.372916,-0.52091 z m 67.683063,2.20763 c -22.561815,0.0123 -45.122042,0.19516 -67.683063,0.44649 v 0.0661 c 18.969831,-0.25521 37.946541,-0.40838 56.917166,-0.41341 7.050357,-0.003 14.099907,0.0185 21.150267,0.0579 0.33371,0.003 0.66675,0.0127 1.00044,0.0165 v -0.15708 l -0.80201,-0.008 c -3.52848,-0.006 -7.05485,-0.0102 -10.58333,-0.008 z m 11.38528,0.41341 c -9.66602,0.0358 -19.331248,0.0908 -28.995683,0.18191 -22.163352,0.26085 -15.260373,0.13866 -37.380333,0.56224 -4.230158,0.081 -8.461375,0.16107 -12.691798,0.24804 v 0.0248 c 10.440194,-0.21571 20.879594,-0.44651 31.321375,-0.60356 6.243108,-0.0939 12.4841,-0.14148 18.727473,-0.21498 9.671579,-0.0777 19.349776,-0.13967 29.022146,-0.1819 v -0.0165 z m -79.068078,3.43139 v 0.0331 l 5.1181,0.18193 c 15.994327,0.51223 31.996062,0.81147 47.998062,1.02526 -15.994327,-0.20574 -31.993417,-0.53137 -47.979541,-1.04183 -1.712437,-0.0646 -3.422121,-0.13229 -5.134505,-0.19843 z m 53.115103,1.24026 c 1.581865,0.0211 3.164152,0.0468 4.746096,0.0661 -3.467894,-0.0143 -6.941873,-0.029 -10.409767,-0.0496 -15.817585,-0.11007 -31.633582,-0.15815 -47.450374,-0.23151 v 0.0248 c 15.787687,0.0786 31.572729,0.14751 47.360416,0.28112 4.52464,0.0315 9.05166,0.0672 13.5763,0.0909 3.067054,0.0161 7.058554,0.0331 11.137374,0.0414 2.33153,0.0223 4.66328,0.0377 6.99505,0.0579 v -0.0413 l -1.81901,-0.008 h 1.81901 v -0.15711 c -6.36693,0.0336 -12.73254,0.0224 -19.099741,0 -2.284968,-0.0249 -4.569354,-0.045 -6.854295,-0.0744 z m -53.115103,0.59531 v 0.0909 c 8.79422,0.20828 17.589235,0.43434 26.383985,0.6201 14.260512,0.30125 17.355608,0.33552 31.675916,0.56224 15.995917,0.19166 13.996197,0.18791 21.009507,0.215 v -0.0166 c -7.00088,-0.027 -5.00513,-0.0235 -20.993103,-0.21495 -14.672204,-0.23233 -17.050808,-0.24643 -31.649458,-0.5788 -8.809302,-0.2005 -17.617016,-0.44151 -26.42526,-0.67797 z m 73.736728,2.37297 c -24.579262,0.0137 -49.159583,0.22442 -73.736728,0.51263 v 0.0744 c 26.354352,-0.38587 52.712937,-0.56346 79.068078,-0.45474 v -0.12401 c -1.7781,-0.001 -3.55494,-0.009 -5.33294,-0.008 z m 5.33294,1.62885 c -10.47247,0.0351 -20.947061,0.0914 -31.419269,0.19016 -22.163352,0.26088 -15.260373,0.13864 -37.380333,0.56224 -3.42265,0.0655 -6.846358,0.13642 -10.269008,0.20672 v 0.008 c 9.634008,-0.20024 19.263254,-0.40079 28.897791,-0.5457 6.243109,-0.0939 12.492567,-0.14147 18.735675,-0.21498 10.478029,-0.0841 20.957644,-0.14763 31.435144,-0.19018 z m -79.068081,3.20807 v 0.0331 c 17.804077,0.0946 35.610271,0.14695 53.414083,0.29765 4.524639,0.0315 9.051658,0.0755 13.576298,0.0992 3.29883,0.0173 7.68377,0.0338 12.07982,0.0413 v -0.13229 c -8.5217,0.0155 -17.0442,-0.0238 -25.565366,-0.0744 -17.834504,-0.12412 -35.668479,-0.17307 -53.504041,-0.26459 z m 0,0.32245 v 0.0248 c 0.900959,0.0318 1.802765,0.0678 2.703777,0.0992 11.693525,0.37452 23.384933,0.63519 35.081104,0.83511 -11.692202,-0.20029 -23.376731,-0.47845 -35.065229,-0.85162 -0.90678,-0.0342 -1.813427,-0.0728 -2.720181,-0.1075 z m 37.851291,0.95912 c 13.737167,0.23447 27.47963,0.38047 41.21679,0.4960Line truncated
|
||||||
|
fill="#1a1a1a"
|
||||||
|
opacity="0.2"
|
||||||
|
stroke="#000000"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="bevel"
|
||||||
|
stroke-width="0.145381"
|
||||||
|
id="path136" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 34 KiB |
@@ -0,0 +1,467 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
width="82.855278mm"
|
||||||
|
height="141.74763mm"
|
||||||
|
viewBox="0 0 82.855278 141.74763"
|
||||||
|
version="1.1"
|
||||||
|
id="svg1352"
|
||||||
|
inkscape:version="1.2 (dc2aedaf03, 2022-05-15)"
|
||||||
|
sodipodi:docname="padlock-open.svg"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg">
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="namedview1354"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#000000"
|
||||||
|
borderopacity="0.25"
|
||||||
|
inkscape:showpageshadow="2"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pagecheckerboard="0"
|
||||||
|
inkscape:deskcolor="#d1d1d1"
|
||||||
|
inkscape:document-units="mm"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="1.2938725"
|
||||||
|
inkscape:cx="5.4101158"
|
||||||
|
inkscape:cy="224.90624"
|
||||||
|
inkscape:window-width="2560"
|
||||||
|
inkscape:window-height="1377"
|
||||||
|
inkscape:window-x="-8"
|
||||||
|
inkscape:window-y="-8"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="layer1" />
|
||||||
|
<defs
|
||||||
|
id="defs1349">
|
||||||
|
<filter
|
||||||
|
id="ab"
|
||||||
|
x="-0.063887693"
|
||||||
|
y="-0.038440254"
|
||||||
|
width="1.1277754"
|
||||||
|
height="1.0768805">
|
||||||
|
<feGaussianBlur
|
||||||
|
stdDeviation="8.4959"
|
||||||
|
id="feGaussianBlur14" />
|
||||||
|
</filter>
|
||||||
|
<radialGradient
|
||||||
|
id="f"
|
||||||
|
cx="207.08"
|
||||||
|
cy="608.71997"
|
||||||
|
r="156.57001"
|
||||||
|
gradientTransform="matrix(1,0,0,0.83226,1.428,126.14)"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
xlink:href="#e" />
|
||||||
|
<linearGradient
|
||||||
|
id="e">
|
||||||
|
<stop
|
||||||
|
stop-color="#d3bc5f"
|
||||||
|
offset="0"
|
||||||
|
id="stop49" />
|
||||||
|
<stop
|
||||||
|
stop-color="#c8ab37"
|
||||||
|
offset="1"
|
||||||
|
id="stop51" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="j"
|
||||||
|
x1="201.44"
|
||||||
|
x2="201.78"
|
||||||
|
y1="1021.9"
|
||||||
|
y2="727.78003"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
xlink:href="#d" />
|
||||||
|
<linearGradient
|
||||||
|
id="d">
|
||||||
|
<stop
|
||||||
|
stop-color="#806600"
|
||||||
|
offset="0"
|
||||||
|
id="stop44" />
|
||||||
|
<stop
|
||||||
|
stop-color="#806600"
|
||||||
|
stop-opacity="0"
|
||||||
|
offset="1"
|
||||||
|
id="stop46" />
|
||||||
|
</linearGradient>
|
||||||
|
<mask
|
||||||
|
id="b"
|
||||||
|
maskUnits="userSpaceOnUse">
|
||||||
|
<path
|
||||||
|
d="m -6.2978,665.08 h 288.15 a 12.498,12.498 0 0 1 12.498,12.498 v 235.62 a 12.498,12.498 0 0 1 -12.498,12.498 h -288.15 a 12.498,12.498 0 0 1 -12.498,-12.498 v -235.62 a 12.498,12.498 0 0 1 12.498,-12.498"
|
||||||
|
fill="#ffffff"
|
||||||
|
id="path81" />
|
||||||
|
</mask>
|
||||||
|
<filter
|
||||||
|
id="c"
|
||||||
|
x="-0.021572628"
|
||||||
|
y="-0.025823718"
|
||||||
|
width="1.0431453"
|
||||||
|
height="1.0516474">
|
||||||
|
<feGaussianBlur
|
||||||
|
stdDeviation="2.8688"
|
||||||
|
id="feGaussianBlur2" />
|
||||||
|
</filter>
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#a"
|
||||||
|
id="linearGradient457"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
x1="59.094002"
|
||||||
|
x2="357.94" />
|
||||||
|
<linearGradient
|
||||||
|
id="a"
|
||||||
|
x1="59.094002"
|
||||||
|
x2="357.94"
|
||||||
|
gradientUnits="userSpaceOnUse">
|
||||||
|
<stop
|
||||||
|
stop-color="#d4aa00"
|
||||||
|
offset="0"
|
||||||
|
id="stop54" />
|
||||||
|
<stop
|
||||||
|
stop-color="#fea"
|
||||||
|
offset=".5763"
|
||||||
|
id="stop56" />
|
||||||
|
<stop
|
||||||
|
stop-color="#d4aa00"
|
||||||
|
offset="1"
|
||||||
|
id="stop58" />
|
||||||
|
</linearGradient>
|
||||||
|
<filter
|
||||||
|
id="n"
|
||||||
|
x="-0.0021757265"
|
||||||
|
y="-0.0026762109"
|
||||||
|
width="1.0043515"
|
||||||
|
height="1.0053524">
|
||||||
|
<feGaussianBlur
|
||||||
|
stdDeviation=".2656"
|
||||||
|
id="feGaussianBlur5" />
|
||||||
|
</filter>
|
||||||
|
<linearGradient
|
||||||
|
id="i"
|
||||||
|
x1="-692.91998"
|
||||||
|
x2="-710.91998"
|
||||||
|
y1="1521.9"
|
||||||
|
y2="1295.6"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
xlink:href="#k" />
|
||||||
|
<linearGradient
|
||||||
|
id="k">
|
||||||
|
<stop
|
||||||
|
stop-color="#ccc"
|
||||||
|
offset="0"
|
||||||
|
id="stop37" />
|
||||||
|
<stop
|
||||||
|
stop-color="#fff"
|
||||||
|
offset=".6899"
|
||||||
|
id="stop39" />
|
||||||
|
<stop
|
||||||
|
stop-color="#e6e6e6"
|
||||||
|
offset="1"
|
||||||
|
id="stop41" />
|
||||||
|
</linearGradient>
|
||||||
|
<filter
|
||||||
|
id="l"
|
||||||
|
x="-0.063578956"
|
||||||
|
y="-0.35844691"
|
||||||
|
width="1.1271579"
|
||||||
|
height="1.7168938">
|
||||||
|
<feGaussianBlur
|
||||||
|
stdDeviation="3.4308"
|
||||||
|
id="feGaussianBlur34" />
|
||||||
|
</filter>
|
||||||
|
<filter
|
||||||
|
id="p"
|
||||||
|
x="-0.037389143"
|
||||||
|
y="-0.020053786"
|
||||||
|
width="1.0747783"
|
||||||
|
height="1.0401076">
|
||||||
|
<feGaussianBlur
|
||||||
|
result="result8"
|
||||||
|
stdDeviation="4"
|
||||||
|
id="feGaussianBlur20" />
|
||||||
|
<feComposite
|
||||||
|
in="result8"
|
||||||
|
in2="result8"
|
||||||
|
operator="xor"
|
||||||
|
result="result6"
|
||||||
|
id="feComposite22" />
|
||||||
|
<feDisplacementMap
|
||||||
|
in="result6"
|
||||||
|
in2="result6"
|
||||||
|
result="result4"
|
||||||
|
scale="80"
|
||||||
|
id="feDisplacementMap24"
|
||||||
|
xChannelSelector="A"
|
||||||
|
yChannelSelector="A" />
|
||||||
|
<feComposite
|
||||||
|
in="result8"
|
||||||
|
in2="result4"
|
||||||
|
k1="3"
|
||||||
|
operator="arithmetic"
|
||||||
|
result="result2"
|
||||||
|
id="feComposite26"
|
||||||
|
k2="0"
|
||||||
|
k3="0"
|
||||||
|
k4="0" />
|
||||||
|
<feComposite
|
||||||
|
in="result2"
|
||||||
|
in2="result2"
|
||||||
|
operator="in"
|
||||||
|
result="fbSourceGraphic"
|
||||||
|
id="feComposite28" />
|
||||||
|
</filter>
|
||||||
|
<mask
|
||||||
|
id="h"
|
||||||
|
maskUnits="userSpaceOnUse">
|
||||||
|
<path
|
||||||
|
d="m 1242.1,323.25 c -46.21,0.1434 -97.408,19.082 -119.06,62.688 -13.801,27.856 -8.4155,59.986 -10.594,89.938 -0.3932,36.847 -0.6396,73.715 -0.031,110.56 l 21.781,-1.5 -21.219,26.812 c 0.041,1.428 0.081,2.8534 0.125,4.2812 0.1398,29.944 38.758,3.7481 39.438,-16.312 -0.522,-60.445 -1.3603,-121 1.9063,-181.38 6.1489,-28.89 33.689,-48.001 61.812,-51.906 31.318,-5.1896 67.758,-3.053 92.781,18.562 17.831,14.267 21.591,37.115 19.031,58.469 -0.9481,114.24 -1.5396,228.53 -0.6875,342.75 7.8425,31.35 50.552,10.639 39.656,-16.625 -0.048,-118.23 -0.024,-236.48 1.2188,-354.69 -4.9781,-40.123 -37.945,-73.15 -76.125,-84 -16.133,-5.1758 -33.097,-7.6894 -50.031,-7.6562 z"
|
||||||
|
fill="#cccccc"
|
||||||
|
id="path78" />
|
||||||
|
</mask>
|
||||||
|
<filter
|
||||||
|
id="o"
|
||||||
|
x="-0.14145334"
|
||||||
|
y="-0.072653391"
|
||||||
|
width="1.2829067"
|
||||||
|
height="1.1453068">
|
||||||
|
<feGaussianBlur
|
||||||
|
stdDeviation="13.8123"
|
||||||
|
id="feGaussianBlur31" />
|
||||||
|
</filter>
|
||||||
|
<mask
|
||||||
|
id="g"
|
||||||
|
maskUnits="userSpaceOnUse">
|
||||||
|
<path
|
||||||
|
d="m -125.64,141.27 c -46.21,0.12373 -97.408,16.465 -119.06,54.089 -13.801,24.035 -8.4155,51.758 -10.594,77.602 -0.3932,31.793 -0.6396,63.604 -0.031,95.398 l 21.781,-1.2943 -21.219,23.135 c 0.041,1.2321 0.081,2.462 0.125,3.694 0.1398,25.837 38.758,3.234 39.437,-14.075 -0.522,-52.154 -1.3603,-104.4 1.9063,-156.5 6.1489,-24.928 33.689,-41.417 61.812,-44.787 31.318,-4.4778 67.758,-2.6342 92.781,16.016 17.831,12.31 21.591,32.024 19.031,50.449 -0.9481,98.57 -1.5396,197.19 -0.6875,295.74 7.8425,27.05 50.552,9.1799 39.656,-14.345 -0.048,-102.01 -0.024,-204.04 1.2188,-306.04 -4.9781,-34.62 -37.945,-63.117 -76.125,-72.479 -16.133,-4.4659 -33.097,-6.6347 -50.031,-6.6061 z"
|
||||||
|
fill="url(#y)"
|
||||||
|
id="path84" />
|
||||||
|
</mask>
|
||||||
|
<linearGradient
|
||||||
|
id="y"
|
||||||
|
x1="-100.13"
|
||||||
|
x2="-118.13"
|
||||||
|
y1="380.12"
|
||||||
|
y2="153.84"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
xlink:href="#k" />
|
||||||
|
<filter
|
||||||
|
id="m"
|
||||||
|
x="-0.03714728"
|
||||||
|
y="-0.023091114"
|
||||||
|
width="1.0742253"
|
||||||
|
height="1.0461927">
|
||||||
|
<feGaussianBlur
|
||||||
|
stdDeviation="3.3491"
|
||||||
|
id="feGaussianBlur8" />
|
||||||
|
</filter>
|
||||||
|
<radialGradient
|
||||||
|
id="s"
|
||||||
|
cx="207.08"
|
||||||
|
cy="608.71997"
|
||||||
|
r="156.57001"
|
||||||
|
gradientTransform="matrix(0.26458333,0,0,0.22020212,35.514623,57.4525)"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
xlink:href="#e" />
|
||||||
|
<linearGradient
|
||||||
|
id="w"
|
||||||
|
x1="-586.71002"
|
||||||
|
x2="-586.35999"
|
||||||
|
y1="1121.6"
|
||||||
|
y2="827.53003"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
xlink:href="#d"
|
||||||
|
gradientTransform="matrix(0.26458333,0,0,0.26458333,243.66762,-2.316874)" />
|
||||||
|
<mask
|
||||||
|
id="mask1302"
|
||||||
|
maskUnits="userSpaceOnUse">
|
||||||
|
<path
|
||||||
|
d="m -6.2978,665.08 h 288.15 a 12.498,12.498 0 0 1 12.498,12.498 v 235.62 a 12.498,12.498 0 0 1 -12.498,12.498 h -288.15 a 12.498,12.498 0 0 1 -12.498,-12.498 v -235.62 a 12.498,12.498 0 0 1 12.498,-12.498"
|
||||||
|
fill="#ffffff"
|
||||||
|
id="path1300" />
|
||||||
|
</mask>
|
||||||
|
<filter
|
||||||
|
id="filter1306"
|
||||||
|
x="-0.021572627"
|
||||||
|
y="-0.025823718"
|
||||||
|
width="1.0431453"
|
||||||
|
height="1.0516474">
|
||||||
|
<feGaussianBlur
|
||||||
|
stdDeviation="2.8688"
|
||||||
|
id="feGaussianBlur1304" />
|
||||||
|
</filter>
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#a"
|
||||||
|
id="linearGradient459"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
x1="59.094002"
|
||||||
|
x2="357.94"
|
||||||
|
gradientTransform="matrix(0.26458333,0,0,0.26458333,35.136268,24.045415)" />
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient1315"
|
||||||
|
x1="59.094002"
|
||||||
|
x2="357.94"
|
||||||
|
gradientUnits="userSpaceOnUse">
|
||||||
|
<stop
|
||||||
|
stop-color="#d4aa00"
|
||||||
|
offset="0"
|
||||||
|
id="stop1309" />
|
||||||
|
<stop
|
||||||
|
stop-color="#fea"
|
||||||
|
offset=".5763"
|
||||||
|
id="stop1311" />
|
||||||
|
<stop
|
||||||
|
stop-color="#d4aa00"
|
||||||
|
offset="1"
|
||||||
|
id="stop1313" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#a"
|
||||||
|
id="linearGradient461"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
x1="59.094002"
|
||||||
|
x2="357.94"
|
||||||
|
gradientTransform="matrix(0.26458333,0,0,0.26458333,35.136268,24.045415)" />
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient1324"
|
||||||
|
x1="59.094002"
|
||||||
|
x2="357.94"
|
||||||
|
gradientUnits="userSpaceOnUse">
|
||||||
|
<stop
|
||||||
|
stop-color="#d4aa00"
|
||||||
|
offset="0"
|
||||||
|
id="stop1318" />
|
||||||
|
<stop
|
||||||
|
stop-color="#fea"
|
||||||
|
offset=".5763"
|
||||||
|
id="stop1320" />
|
||||||
|
<stop
|
||||||
|
stop-color="#d4aa00"
|
||||||
|
offset="1"
|
||||||
|
id="stop1322" />
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(-48.877192,-116.29581)">
|
||||||
|
<g
|
||||||
|
transform="matrix(0.26458333,0,0,0.26458333,35.136268,24.077694)"
|
||||||
|
id="g152">
|
||||||
|
<path
|
||||||
|
d="m 64.433,623.66 h 288.15 a 12.498,12.498 0 0 1 12.498,12.498 v 235.62 a 12.498,12.498 0 0 1 -12.498,12.498 H 64.433 A 12.498,12.498 0 0 1 51.935,871.778 V 636.158 A 12.498,12.498 0 0 1 64.433,623.66"
|
||||||
|
fill="url(#f)"
|
||||||
|
id="path142"
|
||||||
|
style="fill:url(#f)" />
|
||||||
|
<path
|
||||||
|
d="m 64.433,623.66 h 288.15 a 12.498,12.498 0 0 1 12.498,12.498 v 235.62 a 12.498,12.498 0 0 1 -12.498,12.498 H 64.433 A 12.498,12.498 0 0 1 51.935,871.778 V 636.158 A 12.498,12.498 0 0 1 64.433,623.66"
|
||||||
|
fill="url(#j)"
|
||||||
|
id="path144"
|
||||||
|
style="fill:url(#j)" />
|
||||||
|
<path
|
||||||
|
transform="translate(70.731,-41.416)"
|
||||||
|
d="m -6.2998,662.08 c -8.5337,0 -15.5,6.9663 -15.5,15.5 V 913.2 c 0,8.5337 6.9663,15.5 15.5,15.5 h 288.16 c 8.5337,0 15.5,-6.9663 15.5,-15.5 V 677.58 c 0,-8.5337 -6.9663,-15.5 -15.5,-15.5 z m 0,6 h 288.16 c 5.3135,0 9.5,4.1865 9.5,9.5 V 913.2 c 0,5.3135 -4.1865,9.5 -9.5,9.5 h -288.16 c -5.3135,0 -9.5,-4.1865 -9.5,-9.5 V 677.58 c 0,-5.3135 4.1865,-9.5 9.5,-9.5 z"
|
||||||
|
fill="#ffffff"
|
||||||
|
filter="url(#c)"
|
||||||
|
mask="url(#b)"
|
||||||
|
id="path146" />
|
||||||
|
<path
|
||||||
|
d="m 64.438,630.81 c -3.0883,0 -5.3438,2.2554 -5.3438,5.3438 v 235.62 c 0,3.0883 2.2554,5.3438 5.3438,5.3438 h 288.16 c 3.0883,0 5.3438,-2.2554 5.3438,-5.3438 v -235.62 c 0,-3.0883 -2.2554,-5.3438 -5.3438,-5.3438 z"
|
||||||
|
fill="url(#a)"
|
||||||
|
id="path148"
|
||||||
|
style="fill:url(#linearGradient457)" />
|
||||||
|
<path
|
||||||
|
d="m 65.691,637.37 c -0.0543,0.2253 -0.0937,0.4551 -0.0937,0.7188 v 1.3124 c 97.654,-0.4644 195.31,-0.674 292.97,-0.6562 v -0.6562 c 0,-0.033 8.7e-4,-0.0614 0,-0.0938 -97.624,0.0192 -195.25,-0.1507 -292.88,-0.625 z m -0.0937,9.5 v 1.9375 c 34.054,-0.1333 68.102,-0.2451 102.16,-0.3437 63.603,-0.1703 127.21,-0.2222 190.81,-0.1876 v -0.8437 c -63.054,0.0306 -126.1,-0.0178 -189.16,-0.1875 -34.601,-0.1011 -69.213,-0.237 -103.81,-0.375 z m 0,8.0938 v 2.0312 c 97.654,-0.4634 195.31,-0.6454 292.97,-0.625 v -0.75 c -97.655,0.0166 -195.31,-0.1808 -292.97,-0.6562 z m 0,9.5312 v 1.9062 c 34.054,-0.1319 68.102,-0.245 102.16,-0.3437 63.603,-0.1703 127.21,-0.2196 190.81,-0.1875 v -0.8438 c -63.054,0.0332 -126.1,-0.0178 -189.16,-0.1874 -34.601,-0.1011 -69.213,-0.2058 -103.81,-0.3438 z m 0,8.2188 v 1.75 c 97.654,-0.4031 195.31,-0.5301 292.97,-0.4688 v -0.8125 c -97.653,0.0582 -195.32,-0.0547 -292.97,-0.4687 z m 0,9.5 v 1.6874 c 23.617,-0.0835 47.258,-0.1815 70.875,-0.25 74.041,-0.1982 148.05,-0.2323 222.09,-0.1562 v -0.875 c -73.479,0.074 -146.96,0.0415 -220.44,-0.1562 -24.173,-0.0707 -48.358,-0.1632 -72.531,-0.25 z m 0,6.125 v 1.8124 c 97.655,-0.4141 195.31,-0.5537 292.97,-0.5 v -0.8124 c -97.659,0.0505 -195.31,-0.0746 -292.97,-0.5 z m 0,9.5312 v 1.6875 c 25.574,-0.0921 51.145,-0.1759 76.719,-0.25 72.082,-0.1929 144.17,-0.2239 216.25,-0.1563 v -0.875 c -71.532,0.0657 -143.06,0.0363 -214.59,-0.1562 -26.13,-0.0763 -52.245,-0.1543 -78.375,-0.25 z m 0,8.125 v 1.7188 c 97.656,-0.4013 195.31,-0.5308 292.97,-0.4688 v -0.8125 c -97.662,0.0626 -195.31,-0.029 -292.97,-0.4375 z m 0,9.4688 v 1.6562 c 22.961,-0.0807 45.945,-0.1522 68.906,-0.2188 74.686,-0.1999 149.37,-0.2352 224.06,-0.1562 v -0.875 c -74.138,0.0739 -148.27,0.0433 -222.41,-0.1562 -23.517,-0.0687 -47.047,-0.1668 -70.563,-0.25 z m 0,8 v 1.9687 c 97.657,-0.4569 195.31,-0.6169 292.97,-0.5937 v -0.7813 c -97.651,0.0245 -195.32,-0.127 -292.97,-0.5937 z m 0,9.5 v 1.9062 c 32.741,-0.1265 65.509,-0.2489 98.25,-0.3438 64.916,-0.1738 129.8,-0.2268 194.72,-0.1874 v -0.8438 c -64.356,0.0352 -128.71,-0.0143 -193.06,-0.1875 -33.298,-0.0973 -66.609,-0.2127 -99.906,-0.3437 z m 0,8.0937 v 2 c 97.657,-0.4557 195.31,-0.6507 292.97,-0.625 v -0.75 c -97.651,0.0219 -195.32,-0.1574 -292.97,-0.625 z m 0,9.5313 v 1.875 c 32.741,-0.1253 65.509,-0.2489 98.25,-0.3438 64.916,-0.1738 129.8,-0.2243 194.72,-0.1875 V 751.12 c -64.356,0.0377 -128.71,-0.0143 -193.06,-0.1875 -33.298,-0.0973 -66.609,-0.2127 -99.906,-0.3437 z m 0,8.1874 v 1.75 c 97.659,-0.3956 195.31,-0.5349 292.97,-0.4687 v -0.8125 c -97.659,0.0632 -195.31,-0.0622 -292.97,-0.4688 z m 0,9.5313 v 1.625 c 22.314,-0.078 44.624,-0.1541 66.938,-0.2187 75.343,-0.2018 150.69,-0.2383 226.03,-0.1563 v -0.875 c -74.789,0.0797 -149.58,0.045 -224.38,-0.1563 -22.869,-0.0668 -45.725,-0.1375 -68.594,-0.2187 z m 0,10.125 v 1.5313 c 97.659,-0.3484 195.31,-0.4415 292.97,-0.3438 v -0.8125 c -97.656,0.0952 -195.31,-0.0166 -292.97,-0.375 z m 0,9.5 v 1.4687 l 41.531,-0.125 c 83.822,-0.2244 167.62,-0.2482 251.44,-0.125 v -0.9374 c -83.264,0.1203 -166.52,0.099 -249.78,-0.125 -14.393,-0.0421 -28.794,-0.1091 -43.188,-0.1563 z m 0,8.1563 v 1.4687 c 97.65,-0.3367 195.32,-0.4189 292.97,-0.3125 v -0.875 c -97.657,0.1055 -195.31,0.0599 -292.97,-0.2812 z m 0,9.4687 v 1.4375 c 11.23,-0.0355 22.458,-0.0925 33.688,-0.125 86.426,-0.2314 172.85,-0.2308 259.28,-0.0938 v -1 c -85.874,0.1309 -171.75,0.1374 -257.63,-0.0937 -11.784,-0.0344 -23.56,-0.0874 -35.344,-0.125 z m 0,8.0313 v 1.6874 c 97.653,-0.3903 195.31,-0.507 292.97,-0.4374 v -0.8438 c -97.656,0.0699 -195.31,-0.009 -292.97,-0.4062 z m 0,9.4687 v 1.6563 c 21.011,-0.0726 42.02,-0.1579 63.031,-0.2188 76.645,-0.2052 153.29,-0.2442 229.94,-0.1562 v -0.9063 c -76.094,0.0826 -152.19,0.0485 -228.28,-0.1563 -21.567,-0.0629 -43.121,-0.1431 -64.688,-0.2187 z m 0,8.125 v 1.6875 c 97.653,-0.3882 195.31,-0.5087 292.97,-0.4375 V 831.62 c -97.656,0.0682 -195.31,-0.0385 -292.97,-0.4375 z m 0,9.5 v 1.625 c 21.011,-0.0719 42.02,-0.1579 63.031,-0.2187 76.645,-0.2053 153.29,-0.2412 229.94,-0.1563 v -0.875 c -76.094,0.0856 -152.19,0.0485 -228.28,-0.1563 -21.567,-0.0629 -43.121,-0.1431 -64.688,-0.2187 z m 0,8.2187 v 1.4376 c 97.66,-0.3305 195.31,-0.3594 292.97,-0.25 v -0.9063 c -97.657,0.1072 -195.31,0.059 -292.97,-0.2813 z m 0,9.4688 v 1.4062 l 31.75,-0.0937 c 87.078,-0.2331 174.14,-0.2344 261.22,-0.0937 v -1 c -86.522,0.1374 -173.04,0.1391 -259.56,-0.0938 -11.133,-0.0325 -22.273,-0.0895 -33.406,-0.125 z m 0,6.0312 v 1.75 c 97.654,-0.3955 195.31,-0.5349 292.97,-0.4687 V 864.87 c -97.659,0.0632 -195.31,-0.0622 -292.97,-0.4688 z m 0,9.5313 c 0.0444,0.6929 0.3272,1.2501 0.75,1.625 22.064,-0.0769 44.124,-0.1548 66.188,-0.2187 75.207,-0.2014 150.42,-0.2376 225.62,-0.1563 0.16038,-0.2431 0.28202,-0.5509 0.34375,-0.875 -74.771,0.0796 -149.54,0.045 -224.31,-0.1563 -22.869,-0.0668 -45.725,-0.1375 -68.594,-0.2187 z"
|
||||||
|
filter="url(#n)"
|
||||||
|
opacity="0.2202"
|
||||||
|
id="path150" />
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
transform="matrix(0.26458333,0,0,0.26458333,279.66947,-220.83625)"
|
||||||
|
id="g158">
|
||||||
|
<path
|
||||||
|
d="m -718.43,1283 c -46.21,0.1238 -97.408,16.465 -119.06,54.089 -13.801,24.035 -8.4155,51.758 -10.594,77.602 -0.3932,31.793 -0.6396,63.604 -0.031,95.398 l 21.781,-1.2943 -21.219,23.135 c 0.041,1.2322 0.081,2.4621 0.125,3.694 0.1398,25.837 38.758,3.234 39.437,-14.075 -0.522,-52.154 -1.3603,-104.4 1.9063,-156.5 6.1489,-24.928 33.689,-41.417 61.812,-44.787 31.318,-4.4778 67.758,-2.6342 92.781,16.016 17.831,12.31 21.591,32.024 19.031,50.449 -0.9481,98.57 -1.5396,197.19 -0.6875,295.74 7.8425,27.05 50.552,9.1799 39.656,-14.345 -0.048,-102.01 -0.024,-204.04 1.2188,-306.04 -4.9781,-34.62 -37.945,-63.117 -76.125,-72.479 -16.133,-4.4659 -33.097,-6.6347 -50.031,-6.6061 z"
|
||||||
|
fill="url(#i)"
|
||||||
|
id="path154"
|
||||||
|
style="fill:url(#i)" />
|
||||||
|
<path
|
||||||
|
d="m -719.39,1290.2 c -35.758,0 -64.743,5.9938 -64.743,13.383 0,3.7664 7.5446,7.1567 19.665,9.5881 11.739,-2.4569 28.043,-3.9782 46.071,-3.9782 17.531,0 33.42,1.4562 45.078,3.7949 11.544,-2.4162 18.693,-5.7411 18.693,-9.4048 0,-7.3892 -29.006,-13.383 -64.764,-13.383 z"
|
||||||
|
fill="#ffffff"
|
||||||
|
filter="url(#l)"
|
||||||
|
opacity="0.7278"
|
||||||
|
id="path156" />
|
||||||
|
</g>
|
||||||
|
<path
|
||||||
|
transform="matrix(0.26458333,0,0,0.22829308,-369.31904,41.045688)"
|
||||||
|
d="m 1734.4,339.23 c -46.21,0.1434 -97.408,19.082 -119.06,62.688 -13.801,27.856 -8.4155,59.986 -10.594,89.938 -0.3932,36.847 -0.6396,73.715 -0.031,110.56 l 21.781,-1.5 -21.219,26.812 c 0.041,1.428 0.081,2.8534 0.125,4.2812 0.1398,29.944 38.758,3.7481 39.438,-16.312 -0.522,-60.445 -1.3603,-121 1.9063,-181.38 6.1489,-28.89 33.689,-48.001 61.812,-51.906 31.318,-5.1896 67.758,-3.053 92.781,18.562 17.831,14.267 21.591,37.115 19.031,58.469 -0.9481,114.24 -1.5396,228.53 -0.6875,342.75 7.8425,31.35 50.552,10.639 39.656,-16.625 -0.048,-118.23 -0.024,-236.48 1.2188,-354.69 -4.9781,-40.123 -37.945,-73.15 -76.125,-84 -16.134,-5.1758 -33.097,-7.6894 -50.031,-7.6562 z"
|
||||||
|
fill="#cccccc"
|
||||||
|
filter="url(#p)"
|
||||||
|
id="path160" />
|
||||||
|
<path
|
||||||
|
transform="matrix(0.26458333,0,0,0.22817402,-239.06467,44.763084)"
|
||||||
|
d="m 1242.1,334.47 c -43.163,0.13395 -89.956,17.995 -109.06,56.438 v 0.0312 c -11.662,23.566 -7.2063,53.469 -9.4062,85.062 -0.3508,32.868 -0.5102,65.68 -0.125,98.438 l 9.875,-0.6875 a 11.211,11.211 0 0 1 7.7812,2.4375 c -0.4624,-52.634 -0.8032,-105.47 2.0625,-158.44 a 11.211,11.211 0 0 1 0.2187,-1.75 c 7.3342,-34.459 38.973,-56.043 70.938,-60.594 v -0.0312 c 0.1012,-0.0168 0.2111,-0.0146 0.3124,-0.0312 33.012,-5.4196 72.604,-3.6311 101.31,20.938 v -0.0312 c 0.077,0.0618 0.1419,0.12544 0.2187,0.1875 l 0.094,0.0937 c 21.121,17.144 25.459,43.852 22.938,67.031 -3e-4,0.0312 2e-4,0.0625 0,0.0937 -0.9432,113.66 -1.5218,227.34 -0.6876,340.91 1.2462,4.1697 2.7143,5.1796 4.0938,5.75 1.505,0.62221 4.0586,0.66583 6.9062,-0.625 2.8476,-1.29083 5.5447,-3.8207 6.875,-6.5312 1.3303,-2.7105 1.7621,-5.3878 0.1563,-9.4062 a 11.211,11.211 0 0 1 -0.8125,-4.1562 c -0.048,-117.93 -0.015,-235.92 1.2188,-353.91 -4.5894,-34.613 -34.106,-64.377 -67.969,-74 a 11.211,11.211 0 0 1 -0.375,-0.0937 c -14.962,-4.8001 -30.752,-7.156 -46.562,-7.125 z m -100.84,259.56 -16.969,21.469 v 0.1875 a 11.211,11.211 0 0 1 0,0.28125 c 0.01,1.215 0.1339,1.1748 0.25,1.7812 0.7478,-0.19089 1.4986,-0.32129 2.6875,-0.96875 3.2667,-1.779 7.2221,-5.135 9.9687,-8.6875 2.7466,-3.5525 4.0428,-7.2429 4.0938,-8.75 -0.015,-1.7663 -0.015,-3.5455 -0.031,-5.3125 z"
|
||||||
|
fill="#ffffff"
|
||||||
|
filter="url(#o)"
|
||||||
|
mask="url(#h)"
|
||||||
|
opacity="0.7"
|
||||||
|
id="path162" />
|
||||||
|
<path
|
||||||
|
transform="matrix(0.26458333,0,0,0.26458333,122.82712,81.114187)"
|
||||||
|
d="m -125.64,141.27 c -46.21,0.12373 -97.408,16.465 -119.06,54.089 -13.801,24.035 -8.4155,51.758 -10.594,77.602 -0.3932,31.793 -0.6396,63.604 -0.031,95.398 l 21.781,-1.2943 -21.219,23.135 c 0.041,1.2321 0.081,2.462 0.125,3.694 0.1398,25.837 38.758,3.234 39.437,-14.075 -0.522,-52.154 -1.3603,-104.4 1.9063,-156.5 6.1489,-24.928 33.689,-41.417 61.812,-44.787 31.318,-4.4778 67.758,-2.6342 92.781,16.016 17.831,12.31 21.591,32.024 19.031,50.449 -0.9481,98.57 -1.5396,197.19 -0.6875,295.74 7.8425,27.05 50.552,9.1799 39.656,-14.345 -0.048,-102.01 -0.024,-204.04 1.2188,-306.04 -4.9781,-34.62 -37.945,-63.117 -76.125,-72.479 -16.133,-4.4659 -33.097,-6.6347 -50.031,-6.6061 z"
|
||||||
|
fill="none"
|
||||||
|
filter="url(#m)"
|
||||||
|
mask="url(#g)"
|
||||||
|
stroke="#000000"
|
||||||
|
stroke-width="3"
|
||||||
|
id="path164" />
|
||||||
|
<path
|
||||||
|
d="M 52.186018,189.088 H 128.4257 a 3.3067625,3.3067625 0 0 1 3.30677,3.30676 v 62.34113 a 3.3067625,3.3067625 0 0 1 -3.30677,3.30676 H 52.186018 a 3.3067625,3.3067625 0 0 1 -3.306762,-3.30676 v -62.34113 a 3.3067625,3.3067625 0 0 1 3.306762,-3.30676"
|
||||||
|
fill="url(#s)"
|
||||||
|
id="path166"
|
||||||
|
style="fill:url(#s);stroke-width:0.264583" />
|
||||||
|
<path
|
||||||
|
d="M 52.186018,189.088 H 128.4257 a 3.3067625,3.3067625 0 0 1 3.30677,3.30676 v 62.34113 a 3.3067625,3.3067625 0 0 1 -3.30677,3.30676 H 52.186018 a 3.3067625,3.3067625 0 0 1 -3.306762,-3.30676 v -62.34113 a 3.3067625,3.3067625 0 0 1 3.306762,-3.30676"
|
||||||
|
fill="url(#w)"
|
||||||
|
id="path168"
|
||||||
|
style="fill:url(#w);stroke-width:0.264583" />
|
||||||
|
<path
|
||||||
|
transform="matrix(0.26458333,0,0,0.26458333,53.850247,13.119711)"
|
||||||
|
d="m -6.2998,662.08 c -8.5337,0 -15.5,6.9663 -15.5,15.5 V 913.2 c 0,8.5337 6.9663,15.5 15.5,15.5 h 288.16 c 8.5337,0 15.5,-6.9663 15.5,-15.5 V 677.58 c 0,-8.5337 -6.9663,-15.5 -15.5,-15.5 z m 0,6 h 288.16 c 5.3135,0 9.5,4.1865 9.5,9.5 V 913.2 c 0,5.3135 -4.1865,9.5 -9.5,9.5 h -288.16 c -5.3135,0 -9.5,-4.1865 -9.5,-9.5 V 677.58 c 0,-5.3135 4.1865,-9.5 9.5,-9.5 z"
|
||||||
|
fill="#ffffff"
|
||||||
|
filter="url(#c)"
|
||||||
|
mask="url(#b)"
|
||||||
|
id="path170" />
|
||||||
|
<path
|
||||||
|
d="m 52.185489,190.94723 c -0.817113,0 -1.413881,0.59674 -1.413881,1.41388 v 62.34112 c 0,0.81711 0.596741,1.41388 1.413881,1.41388 h 76.242331 c 0.81711,0 1.41388,-0.59674 1.41388,-1.41388 v -62.34112 c 0,-0.81712 -0.59674,-1.41388 -1.41388,-1.41388 z"
|
||||||
|
fill="url(#a)"
|
||||||
|
id="path172"
|
||||||
|
style="fill:url(#linearGradient459);stroke-width:0.264583" />
|
||||||
|
<path
|
||||||
|
d="m 124.96495,190.45854 c 1.06101,0.009 2.12225,0.0159 3.18321,0.0248 -0.0816,-0.0131 -0.16099,-0.0248 -0.24805,-0.0248 h -2.93529 z m -74.339973,0.42169 c -0.02551,0.0264 -0.05117,0.0542 -0.07441,0.0827 7.481887,0.18047 14.965891,0.3711 22.448308,0.52916 14.260512,0.30126 17.355608,0.32727 31.675915,0.55396 17.77179,0.21296 14.24119,0.19079 24.63932,0.23151 v -0.008 c -10.37405,-0.0406 -6.8617,-0.0269 -24.62265,-0.23977 -14.672204,-0.2323 -17.050809,-0.2382 -31.649458,-0.57052 -7.472363,-0.1701 -14.943667,-0.37735 -22.415235,-0.57878 z m 69.725643,2.2655 c -23.368792,0.0128 -46.738644,0.20531 -70.106643,0.4713 v 0.0744 c 26.354881,-0.36719 52.712933,-0.53279 79.068083,-0.39687 v -0.14055 c -2.98821,-0.004 -5.97456,-0.01 -8.96276,-0.008 z m 8.96276,1.62057 c -11.68215,0.0338 -23.3672,0.0883 -35.049352,0.19844 -22.163352,0.26082 -15.260373,0.13867 -37.380333,0.56224 -2.212604,0.0424 -4.426743,0.0875 -6.639454,0.13229 v 0.0165 c 8.422746,-0.17489 16.844698,-0.3446 25.267708,-0.47128 6.243108,-0.094 12.492567,-0.14975 18.735675,-0.22326 11.687966,-0.0938 23.377526,-0.16459 35.065226,-0.20669 v -0.008 z m -79.06808,3.23294 v 0.0331 c 16.594401,0.0845 33.189332,0.14893 49.784,0.2894 4.52464,0.0315 9.04346,0.0672 13.5681,0.091 4.22883,0.0222 10.16529,0.0394 15.71783,0.0413 v -0.14055 c -9.73111,0.0371 -19.4646,-0.008 -29.19412,-0.0661 -16.624565,-0.1157 -33.250188,-0.16804 -49.873958,-0.24808 z m 0,0.43823 v 0.0165 c 26.34853,0.83103 52.71029,1.1253 79.06808,1.33945 v -0.0661 C 102.95162,199.59307 76.595153,199.2671 50.2453,198.43747 Z m 0,1.77766 v 0.0744 c 6.776243,0.16414 13.554868,0.33639 20.331641,0.47955 14.260512,0.30123 17.355608,0.32727 31.675919,0.55399 18.95289,0.22704 13.68636,0.18555 27.06158,0.23976 v -0.008 c -13.35326,-0.0541 -8.10075,-0.0208 -27.04571,-0.24807 -14.672202,-0.23228 -17.050806,-0.23813 -31.649456,-0.5705 -6.791589,-0.15459 -13.58212,-0.338 -20.372916,-0.52091 z m 67.68306,2.20763 c -22.561813,0.0123 -45.12204,0.19516 -67.68306,0.44648 v 0.0662 c 18.969831,-0.25522 37.946541,-0.40838 56.91717,-0.41341 7.05035,-0.003 14.09991,0.0185 21.15026,0.0579 0.33372,0.003 0.66675,0.0127 1.00044,0.0165 v -0.15708 l -0.802,-0.008 c -3.52849,-0.006 -7.05485,-0.0102 -10.58334,-0.008 z m 11.38529,0.41341 c -9.66603,0.0358 -19.33126,0.0908 -28.99569,0.1819 -22.163352,0.26086 -15.260373,0.13867 -37.380334,0.56224 -4.230158,0.081 -8.461374,0.16108 -12.691797,0.24805 v 0.0248 c 10.440193,-0.21571 20.879593,-0.44651 31.321374,-0.60357 6.243109,-0.0939 12.4841,-0.14147 18.727477,-0.21497 9.67158,-0.0777 19.34977,-0.13967 29.02214,-0.1819 v -0.0165 z m -79.068086,3.43138 v 0.0331 l 5.1181,0.18192 c 15.994327,0.51224 31.996062,0.81148 47.998066,1.02526 -15.994331,-0.20574 -31.99342,-0.53136 -47.979545,-1.04182 -1.712436,-0.0646 -3.422121,-0.13229 -5.134504,-0.19844 z m 53.115106,1.24026 c 1.58186,0.0211 3.16415,0.0468 4.74609,0.0661 -3.46789,-0.0143 -6.94187,-0.0291 -10.409763,-0.0496 -15.817585,-0.11006 -31.633583,-0.15814 -47.450375,-0.23151 v 0.0248 c 15.787688,0.0786 31.572729,0.14751 47.360417,0.28112 4.524641,0.0315 9.051661,0.0672 13.576301,0.0909 3.06705,0.0161 7.05855,0.033 11.13737,0.0413 2.33153,0.0223 4.66328,0.0377 6.99505,0.0579 v -0.0413 l -1.81901,-0.008 h 1.81901 v -0.15711 c -6.36693,0.0336 -12.73254,0.0224 -19.09974,0 -2.28497,-0.0249 -4.56935,-0.045 -6.85429,-0.0744 z m -53.115106,0.59532 v 0.0909 c 8.794221,0.20828 17.589235,0.43434 26.383985,0.62011 14.260513,0.30125 17.355608,0.33552 31.675921,0.56224 15.99591,0.19166 13.99619,0.1879 21.0095,0.215 v -0.0166 c -7.00088,-0.027 -5.00512,-0.0235 -20.9931,-0.21494 -14.672204,-0.23233 -17.050808,-0.24644 -31.649458,-0.57881 -8.809302,-0.2005 -17.617017,-0.44151 -26.42526,-0.67796 z m 73.736726,2.37296 c -24.57926,0.0137 -49.15958,0.22442 -73.736726,0.51263 v 0.0744 c 26.354352,-0.38587 52.712936,-0.56346 79.068086,-0.45474 v -0.12401 c -1.77811,-0.001 -3.55495,-0.009 -5.33295,-0.008 z m 5.33294,1.62886 c -10.47247,0.0351 -20.94706,0.0914 -31.419266,0.19016 -22.163352,0.26087 -15.260373,0.13864 -37.380333,0.56223 -3.42265,0.0655 -6.846359,0.13642 -10.269009,0.20672 v 0.008 c 9.634009,-0.20024 19.263254,-0.40079 28.897792,-0.5457 6.243108,-0.0939 12.492566,-0.14148 18.735675,-0.21498 10.478031,-0.0841 20.957641,-0.14764 31.435141,-0.19018 z m -79.068078,3.20807 v 0.0331 c 17.804076,0.0946 35.61027,0.14695 53.414078,0.29766 4.52464,0.0315 9.05166,0.0755 13.5763,0.0992 3.29883,0.0173 7.68377,0.0338 12.07982,0.0413 v -0.13229 c -8.5217,0.0155 -17.04419,-0.0238 -25.56536,-0.0744 -17.834508,-0.12412 -35.668482,-0.17307 -53.504045,-0.26459 z m 0,0.32245 v 0.0248 c 0.900959,0.0318 1.802765,0.0678 2.703777,0.0992 11.693525,0.37452 23.384933,0.63519 35.081103,0.8351 -11.692202,-0.20029 -23.376731,-0.47844 -35.065228,-0.85161 -0.90678,-0.0342 -1.813428,-0.0728 -2.720182,-0.1075 z m 37.851291,0.95911 c 13.737167,0.23448 27.479627,0.38048 41.216787,0.4961 v -0.0579 c -13.73901,-0.0793 -27.47962,-0.20325 -41.216787,-0.43823 z m -37.851291,0.85162Line truncated
|
||||||
|
fill="#1a1a1a"
|
||||||
|
opacity="0.2"
|
||||||
|
stroke="#000000"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="bevel"
|
||||||
|
stroke-width="0.145381"
|
||||||
|
id="path174" />
|
||||||
|
<path
|
||||||
|
d="m 52.185489,190.94723 c -0.817113,0 -1.413881,0.59674 -1.413881,1.41388 v 62.34112 c 0,0.81711 0.596741,1.41388 1.413881,1.41388 h 76.242331 c 0.81711,0 1.41388,-0.59674 1.41388,-1.41388 v -62.34112 c 0,-0.81712 -0.59674,-1.41388 -1.41388,-1.41388 z"
|
||||||
|
fill="url(#a)"
|
||||||
|
id="path176"
|
||||||
|
style="fill:url(#linearGradient461);stroke-width:0.264583" />
|
||||||
|
<path
|
||||||
|
d="m 125.00729,190.98771 c 1.061,0.009 2.12225,0.0159 3.1832,0.0248 -0.0816,-0.0131 -0.16099,-0.0248 -0.24805,-0.0248 h -2.93528 z m -74.33998,0.42169 c -0.02551,0.0264 -0.05116,0.0542 -0.07441,0.0827 7.481887,0.18047 14.965891,0.37111 22.448308,0.52917 14.260512,0.30125 17.355608,0.32726 31.675912,0.55396 17.7718,0.21296 14.2412,0.19079 24.63932,0.23151 v -0.008 c -10.37404,-0.0406 -6.8617,-0.0269 -24.62265,-0.23976 -14.672201,-0.23231 -17.050805,-0.23821 -31.649455,-0.57052 -7.472362,-0.1701 -14.943666,-0.37735 -22.415235,-0.57878 z m 69.72564,2.26549 c -23.368789,0.0128 -46.73864,0.20532 -70.10664,0.47131 v 0.0744 c 26.354881,-0.36719 52.71294,-0.53279 79.06808,-0.39688 v -0.14054 c -2.9882,-0.004 -5.97455,-0.01 -8.96276,-0.008 z m 8.96277,1.62058 c -11.68215,0.0338 -23.36721,0.0883 -35.049359,0.19843 -22.163351,0.26083 -15.260372,0.13867 -37.380332,0.56224 -2.212605,0.0424 -4.426744,0.0875 -6.639454,0.1323 v 0.0165 c 8.422745,-0.17489 16.844697,-0.34459 25.267708,-0.47127 6.243108,-0.094 12.492566,-0.14976 18.735674,-0.22326 11.687973,-0.0938 23.377523,-0.1646 35.065233,-0.20669 v -0.008 z m -79.068087,3.23294 v 0.0331 c 16.594402,0.0845 33.189333,0.14894 49.783997,0.28941 4.52464,0.0315 9.04346,0.0672 13.5681,0.091 4.22884,0.0222 10.16529,0.0393 15.71784,0.0413 v -0.14055 c -9.73111,0.0371 -19.4646,-0.008 -29.19413,-0.0662 -16.624562,-0.1157 -33.250184,-0.16803 -49.873955,-0.24807 z m 0,0.43823 v 0.0165 c 26.348531,0.83103 52.710287,1.1253 79.068087,1.33945 v -0.0661 c -26.36176,-0.13425 -52.718233,-0.46021 -79.068087,-1.28984 z m 0,1.77766 v 0.0744 c 6.776244,0.16415 13.554868,0.3364 20.331641,0.47956 14.260513,0.30123 17.355608,0.32726 31.675916,0.55399 18.9529,0.22703 13.68637,0.18555 27.06158,0.23976 v -0.008 c -13.35325,-0.0541 -8.10074,-0.0208 -27.0457,-0.24808 -14.672208,-0.23227 -17.050813,-0.23812 -31.649462,-0.57049 -6.79159,-0.1546 -13.582121,-0.33801 -20.372917,-0.52091 z m 67.683057,2.20763 c -22.56181,0.0123 -45.122037,0.19515 -67.683057,0.44648 v 0.0661 c 18.969831,-0.25522 37.946541,-0.40839 56.917167,-0.41341 7.05035,-0.003 14.09991,0.0185 21.15026,0.0579 0.33372,0.003 0.66675,0.0127 1.00044,0.0165 v -0.15709 l -0.802,-0.008 c -3.52848,-0.006 -7.05485,-0.0102 -10.58333,-0.008 z m 11.38529,0.41341 c -9.66602,0.0358 -19.33125,0.0908 -28.99569,0.1819 -22.163349,0.26085 -15.26037,0.13867 -37.38033,0.56224 -4.230159,0.081 -8.461375,0.16108 -12.691798,0.24805 v 0.0248 c 10.440194,-0.21572 20.879594,-0.44651 31.321375,-0.60357 6.243108,-0.0939 12.484099,-0.14147 18.727473,-0.21497 9.67158,-0.0777 19.34977,-0.13968 29.02214,-0.18191 v -0.0165 z m -79.068083,3.43138 v 0.0331 l 5.1181,0.18193 c 15.994327,0.51223 31.996062,0.81148 47.998063,1.02526 -15.994328,-0.20574 -31.993417,-0.53136 -47.979542,-1.04182 -1.712436,-0.0646 -3.422121,-0.13229 -5.134504,-0.19844 z m 53.115103,1.24026 c 1.58187,0.0211 3.16415,0.0468 4.7461,0.0661 -3.4679,-0.0143 -6.94188,-0.029 -10.40977,-0.0496 -15.817585,-0.11007 -31.633583,-0.15814 -47.450374,-0.23151 v 0.0248 c 15.787687,0.0786 31.572729,0.1475 47.360416,0.28112 4.524638,0.0315 9.051658,0.0672 13.576298,0.0909 3.06705,0.0161 7.05856,0.033 11.13737,0.0413 2.33154,0.0223 4.66328,0.0377 6.99506,0.0579 v -0.0413 l -1.81901,-0.008 h 1.81901 v -0.15711 c -6.36694,0.0336 -12.73255,0.0224 -19.09974,0 -2.28497,-0.0249 -4.56936,-0.045 -6.8543,-0.0744 z m -53.115103,0.59531 v 0.0909 c 8.794221,0.20828 17.589236,0.43434 26.383986,0.6201 14.260512,0.30126 17.355608,0.33552 31.675917,0.56224 15.99591,0.19167 13.99619,0.18791 21.0095,0.215 v -0.0166 c -7.00087,-0.027 -5.00512,-0.0235 -20.9931,-0.21495 -14.672201,-0.23233 -17.050805,-0.24643 -31.649455,-0.5788 -8.809302,-0.2005 -17.617016,-0.44151 -26.42526,-0.67797 z m 73.736733,2.37297 c -24.579267,0.0137 -49.159587,0.22442 -73.736733,0.51263 v 0.0744 c 26.354352,-0.38587 52.712933,-0.56345 79.068083,-0.45474 v -0.12401 c -1.77811,-0.001 -3.55494,-0.009 -5.33294,-0.008 z m 5.33294,1.62886 c -10.47248,0.0351 -20.94706,0.0914 -31.419273,0.19015 -22.163352,0.26088 -15.260373,0.13864 -37.380333,0.56224 -3.42265,0.0655 -6.846358,0.13642 -10.269008,0.20672 v 0.008 c 9.634008,-0.20024 19.263254,-0.4008 28.897791,-0.54571 6.243108,-0.0939 12.492567,-0.14147 18.735675,-0.21497 10.478028,-0.0841 20.957648,-0.14764 31.435148,-0.19018 z m -79.068085,3.20807 v 0.0331 c 17.804077,0.0946 35.61027,0.14695 53.414085,0.29766 4.52464,0.0315 9.05166,0.0755 13.5763,0.0992 3.29882,0.0173 7.68376,0.0338 12.07981,0.0413 v -0.13229 c -8.5217,0.0155 -17.04419,-0.0238 -25.56536,-0.0744 -17.834504,-0.12411 -35.668479,-0.17306 -53.504041,-0.26458 z m 0,0.32245 v 0.0248 c 0.900959,0.0318 1.802765,0.0678 2.703777,0.0992 11.693525,0.37451 23.384933,0.63518 35.081104,0.8351 -11.692202,-0.20029 -23.376731,-0.47845 -35.065229,-0.85161 -0.90678,-0.0342 -1.813428,-0.0728 -2.720181,-0.1075 z m 37.851291,0.95911 c 13.737164,0.23447 27.479624,0.38047 41.216794,0.49609 v -0.0579 c -13.73902,-0.0793 -27.47963,-0.20325 -41.216794,-0.43823 z m -37.851291,0.85Line truncated
|
||||||
|
fill="#1a1a1a"
|
||||||
|
opacity="0.2"
|
||||||
|
stroke="#000000"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="bevel"
|
||||||
|
stroke-width="0.145381"
|
||||||
|
id="path178" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 46 KiB |
Reference in new issue
Block a user