Compare commits
26
Commits
dev2
...
a8aafa1519
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a8aafa1519 | ||
|
|
6f9cd6b471 | ||
|
|
865b7fd5c4 | ||
|
|
f35352eedd | ||
|
|
53580d7919 | ||
|
|
049b81610d | ||
|
|
fd60899f16 | ||
|
|
e0c4c849dc | ||
|
|
cb26201506 | ||
|
|
992e3c8db2 | ||
|
|
4956b64371 | ||
|
|
df6b362a31 | ||
|
|
2943634248 | ||
|
|
06f5a1af42 | ||
|
|
61d674199f | ||
|
|
398916fe10 | ||
|
|
bf4c46238e | ||
|
|
5ffa55c03c | ||
|
|
50f0985f4f | ||
|
|
69475604c0 | ||
|
|
856b6f1e1b | ||
|
|
414379b74e | ||
|
|
80b92ebe69 | ||
|
|
983d0e8639 | ||
|
|
d77437cda8 | ||
|
|
3d5cbedae1 |
No files matched your search
+2
-14
@@ -1,25 +1,13 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en" data-theme="dark">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>Vite + Svelte</title>
|
<title>Vite + Svelte</title>
|
||||||
|
|
||||||
<style>
|
|
||||||
body {
|
|
||||||
margin: 0;
|
|
||||||
display: grid;
|
|
||||||
align-items: center;
|
|
||||||
justify-items: center;
|
|
||||||
min-width: 100vw;
|
|
||||||
min-height: 100vh;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
<body class="bg-zinc-800">
|
<body id="app" class="m-0">
|
||||||
<div id="app"></div>
|
|
||||||
<script type="module" src="/src/main.js"></script>
|
<script type="module" src="/src/main.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
Generated
+1026
-701
File diff suppressed because it is too large.
Load diff
+2
-1
@@ -17,6 +17,7 @@
|
|||||||
"vite": "^3.0.7"
|
"vite": "^3.0.7"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tauri-apps/api": "^1.0.2"
|
"@tauri-apps/api": "^1.0.2",
|
||||||
|
"daisyui": "^2.51.5"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
[target.x86_64-unknown-linux-gnu]
|
||||||
|
linker = "clang"
|
||||||
|
rustflags = ["-C", "link-arg=--ld-path=/usr/bin/mold"]
|
||||||
|
|
||||||
|
[target.x86_64-pc-windows-msvc]
|
||||||
|
rustflags = ["-C", "link-arg=-fuse-ld=lld"]
|
||||||
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
DATABASE_URL=sqlite://creddy.db?mode=rwc
|
||||||
Generated
+624
-17
@@ -68,14 +68,22 @@ checksum = "bb07d2053ccdbe10e2af2995a2f116c1330396493dc1269f6a91d0ae82e19704"
|
|||||||
name = "app"
|
name = "app"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"aws-config",
|
||||||
|
"aws-sdk-sts",
|
||||||
|
"aws-smithy-types",
|
||||||
|
"aws-types",
|
||||||
"netstat2",
|
"netstat2",
|
||||||
|
"once_cell",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"sodiumoxide",
|
"sodiumoxide",
|
||||||
"sqlx",
|
"sqlx",
|
||||||
|
"strum 0.24.1",
|
||||||
|
"strum_macros 0.24.3",
|
||||||
"sysinfo",
|
"sysinfo",
|
||||||
"tauri",
|
"tauri",
|
||||||
"tauri-build",
|
"tauri-build",
|
||||||
|
"thiserror",
|
||||||
"tokio",
|
"tokio",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -136,12 +144,288 @@ version = "1.1.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aws-config"
|
||||||
|
version = "0.52.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e7688e1dfbb9f7804fab0a830820d7e827b8d973906763cf1a855ce4719292f5"
|
||||||
|
dependencies = [
|
||||||
|
"aws-http",
|
||||||
|
"aws-sdk-sso",
|
||||||
|
"aws-sdk-sts",
|
||||||
|
"aws-smithy-async",
|
||||||
|
"aws-smithy-client",
|
||||||
|
"aws-smithy-http",
|
||||||
|
"aws-smithy-http-tower",
|
||||||
|
"aws-smithy-json",
|
||||||
|
"aws-smithy-types",
|
||||||
|
"aws-types",
|
||||||
|
"bytes",
|
||||||
|
"hex",
|
||||||
|
"http",
|
||||||
|
"hyper",
|
||||||
|
"ring",
|
||||||
|
"time",
|
||||||
|
"tokio",
|
||||||
|
"tower",
|
||||||
|
"tracing",
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aws-endpoint"
|
||||||
|
version = "0.52.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "253d7cd480bfa59a5323390e9e91885a8f06a275e0517d81eeb1070b6aa7d271"
|
||||||
|
dependencies = [
|
||||||
|
"aws-smithy-http",
|
||||||
|
"aws-smithy-types",
|
||||||
|
"aws-types",
|
||||||
|
"http",
|
||||||
|
"regex",
|
||||||
|
"tracing",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aws-http"
|
||||||
|
version = "0.52.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4cd1b83859383e46ea8fda633378f9f3f02e6e3a446fd89f0240b5c3662716c9"
|
||||||
|
dependencies = [
|
||||||
|
"aws-smithy-http",
|
||||||
|
"aws-smithy-types",
|
||||||
|
"aws-types",
|
||||||
|
"bytes",
|
||||||
|
"http",
|
||||||
|
"http-body",
|
||||||
|
"lazy_static",
|
||||||
|
"percent-encoding",
|
||||||
|
"pin-project-lite",
|
||||||
|
"tracing",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aws-sdk-sso"
|
||||||
|
version = "0.22.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bf03342c2b3f52b180f484e60586500765474f2bfc7dcd4ffe893a7a1929db1d"
|
||||||
|
dependencies = [
|
||||||
|
"aws-endpoint",
|
||||||
|
"aws-http",
|
||||||
|
"aws-sig-auth",
|
||||||
|
"aws-smithy-async",
|
||||||
|
"aws-smithy-client",
|
||||||
|
"aws-smithy-http",
|
||||||
|
"aws-smithy-http-tower",
|
||||||
|
"aws-smithy-json",
|
||||||
|
"aws-smithy-types",
|
||||||
|
"aws-types",
|
||||||
|
"bytes",
|
||||||
|
"http",
|
||||||
|
"tokio-stream",
|
||||||
|
"tower",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aws-sdk-sts"
|
||||||
|
version = "0.22.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "aa1de4e07ea87a30a317c7b563b3a40fd18a843ad794216dda81672b6e174bce"
|
||||||
|
dependencies = [
|
||||||
|
"aws-endpoint",
|
||||||
|
"aws-http",
|
||||||
|
"aws-sig-auth",
|
||||||
|
"aws-smithy-async",
|
||||||
|
"aws-smithy-client",
|
||||||
|
"aws-smithy-http",
|
||||||
|
"aws-smithy-http-tower",
|
||||||
|
"aws-smithy-query",
|
||||||
|
"aws-smithy-types",
|
||||||
|
"aws-smithy-xml",
|
||||||
|
"aws-types",
|
||||||
|
"bytes",
|
||||||
|
"http",
|
||||||
|
"tower",
|
||||||
|
"tracing",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aws-sig-auth"
|
||||||
|
version = "0.52.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6126c4ff918e35fb9ae1bf2de71157fad36f0cc6a2b1d0f7197ee711713700fc"
|
||||||
|
dependencies = [
|
||||||
|
"aws-sigv4",
|
||||||
|
"aws-smithy-http",
|
||||||
|
"aws-types",
|
||||||
|
"http",
|
||||||
|
"tracing",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aws-sigv4"
|
||||||
|
version = "0.52.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "84c7f88d7395f5411c6eef5889b6cd577ce6b677af461356cbfc20176c26c160"
|
||||||
|
dependencies = [
|
||||||
|
"aws-smithy-http",
|
||||||
|
"form_urlencoded",
|
||||||
|
"hex",
|
||||||
|
"hmac",
|
||||||
|
"http",
|
||||||
|
"once_cell",
|
||||||
|
"percent-encoding",
|
||||||
|
"regex",
|
||||||
|
"sha2",
|
||||||
|
"time",
|
||||||
|
"tracing",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aws-smithy-async"
|
||||||
|
version = "0.52.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3e6a895d68852dd1564328e63ef1583e5eb307dd2a5ebf35d862a5c402957d5e"
|
||||||
|
dependencies = [
|
||||||
|
"futures-util",
|
||||||
|
"pin-project-lite",
|
||||||
|
"tokio",
|
||||||
|
"tokio-stream",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aws-smithy-client"
|
||||||
|
version = "0.52.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f505bf793eb3e6d7c166ef1275c27b4b2cd5361173fe950ac8e2cfc08c29a7ef"
|
||||||
|
dependencies = [
|
||||||
|
"aws-smithy-async",
|
||||||
|
"aws-smithy-http",
|
||||||
|
"aws-smithy-http-tower",
|
||||||
|
"aws-smithy-types",
|
||||||
|
"bytes",
|
||||||
|
"fastrand",
|
||||||
|
"http",
|
||||||
|
"http-body",
|
||||||
|
"hyper",
|
||||||
|
"hyper-rustls",
|
||||||
|
"lazy_static",
|
||||||
|
"pin-project-lite",
|
||||||
|
"tokio",
|
||||||
|
"tower",
|
||||||
|
"tracing",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aws-smithy-http"
|
||||||
|
version = "0.52.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "37e4b4304b7ea4af1af3e08535100eb7b6459d5a6264b92078bf85176d04ab85"
|
||||||
|
dependencies = [
|
||||||
|
"aws-smithy-types",
|
||||||
|
"bytes",
|
||||||
|
"bytes-utils",
|
||||||
|
"futures-core",
|
||||||
|
"http",
|
||||||
|
"http-body",
|
||||||
|
"hyper",
|
||||||
|
"once_cell",
|
||||||
|
"percent-encoding",
|
||||||
|
"pin-project-lite",
|
||||||
|
"pin-utils",
|
||||||
|
"tokio",
|
||||||
|
"tokio-util",
|
||||||
|
"tracing",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aws-smithy-http-tower"
|
||||||
|
version = "0.52.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e86072ecc4dc4faf3e2071144285cfd539263fe7102b701d54fb991eafb04af8"
|
||||||
|
dependencies = [
|
||||||
|
"aws-smithy-http",
|
||||||
|
"aws-smithy-types",
|
||||||
|
"bytes",
|
||||||
|
"http",
|
||||||
|
"http-body",
|
||||||
|
"pin-project-lite",
|
||||||
|
"tower",
|
||||||
|
"tracing",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aws-smithy-json"
|
||||||
|
version = "0.52.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9e3ddd9275b167bc59e9446469eca56177ec0b51225632f90aaa2cd5f41c940e"
|
||||||
|
dependencies = [
|
||||||
|
"aws-smithy-types",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aws-smithy-query"
|
||||||
|
version = "0.52.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "13b19d2e0b3ce20e460bad0d0d974238673100edebba6978c2c1aadd925602f7"
|
||||||
|
dependencies = [
|
||||||
|
"aws-smithy-types",
|
||||||
|
"urlencoding",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aws-smithy-types"
|
||||||
|
version = "0.52.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "987b1e37febb9bd409ca0846e82d35299e572ad8279bc404778caeb5fc05ad56"
|
||||||
|
dependencies = [
|
||||||
|
"base64-simd",
|
||||||
|
"itoa 1.0.2",
|
||||||
|
"num-integer",
|
||||||
|
"ryu",
|
||||||
|
"time",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aws-smithy-xml"
|
||||||
|
version = "0.52.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "37ce3791e14eec75ffac851a5a559f1ce6b31843297f42cc8bfba82714a6a5d8"
|
||||||
|
dependencies = [
|
||||||
|
"xmlparser",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aws-types"
|
||||||
|
version = "0.52.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6c05adca3e2bcf686dd2c47836f216ab52ed7845c177d180c84b08522c1166a3"
|
||||||
|
dependencies = [
|
||||||
|
"aws-smithy-async",
|
||||||
|
"aws-smithy-client",
|
||||||
|
"aws-smithy-http",
|
||||||
|
"aws-smithy-types",
|
||||||
|
"http",
|
||||||
|
"rustc_version 0.4.0",
|
||||||
|
"tracing",
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "base64"
|
name = "base64"
|
||||||
version = "0.13.0"
|
version = "0.13.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
|
checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "base64-simd"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "781dd20c3aff0bd194fe7d2a977dd92f21c173891f3a03b677359e5fa457e5d5"
|
||||||
|
dependencies = [
|
||||||
|
"simd-abstraction",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "1.3.2"
|
version = "1.3.2"
|
||||||
@@ -217,6 +501,16 @@ version = "1.2.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db"
|
checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bytes-utils"
|
||||||
|
version = "0.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e47d3a8076e283f3acd27400535992edb3ba4b5bb72f8891ad8fbe7932a7d4b9"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"either",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cairo-rs"
|
name = "cairo-rs"
|
||||||
version = "0.15.12"
|
version = "0.15.12"
|
||||||
@@ -618,6 +912,7 @@ checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"block-buffer",
|
"block-buffer",
|
||||||
"crypto-common",
|
"crypto-common",
|
||||||
|
"subtle",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -736,7 +1031,7 @@ dependencies = [
|
|||||||
"cfg-if",
|
"cfg-if",
|
||||||
"libc",
|
"libc",
|
||||||
"redox_syscall",
|
"redox_syscall",
|
||||||
"windows-sys",
|
"windows-sys 0.36.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1203,6 +1498,25 @@ dependencies = [
|
|||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "h2"
|
||||||
|
version = "0.3.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5f9f29bc9dda355256b2916cf526ab02ce0aeaaaf2bad60d65ef3f12f11dd0f4"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"fnv",
|
||||||
|
"futures-core",
|
||||||
|
"futures-sink",
|
||||||
|
"futures-util",
|
||||||
|
"http",
|
||||||
|
"indexmap",
|
||||||
|
"slab",
|
||||||
|
"tokio",
|
||||||
|
"tokio-util",
|
||||||
|
"tracing",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashbrown"
|
name = "hashbrown"
|
||||||
version = "0.12.3"
|
version = "0.12.3"
|
||||||
@@ -1254,6 +1568,15 @@ version = "0.4.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hmac"
|
||||||
|
version = "0.12.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
|
||||||
|
dependencies = [
|
||||||
|
"digest",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "html5ever"
|
name = "html5ever"
|
||||||
version = "0.25.2"
|
version = "0.25.2"
|
||||||
@@ -1279,12 +1602,75 @@ dependencies = [
|
|||||||
"itoa 1.0.2",
|
"itoa 1.0.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "http-body"
|
||||||
|
version = "0.4.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"http",
|
||||||
|
"pin-project-lite",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "http-range"
|
name = "http-range"
|
||||||
version = "0.1.5"
|
version = "0.1.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "21dec9db110f5f872ed9699c3ecf50cf16f423502706ba5c72462e28d3157573"
|
checksum = "21dec9db110f5f872ed9699c3ecf50cf16f423502706ba5c72462e28d3157573"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "httparse"
|
||||||
|
version = "1.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "httpdate"
|
||||||
|
version = "1.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hyper"
|
||||||
|
version = "0.14.22"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "abfba89e19b959ca163c7752ba59d737c1ceea53a5d31a149c805446fc958064"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"futures-channel",
|
||||||
|
"futures-core",
|
||||||
|
"futures-util",
|
||||||
|
"h2",
|
||||||
|
"http",
|
||||||
|
"http-body",
|
||||||
|
"httparse",
|
||||||
|
"httpdate",
|
||||||
|
"itoa 1.0.2",
|
||||||
|
"pin-project-lite",
|
||||||
|
"socket2",
|
||||||
|
"tokio",
|
||||||
|
"tower-service",
|
||||||
|
"tracing",
|
||||||
|
"want",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hyper-rustls"
|
||||||
|
version = "0.23.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1788965e61b367cd03a62950836d5cd41560c3577d90e40e0819373194d1661c"
|
||||||
|
dependencies = [
|
||||||
|
"http",
|
||||||
|
"hyper",
|
||||||
|
"log",
|
||||||
|
"rustls",
|
||||||
|
"rustls-native-certs",
|
||||||
|
"tokio",
|
||||||
|
"tokio-rustls",
|
||||||
|
"webpki-roots",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ico"
|
name = "ico"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@@ -1496,6 +1882,30 @@ version = "1.4.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libappindicator"
|
||||||
|
version = "0.7.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "db2d3cb96d092b4824cb306c9e544c856a4cb6210c1081945187f7f1924b47e8"
|
||||||
|
dependencies = [
|
||||||
|
"glib",
|
||||||
|
"gtk",
|
||||||
|
"gtk-sys",
|
||||||
|
"libappindicator-sys",
|
||||||
|
"log",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libappindicator-sys"
|
||||||
|
version = "0.7.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f1b3b6681973cea8cc3bce7391e6d7d5502720b80a581c9a95c9cbaf592826aa"
|
||||||
|
dependencies = [
|
||||||
|
"gtk-sys",
|
||||||
|
"libloading",
|
||||||
|
"once_cell",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.126"
|
version = "0.2.126"
|
||||||
@@ -1511,6 +1921,16 @@ dependencies = [
|
|||||||
"pkg-config",
|
"pkg-config",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libloading"
|
||||||
|
version = "0.7.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libsodium-sys"
|
name = "libsodium-sys"
|
||||||
version = "0.2.7"
|
version = "0.2.7"
|
||||||
@@ -1682,7 +2102,7 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"wasi 0.11.0+wasi-snapshot-preview1",
|
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||||
"windows-sys",
|
"windows-sys 0.36.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1920,9 +2340,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "once_cell"
|
name = "once_cell"
|
||||||
version = "1.13.0"
|
version = "1.16.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1"
|
checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "open"
|
name = "open"
|
||||||
@@ -1931,7 +2351,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "f23a407004a1033f53e93f9b45580d14de23928faad187384f891507c9b0c045"
|
checksum = "f23a407004a1033f53e93f9b45580d14de23928faad187384f891507c9b0c045"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"pathdiff",
|
"pathdiff",
|
||||||
"windows-sys",
|
"windows-sys 0.36.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2000,6 +2420,12 @@ dependencies = [
|
|||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "outref"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7f222829ae9293e33a9f5e9f440c6760a3d450a64affe1846486b140db81c1f4"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pango"
|
name = "pango"
|
||||||
version = "0.15.10"
|
version = "0.15.10"
|
||||||
@@ -2076,7 +2502,7 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
"redox_syscall",
|
"redox_syscall",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"windows-sys",
|
"windows-sys 0.36.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2589,6 +3015,18 @@ dependencies = [
|
|||||||
"webpki",
|
"webpki",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustls-native-certs"
|
||||||
|
version = "0.6.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0167bac7a9f490495f3c33013e7722b53cb087ecbe082fb0c6387c96f634ea50"
|
||||||
|
dependencies = [
|
||||||
|
"openssl-probe",
|
||||||
|
"rustls-pemfile",
|
||||||
|
"schannel",
|
||||||
|
"security-framework",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustls-pemfile"
|
name = "rustls-pemfile"
|
||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
@@ -2632,7 +3070,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "88d6731146462ea25d9244b2ed5fd1d716d25c52e4d54aa4fb0f3c4e9854dbe2"
|
checksum = "88d6731146462ea25d9244b2ed5fd1d716d25c52e4d54aa4fb0f3c4e9854dbe2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"windows-sys",
|
"windows-sys 0.36.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2880,6 +3318,15 @@ version = "1.5.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f054c6c1a6e95179d6f23ed974060dcefb2d9388bb7256900badad682c499de4"
|
checksum = "f054c6c1a6e95179d6f23ed974060dcefb2d9388bb7256900badad682c499de4"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "simd-abstraction"
|
||||||
|
version = "0.7.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9cadb29c57caadc51ff8346233b5cec1d240b68ce55cf1afc764818791876987"
|
||||||
|
dependencies = [
|
||||||
|
"outref",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "siphasher"
|
name = "siphasher"
|
||||||
version = "0.3.10"
|
version = "0.3.10"
|
||||||
@@ -3126,9 +3573,15 @@ version = "0.22.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f7ac893c7d471c8a21f31cfe213ec4f6d9afeed25537c772e08ef3f005f8729e"
|
checksum = "f7ac893c7d471c8a21f31cfe213ec4f6d9afeed25537c772e08ef3f005f8729e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"strum_macros",
|
"strum_macros 0.22.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "strum"
|
||||||
|
version = "0.24.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "strum_macros"
|
name = "strum_macros"
|
||||||
version = "0.22.0"
|
version = "0.22.0"
|
||||||
@@ -3141,6 +3594,25 @@ dependencies = [
|
|||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "strum_macros"
|
||||||
|
version = "0.24.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59"
|
||||||
|
dependencies = [
|
||||||
|
"heck 0.4.0",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"rustversion",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "subtle"
|
||||||
|
version = "2.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "1.0.98"
|
version = "1.0.98"
|
||||||
@@ -3206,6 +3678,7 @@ dependencies = [
|
|||||||
"core-foundation",
|
"core-foundation",
|
||||||
"core-graphics",
|
"core-graphics",
|
||||||
"crossbeam-channel",
|
"crossbeam-channel",
|
||||||
|
"dirs-next",
|
||||||
"dispatch",
|
"dispatch",
|
||||||
"gdk",
|
"gdk",
|
||||||
"gdk-pixbuf",
|
"gdk-pixbuf",
|
||||||
@@ -3219,6 +3692,7 @@ dependencies = [
|
|||||||
"instant",
|
"instant",
|
||||||
"jni 0.19.0",
|
"jni 0.19.0",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
|
"libappindicator",
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"ndk",
|
"ndk",
|
||||||
@@ -3459,18 +3933,18 @@ checksum = "8eaa81235c7058867fa8c0e7314f33dcce9c215f535d1913822a2b3f5e289f3c"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror"
|
name = "thiserror"
|
||||||
version = "1.0.31"
|
version = "1.0.38"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a"
|
checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"thiserror-impl",
|
"thiserror-impl",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror-impl"
|
name = "thiserror-impl"
|
||||||
version = "1.0.31"
|
version = "1.0.38"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a"
|
checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -3514,9 +3988,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio"
|
name = "tokio"
|
||||||
version = "1.20.1"
|
version = "1.23.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7a8325f63a7d4774dd041e363b2409ed1c5cbbd0f867795e661df066b2b0a581"
|
checksum = "eab6d665857cc6ca78d6e80303a02cea7a7851e85dfbd77cbdc09bd129f1ef46"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg",
|
"autocfg",
|
||||||
"bytes",
|
"bytes",
|
||||||
@@ -3524,13 +3998,12 @@ dependencies = [
|
|||||||
"memchr",
|
"memchr",
|
||||||
"mio",
|
"mio",
|
||||||
"num_cpus",
|
"num_cpus",
|
||||||
"once_cell",
|
|
||||||
"parking_lot 0.12.1",
|
"parking_lot 0.12.1",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"signal-hook-registry",
|
"signal-hook-registry",
|
||||||
"socket2",
|
"socket2",
|
||||||
"tokio-macros",
|
"tokio-macros",
|
||||||
"winapi",
|
"windows-sys 0.42.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3566,6 +4039,20 @@ dependencies = [
|
|||||||
"tokio",
|
"tokio",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tokio-util"
|
||||||
|
version = "0.7.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0bb2e075f03b3d66d8d8785356224ba688d2906a371015e225beeb65ca92c740"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"futures-core",
|
||||||
|
"futures-sink",
|
||||||
|
"pin-project-lite",
|
||||||
|
"tokio",
|
||||||
|
"tracing",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml"
|
name = "toml"
|
||||||
version = "0.5.9"
|
version = "0.5.9"
|
||||||
@@ -3575,6 +4062,34 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tower"
|
||||||
|
version = "0.4.13"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c"
|
||||||
|
dependencies = [
|
||||||
|
"futures-core",
|
||||||
|
"futures-util",
|
||||||
|
"pin-project",
|
||||||
|
"pin-project-lite",
|
||||||
|
"tokio",
|
||||||
|
"tower-layer",
|
||||||
|
"tower-service",
|
||||||
|
"tracing",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tower-layer"
|
||||||
|
version = "0.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tower-service"
|
||||||
|
version = "0.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tracing"
|
name = "tracing"
|
||||||
version = "0.1.36"
|
version = "0.1.36"
|
||||||
@@ -3582,6 +4097,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "2fce9567bd60a67d08a16488756721ba392f24f29006402881e43b19aac64307"
|
checksum = "2fce9567bd60a67d08a16488756721ba392f24f29006402881e43b19aac64307"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
|
"log",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"tracing-attributes",
|
"tracing-attributes",
|
||||||
"tracing-core",
|
"tracing-core",
|
||||||
@@ -3646,6 +4162,12 @@ dependencies = [
|
|||||||
"serde_json",
|
"serde_json",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "try-lock"
|
||||||
|
version = "0.2.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "typenum"
|
name = "typenum"
|
||||||
version = "1.15.0"
|
version = "1.15.0"
|
||||||
@@ -3710,6 +4232,12 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "urlencoding"
|
||||||
|
version = "2.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e8db7427f936968176eaa7cdf81b7f98b980b18495ec28f1b5791ac3bfe3eea9"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "utf-8"
|
name = "utf-8"
|
||||||
version = "0.7.6"
|
version = "0.7.6"
|
||||||
@@ -3798,6 +4326,16 @@ dependencies = [
|
|||||||
"winapi-util",
|
"winapi-util",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "want"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0"
|
||||||
|
dependencies = [
|
||||||
|
"log",
|
||||||
|
"try-lock",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasi"
|
name = "wasi"
|
||||||
version = "0.9.0+wasi-snapshot-preview1"
|
version = "0.9.0+wasi-snapshot-preview1"
|
||||||
@@ -4104,12 +4642,33 @@ dependencies = [
|
|||||||
"windows_x86_64_msvc 0.36.1",
|
"windows_x86_64_msvc 0.36.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-sys"
|
||||||
|
version = "0.42.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
|
||||||
|
dependencies = [
|
||||||
|
"windows_aarch64_gnullvm",
|
||||||
|
"windows_aarch64_msvc 0.42.0",
|
||||||
|
"windows_i686_gnu 0.42.0",
|
||||||
|
"windows_i686_msvc 0.42.0",
|
||||||
|
"windows_x86_64_gnu 0.42.0",
|
||||||
|
"windows_x86_64_gnullvm",
|
||||||
|
"windows_x86_64_msvc 0.42.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-tokens"
|
name = "windows-tokens"
|
||||||
version = "0.37.0"
|
version = "0.37.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3263d25f1170419995b78ff10c06b949e8a986c35c208dc24333c64753a87169"
|
checksum = "3263d25f1170419995b78ff10c06b949e8a986c35c208dc24333c64753a87169"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_gnullvm"
|
||||||
|
version = "0.42.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_aarch64_msvc"
|
name = "windows_aarch64_msvc"
|
||||||
version = "0.32.0"
|
version = "0.32.0"
|
||||||
@@ -4128,6 +4687,12 @@ version = "0.37.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2623277cb2d1c216ba3b578c0f3cf9cdebeddb6e66b1b218bb33596ea7769c3a"
|
checksum = "2623277cb2d1c216ba3b578c0f3cf9cdebeddb6e66b1b218bb33596ea7769c3a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_msvc"
|
||||||
|
version = "0.42.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_i686_gnu"
|
name = "windows_i686_gnu"
|
||||||
version = "0.24.0"
|
version = "0.24.0"
|
||||||
@@ -4152,6 +4717,12 @@ version = "0.37.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d3925fd0b0b804730d44d4b6278c50f9699703ec49bcd628020f46f4ba07d9e1"
|
checksum = "d3925fd0b0b804730d44d4b6278c50f9699703ec49bcd628020f46f4ba07d9e1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_gnu"
|
||||||
|
version = "0.42.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_i686_msvc"
|
name = "windows_i686_msvc"
|
||||||
version = "0.24.0"
|
version = "0.24.0"
|
||||||
@@ -4176,6 +4747,12 @@ version = "0.37.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ce907ac74fe331b524c1298683efbf598bb031bc84d5e274db2083696d07c57c"
|
checksum = "ce907ac74fe331b524c1298683efbf598bb031bc84d5e274db2083696d07c57c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_msvc"
|
||||||
|
version = "0.42.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_gnu"
|
name = "windows_x86_64_gnu"
|
||||||
version = "0.24.0"
|
version = "0.24.0"
|
||||||
@@ -4200,6 +4777,18 @@ version = "0.37.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2babfba0828f2e6b32457d5341427dcbb577ceef556273229959ac23a10af33d"
|
checksum = "2babfba0828f2e6b32457d5341427dcbb577ceef556273229959ac23a10af33d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnu"
|
||||||
|
version = "0.42.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnullvm"
|
||||||
|
version = "0.42.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_msvc"
|
name = "windows_x86_64_msvc"
|
||||||
version = "0.24.0"
|
version = "0.24.0"
|
||||||
@@ -4224,6 +4813,12 @@ version = "0.37.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f4dd6dc7df2d84cf7b33822ed5b86318fb1781948e9663bacd047fc9dd52259d"
|
checksum = "f4dd6dc7df2d84cf7b33822ed5b86318fb1781948e9663bacd047fc9dd52259d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_msvc"
|
||||||
|
version = "0.42.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winreg"
|
name = "winreg"
|
||||||
version = "0.10.1"
|
version = "0.10.1"
|
||||||
@@ -4248,7 +4843,7 @@ version = "0.5.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "007a0353840b23e0c6dc73e5b962ff58ed7f6bc9ceff3ce7fe6fbad8d496edf4"
|
checksum = "007a0353840b23e0c6dc73e5b962ff58ed7f6bc9ceff3ce7fe6fbad8d496edf4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"strum",
|
"strum 0.22.0",
|
||||||
"windows 0.24.0",
|
"windows 0.24.0",
|
||||||
"xml-rs",
|
"xml-rs",
|
||||||
]
|
]
|
||||||
@@ -4320,3 +4915,15 @@ name = "xml-rs"
|
|||||||
version = "0.8.4"
|
version = "0.8.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d2d7d3948613f75c98fd9328cfdcc45acc4d360655289d0a7d4ec931392200a3"
|
checksum = "d2d7d3948613f75c98fd9328cfdcc45acc4d360655289d0a7d4ec931392200a3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "xmlparser"
|
||||||
|
version = "0.13.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4d25c75bf9ea12c4040a97f829154768bbbce366287e2dc044af160cd79a13fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zeroize"
|
||||||
|
version = "1.5.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c394b5bd0c6f669e7275d9c20aa90ae064cb22e75a1cad54e1b34088034b149f"
|
||||||
+12
-1
@@ -17,12 +17,20 @@ 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.0.5", features = ["api-all"] }
|
tauri = { version = "1.0.5", features = ["api-all", "system-tray"] }
|
||||||
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"] }
|
||||||
netstat2 = "0.9.1"
|
netstat2 = "0.9.1"
|
||||||
sysinfo = "0.26.8"
|
sysinfo = "0.26.8"
|
||||||
|
aws-types = "0.52.0"
|
||||||
|
aws-sdk-sts = "0.22.0"
|
||||||
|
aws-smithy-types = "0.52.0"
|
||||||
|
aws-config = "0.52.0"
|
||||||
|
thiserror = "1.0.38"
|
||||||
|
once_cell = "1.16.0"
|
||||||
|
strum = "0.24"
|
||||||
|
strum_macros = "0.24"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
# by default Tauri runs in production mode
|
# by default Tauri runs in production mode
|
||||||
@@ -31,3 +39,6 @@ default = [ "custom-protocol" ]
|
|||||||
# this feature is used used for production builds where `devPath` points to the filesystem
|
# this feature is used used for production builds where `devPath` points to the filesystem
|
||||||
# DO NOT remove this
|
# DO NOT remove this
|
||||||
custom-protocol = [ "tauri/custom-protocol" ]
|
custom-protocol = [ "tauri/custom-protocol" ]
|
||||||
|
|
||||||
|
# [profile.dev.build-override]
|
||||||
|
# opt-level = 3
|
||||||
@@ -3,12 +3,13 @@ CREATE TABLE credentials (
|
|||||||
access_key_id TEXT NOT NULL,
|
access_key_id TEXT NOT NULL,
|
||||||
secret_key_enc BLOB NOT NULL,
|
secret_key_enc BLOB NOT NULL,
|
||||||
salt BLOB NOT NULL,
|
salt BLOB NOT NULL,
|
||||||
nonce BLOB NOT NULL
|
nonce BLOB NOT NULL,
|
||||||
|
created_at INTEGER NOT NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE config (
|
CREATE TABLE config (
|
||||||
name TEXT,
|
name TEXT NOT NULL,
|
||||||
data TEXT
|
data TEXT NOT NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE clients (
|
CREATE TABLE clients (
|
||||||
|
|||||||
+26
-13
@@ -1,17 +1,26 @@
|
|||||||
use netstat2::{AddressFamilyFlags, ProtocolFlags, ProtocolSocketInfo};
|
use netstat2::{AddressFamilyFlags, ProtocolFlags, ProtocolSocketInfo};
|
||||||
use sysinfo::{System, SystemExt, Pid, ProcessExt};
|
use sysinfo::{System, SystemExt, Pid, PidExt, ProcessExt};
|
||||||
|
use serde::{Serialize, Deserialize};
|
||||||
|
|
||||||
use crate::errors::*;
|
use crate::errors::*;
|
||||||
use crate::ipc::Client;
|
use crate::get_state;
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Hash)]
|
||||||
|
pub struct Client {
|
||||||
|
pub pid: u32,
|
||||||
|
pub exe: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
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 mut it = netstat2::iterate_sockets_info(
|
let sockets_iter = netstat2::iterate_sockets_info(
|
||||||
AddressFamilyFlags::IPV4,
|
AddressFamilyFlags::IPV4,
|
||||||
ProtocolFlags::TCP
|
ProtocolFlags::TCP
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
for (i, item) in it.enumerate() {
|
get_state!(config as app_config);
|
||||||
|
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 {
|
||||||
ProtocolSocketInfo::Tcp(tcp_info) => tcp_info,
|
ProtocolSocketInfo::Tcp(tcp_info) => tcp_info,
|
||||||
@@ -19,9 +28,9 @@ fn get_associated_pids(local_port: u16) -> Result<Vec<u32>, netstat2::error::Err
|
|||||||
};
|
};
|
||||||
|
|
||||||
if proto_info.local_port == local_port
|
if proto_info.local_port == local_port
|
||||||
&& proto_info.remote_port == 12345
|
&& proto_info.remote_port == app_config.listen_port
|
||||||
&& proto_info.local_addr == std::net::Ipv4Addr::LOCALHOST
|
&& proto_info.local_addr == app_config.listen_addr
|
||||||
&& proto_info.remote_addr == std::net::Ipv4Addr::LOCALHOST
|
&& proto_info.remote_addr == app_config.listen_addr
|
||||||
{
|
{
|
||||||
return Ok(sock_info.associated_pids)
|
return Ok(sock_info.associated_pids)
|
||||||
}
|
}
|
||||||
@@ -30,22 +39,26 @@ fn get_associated_pids(local_port: u16) -> Result<Vec<u32>, netstat2::error::Err
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Theoretically, on some systems, multiple processes can share a socket. We have to
|
// Theoretically, on some systems, multiple processes can share a socket
|
||||||
// account for this even though 99% of the time there will be only one.
|
pub fn get_clients(local_port: u16) -> Result<Vec<Option<Client>>, ClientInfoError> {
|
||||||
pub fn get_clients(local_port: u16) -> Result<Vec<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)? {
|
for p in get_associated_pids(local_port)? {
|
||||||
let pid = Pid::from(p as usize);
|
let pid = Pid::from_u32(p);
|
||||||
sys.refresh_process(pid);
|
sys.refresh_process(pid);
|
||||||
let proc = sys.process(pid)
|
let proc = sys.process(pid)
|
||||||
.ok_or(ClientInfoError::PidNotFound)?;
|
.ok_or(ClientInfoError::ProcessNotFound)?;
|
||||||
|
|
||||||
let client = Client {
|
let client = Client {
|
||||||
pid: p,
|
pid: p,
|
||||||
exe: proc.exe().to_string_lossy().into_owned(),
|
exe: proc.exe().to_string_lossy().into_owned(),
|
||||||
};
|
};
|
||||||
clients.push(client);
|
clients.push(Some(client));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if clients.is_empty() {
|
||||||
|
clients.push(None);
|
||||||
|
}
|
||||||
|
|
||||||
Ok(clients)
|
Ok(clients)
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
use std::net::Ipv4Addr;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
use serde::{Serialize, Deserialize};
|
||||||
|
use sqlx::SqlitePool;
|
||||||
|
|
||||||
|
use crate::errors::*;
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
pub struct AppConfig {
|
||||||
|
#[serde(default = "default_listen_addr")]
|
||||||
|
pub listen_addr: Ipv4Addr,
|
||||||
|
#[serde(default = "default_listen_port")]
|
||||||
|
pub listen_port: u16,
|
||||||
|
#[serde(default = "default_rehide_ms")]
|
||||||
|
pub rehide_ms: u64,
|
||||||
|
#[serde(default = "default_start_minimized")]
|
||||||
|
pub start_minimized: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl Default for AppConfig {
|
||||||
|
fn default() -> Self {
|
||||||
|
AppConfig {
|
||||||
|
listen_addr: default_listen_addr(),
|
||||||
|
listen_port: default_listen_port(),
|
||||||
|
rehide_ms: default_rehide_ms(),
|
||||||
|
start_minimized: default_start_minimized(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub async fn load(pool: &SqlitePool) -> Result<AppConfig, SetupError> {
|
||||||
|
let res = sqlx::query!("SELECT * from config where name = 'main'")
|
||||||
|
.fetch_optional(pool)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
let row = match res {
|
||||||
|
Some(row) => row,
|
||||||
|
None => return Ok(AppConfig::default()),
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(serde_json::from_str(&row.data)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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("."));
|
||||||
|
|
||||||
|
parent.push("creddy.db");
|
||||||
|
parent
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn default_listen_port() -> u16 {
|
||||||
|
if cfg!(debug_assertions) {
|
||||||
|
12_345
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
19_923
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn default_listen_addr() -> Ipv4Addr { Ipv4Addr::LOCALHOST }
|
||||||
|
|
||||||
|
fn default_rehide_ms() -> u64 { 1000 }
|
||||||
|
|
||||||
|
fn default_start_minimized() -> bool { !cfg!(debug_assertions) } // default to start-minimized in production only
|
||||||
+199
-100
@@ -1,144 +1,243 @@
|
|||||||
use std::fmt::{Display, Formatter};
|
use std::error::Error;
|
||||||
use std::convert::From;
|
use std::convert::AsRef;
|
||||||
use std::str::Utf8Error;
|
use strum_macros::AsRefStr;
|
||||||
|
|
||||||
|
use thiserror::Error as ThisError;
|
||||||
|
|
||||||
|
use aws_sdk_sts::{
|
||||||
|
types::SdkError as AwsSdkError,
|
||||||
|
error::GetSessionTokenError,
|
||||||
|
};
|
||||||
use sqlx::{
|
use sqlx::{
|
||||||
error::Error as SqlxError,
|
error::Error as SqlxError,
|
||||||
migrate::MigrateError,
|
migrate::MigrateError,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use serde::{Serialize, Serializer, ser::SerializeMap};
|
||||||
|
|
||||||
|
|
||||||
|
// pub struct SerializeError<E> {
|
||||||
|
// pub err: E,
|
||||||
|
// }
|
||||||
|
|
||||||
|
// impl<E: std::error::Error> Serialize for SerializeError<E>
|
||||||
|
// {
|
||||||
|
// fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||||
|
// let mut map = serializer.serialize_map(None)?;
|
||||||
|
// map.serialize_entry("msg", &format!("{}", self.err))?;
|
||||||
|
// if let Some(src) = self.err.source() {
|
||||||
|
// let ser_src = SerializeError { err: src };
|
||||||
|
// map.serialize_entry("source", &ser_src)?;
|
||||||
|
// }
|
||||||
|
// map.end()
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// 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>
|
||||||
|
where
|
||||||
|
E: std::error::Error + AsRef<str>,
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
let mut map = serializer.serialize_map(None)?;
|
||||||
|
map.serialize_entry("code", err.as_ref())?;
|
||||||
|
map.serialize_entry("msg", &format!("{err}"))?;
|
||||||
|
if let Some(src) = err.source() {
|
||||||
|
map.serialize_entry("source", &format!("{src}"))?;
|
||||||
|
}
|
||||||
|
map.end()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn serialize_upstream_err<E, M>(err: &E, map: &mut M) -> Result<(), M::Error>
|
||||||
|
where
|
||||||
|
E: Error,
|
||||||
|
M: serde::ser::SerializeMap,
|
||||||
|
{
|
||||||
|
let src = err.source().map(|s| format!("{s}"));
|
||||||
|
map.serialize_entry("source", &src)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
macro_rules! impl_serialize_basic {
|
||||||
|
($err_type:ident) => {
|
||||||
|
impl Serialize for $err_type {
|
||||||
|
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||||
|
serialize_basic_err(self, serializer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// error during initial setup (primarily loading state from db)
|
// error during initial setup (primarily loading state from db)
|
||||||
|
#[derive(Debug, ThisError, AsRefStr)]
|
||||||
pub enum SetupError {
|
pub enum SetupError {
|
||||||
|
#[error("Invalid database record")]
|
||||||
InvalidRecord, // e.g. wrong size blob for nonce or salt
|
InvalidRecord, // e.g. wrong size blob for nonce or salt
|
||||||
DbError(SqlxError),
|
#[error("Error from database: {0}")]
|
||||||
}
|
DbError(#[from] SqlxError),
|
||||||
impl From<SqlxError> for SetupError {
|
#[error("Error running migrations: {0}")]
|
||||||
fn from(e: SqlxError) -> SetupError {
|
MigrationError(#[from] MigrateError),
|
||||||
SetupError::DbError(e)
|
#[error("Error parsing configuration from database")]
|
||||||
}
|
ConfigParseError(#[from] serde_json::Error),
|
||||||
}
|
|
||||||
impl From<MigrateError> for SetupError {
|
|
||||||
fn from (e: MigrateError) -> SetupError {
|
|
||||||
SetupError::DbError(SqlxError::from(e))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Display for SetupError {
|
|
||||||
fn fmt(&self, f: &mut Formatter) -> Result<(), std::fmt::Error> {
|
|
||||||
match self {
|
|
||||||
SetupError::InvalidRecord => write!(f, "Malformed database record"),
|
|
||||||
SetupError::DbError(e) => write!(f, "Error from database: {e}"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// error when attempting to tell a request handler whether to release or deny crednetials
|
// error when attempting to tell a request handler whether to release or deny credentials
|
||||||
|
#[derive(Debug, ThisError, AsRefStr)]
|
||||||
pub enum SendResponseError {
|
pub enum SendResponseError {
|
||||||
|
#[error("The specified credentials request was not found")]
|
||||||
NotFound, // no request with the given id
|
NotFound, // no request with the given id
|
||||||
|
#[error("The specified request was already closed by the client")]
|
||||||
Abandoned, // request has already been closed by client
|
Abandoned, // request has already been closed by client
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for SendResponseError {
|
|
||||||
fn fmt(&self, f: &mut Formatter) -> Result<(), std::fmt::Error> {
|
|
||||||
use SendResponseError::*;
|
|
||||||
match self {
|
|
||||||
NotFound => write!(f, "The specified command was not found."),
|
|
||||||
Abandoned => write!(f, "The specified request was closed by the client."),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// errors encountered while handling an HTTP request
|
// errors encountered while handling an HTTP request
|
||||||
|
#[derive(Debug, ThisError, AsRefStr)]
|
||||||
pub enum RequestError {
|
pub enum RequestError {
|
||||||
StreamIOError(std::io::Error),
|
#[error("Error writing to stream: {0}")]
|
||||||
InvalidUtf8,
|
StreamIOError(#[from] std::io::Error),
|
||||||
MalformedHttpRequest,
|
// #[error("Received invalid UTF-8 in request")]
|
||||||
|
// InvalidUtf8,
|
||||||
|
// MalformedHttpRequest,
|
||||||
|
#[error("HTTP request too large")]
|
||||||
RequestTooLarge,
|
RequestTooLarge,
|
||||||
NoCredentials(GetCredentialsError),
|
#[error("Error accessing credentials: {0}")]
|
||||||
ClientInfo(ClientInfoError),
|
NoCredentials(#[from] GetCredentialsError),
|
||||||
}
|
#[error("Error getting client details: {0}")]
|
||||||
impl From<tokio::io::Error> for RequestError {
|
ClientInfo(#[from] ClientInfoError),
|
||||||
fn from(e: std::io::Error) -> RequestError {
|
#[error("Error from Tauri: {0}")]
|
||||||
RequestError::StreamIOError(e)
|
Tauri(#[from] tauri::Error),
|
||||||
}
|
#[error("No main application window found")]
|
||||||
}
|
NoMainWindow,
|
||||||
impl From<Utf8Error> for RequestError {
|
|
||||||
fn from(_e: Utf8Error) -> RequestError {
|
|
||||||
RequestError::InvalidUtf8
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl From<GetCredentialsError> for RequestError {
|
|
||||||
fn from (e: GetCredentialsError) -> RequestError {
|
|
||||||
RequestError::NoCredentials(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl From<ClientInfoError> for RequestError {
|
|
||||||
fn from(e: ClientInfoError) -> RequestError {
|
|
||||||
RequestError::ClientInfo(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for RequestError {
|
|
||||||
fn fmt(&self, f: &mut Formatter) -> Result<(), std::fmt::Error> {
|
|
||||||
use RequestError::*;
|
|
||||||
match self {
|
|
||||||
StreamIOError(e) => write!(f, "Stream IO error: {e}"),
|
|
||||||
InvalidUtf8 => write!(f, "Could not decode UTF-8 from bytestream"),
|
|
||||||
MalformedHttpRequest => write!(f, "Maformed HTTP request"),
|
|
||||||
RequestTooLarge => write!(f, "HTTP request too large"),
|
|
||||||
NoCredentials(GetCredentialsError::Locked) => write!(f, "Recieved go-ahead but app is locked"),
|
|
||||||
NoCredentials(GetCredentialsError::Empty) => write!(f, "Received go-ahead but no credentials are known"),
|
|
||||||
ClientInfo(ClientInfoError::PidNotFound) => write!(f, "Could not resolve PID of client process."),
|
|
||||||
ClientInfo(ClientInfoError::NetstatError(e)) => write!(f, "Error getting client socket details: {e}"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Debug, ThisError, AsRefStr)]
|
||||||
pub enum GetCredentialsError {
|
pub enum GetCredentialsError {
|
||||||
|
#[error("Credentials are currently locked")]
|
||||||
Locked,
|
Locked,
|
||||||
|
#[error("No credentials are known")]
|
||||||
Empty,
|
Empty,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Debug, ThisError, AsRefStr)]
|
||||||
|
pub enum GetSessionError {
|
||||||
|
#[error("Request completed successfully but no credentials were returned")]
|
||||||
|
NoCredentials, // SDK returned successfully but credentials are None
|
||||||
|
#[error("Error response from AWS SDK: {0}")]
|
||||||
|
SdkError(#[from] AwsSdkError<GetSessionTokenError>),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Debug, ThisError, AsRefStr)]
|
||||||
pub enum UnlockError {
|
pub enum UnlockError {
|
||||||
|
#[error("App is not locked")]
|
||||||
NotLocked,
|
NotLocked,
|
||||||
|
#[error("No saved credentials were found")]
|
||||||
NoCredentials,
|
NoCredentials,
|
||||||
|
#[error("Invalid passphrase")]
|
||||||
BadPassphrase,
|
BadPassphrase,
|
||||||
|
#[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
|
||||||
DbError(SqlxError),
|
#[error("Database error: {0}")]
|
||||||
}
|
DbError(#[from] SqlxError),
|
||||||
impl From<SqlxError> for UnlockError {
|
#[error("Failed to create AWS session: {0}")]
|
||||||
fn from (e: SqlxError) -> UnlockError {
|
GetSession(#[from] GetSessionError),
|
||||||
match e {
|
|
||||||
SqlxError::RowNotFound => UnlockError::NoCredentials,
|
|
||||||
_ => UnlockError::DbError(e),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Display for UnlockError {
|
|
||||||
fn fmt(&self, f: &mut Formatter) -> Result<(), std::fmt::Error> {
|
|
||||||
use UnlockError::*;
|
|
||||||
match self {
|
|
||||||
NotLocked => write!(f, "App is not locked"),
|
|
||||||
NoCredentials => write!(f, "No saved credentials were found"),
|
|
||||||
BadPassphrase => write!(f, "Invalid passphrase"),
|
|
||||||
InvalidUtf8 => write!(f, "Decrypted data was corrupted"),
|
|
||||||
DbError(e) => write!(f, "Database error: {e}"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 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)]
|
||||||
pub enum ClientInfoError {
|
pub enum ClientInfoError {
|
||||||
PidNotFound,
|
#[error("Found PID for client socket, but no corresponding process")]
|
||||||
NetstatError(netstat2::error::Error),
|
ProcessNotFound,
|
||||||
|
#[error("Couldn't get client socket details: {0}")]
|
||||||
|
NetstatError(#[from] netstat2::error::Error),
|
||||||
}
|
}
|
||||||
impl From<netstat2::error::Error> for ClientInfoError {
|
|
||||||
fn from(e: netstat2::error::Error) -> ClientInfoError {
|
|
||||||
ClientInfoError::NetstatError(e)
|
// =========================
|
||||||
|
// Serialize implementations
|
||||||
|
// =========================
|
||||||
|
|
||||||
|
|
||||||
|
struct SerializeWrapper<E>(pub E);
|
||||||
|
|
||||||
|
impl Serialize for SerializeWrapper<&GetSessionTokenError> {
|
||||||
|
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||||
|
let err = self.0;
|
||||||
|
let mut map = serializer.serialize_map(None)?;
|
||||||
|
map.serialize_entry("code", &err.code())?;
|
||||||
|
map.serialize_entry("msg", &err.message())?;
|
||||||
|
map.serialize_entry("source", &None::<&str>)?;
|
||||||
|
map.end()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
impl_serialize_basic!(SetupError);
|
||||||
|
impl_serialize_basic!(SendResponseError);
|
||||||
|
impl_serialize_basic!(GetCredentialsError);
|
||||||
|
impl_serialize_basic!(ClientInfoError);
|
||||||
|
|
||||||
|
|
||||||
|
impl Serialize for RequestError {
|
||||||
|
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 {
|
||||||
|
RequestError::NoCredentials(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 GetSessionError {
|
||||||
|
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 {
|
||||||
|
GetSessionError::SdkError(AwsSdkError::ServiceError(se_wrapper)) => {
|
||||||
|
let err = se_wrapper.err();
|
||||||
|
map.serialize_entry("source", &SerializeWrapper(err))?
|
||||||
|
}
|
||||||
|
_ => serialize_upstream_err(self, &mut map)?,
|
||||||
|
}
|
||||||
|
|
||||||
|
map.end()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl Serialize for UnlockError {
|
||||||
|
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 {
|
||||||
|
UnlockError::GetSession(src) => map.serialize_entry("source", &src)?,
|
||||||
|
_ => serialize_upstream_err(self, &mut map)?,
|
||||||
|
}
|
||||||
|
map.end()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+25
-19
@@ -1,31 +1,27 @@
|
|||||||
use serde::{Serialize, Deserialize};
|
use serde::{Serialize, Deserialize};
|
||||||
use tauri::State;
|
use tauri::State;
|
||||||
|
|
||||||
|
use crate::errors::*;
|
||||||
|
use crate::config::AppConfig;
|
||||||
|
use crate::clientinfo::Client;
|
||||||
use crate::state::{AppState, Session, Credentials};
|
use crate::state::{AppState, Session, Credentials};
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
pub struct Client {
|
|
||||||
pub pid: u32,
|
|
||||||
pub exe: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone, Serialize, Deserialize)]
|
|
||||||
pub struct Request {
|
pub struct Request {
|
||||||
pub id: u64,
|
pub id: u64,
|
||||||
pub clients: Vec<Client>,
|
pub clients: Vec<Option<Client>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
pub struct RequestResponse {
|
pub struct RequestResponse {
|
||||||
pub id: u64,
|
pub id: u64,
|
||||||
pub approval: Approval,
|
pub approval: Approval,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
pub enum Approval {
|
pub enum Approval {
|
||||||
Approved,
|
Approved,
|
||||||
Denied,
|
Denied,
|
||||||
@@ -40,10 +36,8 @@ pub fn respond(response: RequestResponse, app_state: State<'_, AppState>) -> Res
|
|||||||
|
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn unlock(passphrase: String, app_state: State<'_, AppState>) -> Result<(), String> {
|
pub async fn unlock(passphrase: String, app_state: State<'_, AppState>) -> Result<(), UnlockError> {
|
||||||
app_state.decrypt(&passphrase)
|
app_state.decrypt(&passphrase).await
|
||||||
.await
|
|
||||||
.map_err(|e| e.to_string())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -63,8 +57,20 @@ pub async fn save_credentials(
|
|||||||
credentials: Credentials,
|
credentials: Credentials,
|
||||||
passphrase: String,
|
passphrase: String,
|
||||||
app_state: State<'_, AppState>
|
app_state: State<'_, AppState>
|
||||||
) -> Result<(), String> {
|
) -> Result<(), UnlockError> {
|
||||||
app_state.save_creds(credentials, &passphrase)
|
app_state.save_creds(credentials, &passphrase).await
|
||||||
.await
|
}
|
||||||
.map_err(|e| e.to_string())
|
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
pub fn get_config(app_state: State<'_, AppState>) -> AppConfig {
|
||||||
|
let config = app_state.config.read().unwrap();
|
||||||
|
config.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
pub fn save_config(config: AppConfig, app_state: State<'_, AppState>) {
|
||||||
|
let mut prev_config = app_state.config.write().unwrap();
|
||||||
|
*prev_config = config;
|
||||||
}
|
}
|
||||||
+70
-6
@@ -3,35 +3,99 @@
|
|||||||
windows_subsystem = "windows"
|
windows_subsystem = "windows"
|
||||||
)]
|
)]
|
||||||
|
|
||||||
use std::str::FromStr;
|
use tauri::{AppHandle, Manager, async_runtime as rt};
|
||||||
|
use once_cell::sync::OnceCell;
|
||||||
|
|
||||||
|
mod config;
|
||||||
mod errors;
|
mod errors;
|
||||||
mod clientinfo;
|
mod clientinfo;
|
||||||
mod ipc;
|
mod ipc;
|
||||||
mod state;
|
mod state;
|
||||||
mod server;
|
mod server;
|
||||||
mod storage;
|
mod tray;
|
||||||
|
|
||||||
|
use crate::errors::*;
|
||||||
|
use state::AppState;
|
||||||
|
|
||||||
|
|
||||||
|
pub static APP: OnceCell<AppHandle> = OnceCell::new();
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let initial_state = match state::AppState::new() {
|
let initial_state = match rt::block_on(state::AppState::load()) {
|
||||||
Ok(state) => state,
|
Ok(state) => state,
|
||||||
Err(e) => {eprintln!("{}", e); return;}
|
Err(e) => {eprintln!("{}", e); return;}
|
||||||
};
|
};
|
||||||
|
|
||||||
tauri::Builder::default()
|
tauri::Builder::default()
|
||||||
.manage(initial_state)
|
.manage(initial_state)
|
||||||
|
.system_tray(tray::create())
|
||||||
|
.on_system_tray_event(tray::handle_event)
|
||||||
.invoke_handler(tauri::generate_handler![
|
.invoke_handler(tauri::generate_handler![
|
||||||
ipc::unlock,
|
ipc::unlock,
|
||||||
ipc::respond,
|
ipc::respond,
|
||||||
ipc::get_session_status,
|
ipc::get_session_status,
|
||||||
ipc::save_credentials,
|
ipc::save_credentials,
|
||||||
|
ipc::get_config,
|
||||||
|
ipc::save_config,
|
||||||
])
|
])
|
||||||
.setup(|app| {
|
.setup(|app| {
|
||||||
let addr = std::net::SocketAddrV4::from_str("127.0.0.1:12345").unwrap();
|
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()));
|
tauri::async_runtime::spawn(server::serve(addr, app.handle()));
|
||||||
|
|
||||||
|
if !config.start_minimized {
|
||||||
|
app.get_window("main")
|
||||||
|
.ok_or(RequestError::NoMainWindow)?
|
||||||
|
.show()?;
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
.run(tauri::generate_context!())
|
.build(tauri::generate_context!())
|
||||||
.expect("error while running tauri application");
|
.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;
|
||||||
+153
-74
@@ -1,28 +1,172 @@
|
|||||||
|
use core::time::Duration;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::net::SocketAddrV4;
|
use std::net::{SocketAddr, SocketAddrV4};
|
||||||
use tokio::net::{TcpListener, TcpStream};
|
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 tauri::{AppHandle, Manager};
|
use tauri::{AppHandle, Manager};
|
||||||
|
|
||||||
use crate::clientinfo;
|
use crate::{clientinfo, clientinfo::Client};
|
||||||
use crate::errors::RequestError;
|
use crate::errors::*;
|
||||||
use crate::ipc::{Request, Approval};
|
use crate::ipc::{Request, Approval};
|
||||||
|
use crate::state::AppState;
|
||||||
|
|
||||||
|
|
||||||
|
struct Handler {
|
||||||
|
request_id: u64,
|
||||||
|
stream: TcpStream,
|
||||||
|
receiver: Option<oneshot::Receiver<Approval>>,
|
||||||
|
app: AppHandle,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Handler {
|
||||||
|
fn new(stream: TcpStream, app: AppHandle) -> Self {
|
||||||
|
let state = app.state::<AppState>();
|
||||||
|
let (chan_send, chan_recv) = oneshot::channel();
|
||||||
|
let request_id = state.register_request(chan_send);
|
||||||
|
Handler {
|
||||||
|
request_id,
|
||||||
|
stream,
|
||||||
|
receiver: Some(chan_recv),
|
||||||
|
app
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn handle(mut self) {
|
||||||
|
if let Err(e) = self.try_handle().await {
|
||||||
|
eprintln!("{e}");
|
||||||
|
}
|
||||||
|
let state = self.app.state::<AppState>();
|
||||||
|
state.unregister_request(self.request_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn try_handle(&mut self) -> Result<(), RequestError> {
|
||||||
|
let _ = self.recv_request().await?;
|
||||||
|
let clients = self.get_clients()?;
|
||||||
|
if self.includes_banned(&clients) {
|
||||||
|
self.stream.write(b"HTTP/1.0 403 Access Denied\r\n\r\n").await?;
|
||||||
|
return Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
let req = Request {id: self.request_id, clients};
|
||||||
|
self.app.emit_all("credentials-request", &req)?;
|
||||||
|
let starting_visibility = self.show_window()?;
|
||||||
|
|
||||||
|
match self.wait_for_response().await? {
|
||||||
|
Approval::Approved => self.send_credentials().await?,
|
||||||
|
Approval::Denied => {
|
||||||
|
let state = self.app.state::<AppState>();
|
||||||
|
for client in req.clients {
|
||||||
|
state.add_ban(client, self.app.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// only hide the window if a) it was hidden to start with
|
||||||
|
// and b) there are no other pending requests
|
||||||
|
let state = self.app.state::<AppState>();
|
||||||
|
let delay = {
|
||||||
|
let config = state.config.read().unwrap();
|
||||||
|
Duration::from_millis(config.rehide_ms)
|
||||||
|
};
|
||||||
|
sleep(delay).await;
|
||||||
|
|
||||||
|
if !starting_visibility && state.req_count() == 0 {
|
||||||
|
let window = self.app.get_window("main").ok_or(RequestError::NoMainWindow)?;
|
||||||
|
window.hide()?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
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 n = 0;
|
||||||
|
loop {
|
||||||
|
n += self.stream.read(&mut buf[n..]).await?;
|
||||||
|
if n >= 4 && &buf[(n - 4)..n] == b"\r\n\r\n" {break;}
|
||||||
|
if n == buf.len() {return Err(RequestError::RequestTooLarge);}
|
||||||
|
}
|
||||||
|
|
||||||
|
if cfg!(debug_assertions) {
|
||||||
|
println!("{}", std::str::from_utf8(&buf).unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_clients(&self) -> Result<Vec<Option<Client>>, RequestError> {
|
||||||
|
let peer_addr = match self.stream.peer_addr()? {
|
||||||
|
SocketAddr::V4(addr) => addr,
|
||||||
|
_ => unreachable!(), // we only listen on IPv4
|
||||||
|
};
|
||||||
|
let clients = clientinfo::get_clients(peer_addr.port())?;
|
||||||
|
Ok(clients)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn includes_banned(&self, clients: &Vec<Option<Client>>) -> bool {
|
||||||
|
let state = self.app.state::<AppState>();
|
||||||
|
clients.iter().any(|c| state.is_banned(c))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn show_window(&self) -> Result<bool, RequestError> {
|
||||||
|
let window = self.app.get_window("main").ok_or(RequestError::NoMainWindow)?;
|
||||||
|
let starting_visibility = window.is_visible()?;
|
||||||
|
if !starting_visibility {
|
||||||
|
window.unminimize()?;
|
||||||
|
window.show()?;
|
||||||
|
}
|
||||||
|
window.set_focus()?;
|
||||||
|
Ok(starting_visibility)
|
||||||
|
}
|
||||||
|
|
||||||
|
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"Content-Type: application/json\r\n").await?;
|
||||||
|
self.stream.write(b"X-Creddy-delaying-tactic: ").await?;
|
||||||
|
|
||||||
|
#[allow(unreachable_code)] // seems necessary for type inference
|
||||||
|
let stall = async {
|
||||||
|
let delay = std::time::Duration::from_secs(1);
|
||||||
|
loop {
|
||||||
|
tokio::time::sleep(delay).await;
|
||||||
|
self.stream.write(b"x").await?;
|
||||||
|
}
|
||||||
|
Ok(Approval::Denied)
|
||||||
|
};
|
||||||
|
|
||||||
|
// this is the only place we even read this field, so it's safe to unwrap
|
||||||
|
let receiver = self.receiver.take().unwrap();
|
||||||
|
tokio::select!{
|
||||||
|
r = receiver => Ok(r.unwrap()), // only panics if the sender is dropped without sending, which shouldn't be possible
|
||||||
|
e = stall => e,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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(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?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
pub async fn serve(addr: SocketAddrV4, app_handle: AppHandle) -> io::Result<()> {
|
pub async fn serve(addr: SocketAddrV4, app_handle: AppHandle) -> io::Result<()> {
|
||||||
let listener = TcpListener::bind(&addr).await?;
|
let listener = TcpListener::bind(&addr).await?;
|
||||||
println!("Listening on {addr}");
|
println!("Listening on {addr}");
|
||||||
loop {
|
loop {
|
||||||
let new_handle = app_handle.app_handle();
|
|
||||||
match listener.accept().await {
|
match listener.accept().await {
|
||||||
Ok((stream, _)) => {
|
Ok((stream, _)) => {
|
||||||
tokio::spawn(async {
|
let handler = Handler::new(stream, app_handle.app_handle());
|
||||||
if let Err(e) = handle(stream, new_handle).await {
|
tauri::async_runtime::spawn(handler.handle());
|
||||||
eprintln!("{e}");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
eprintln!("Error accepting connection: {e}");
|
eprintln!("Error accepting connection: {e}");
|
||||||
@@ -30,68 +174,3 @@ pub async fn serve(addr: SocketAddrV4, app_handle: AppHandle) -> io::Result<()>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// it doesn't really return Approval, we just need to placate the compiler
|
|
||||||
async fn stall(stream: &mut TcpStream) -> Result<Approval, tokio::io::Error> {
|
|
||||||
let delay = std::time::Duration::from_secs(1);
|
|
||||||
loop {
|
|
||||||
tokio::time::sleep(delay).await;
|
|
||||||
stream.write(b"x").await?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
async fn handle(mut stream: TcpStream, app_handle: AppHandle) -> Result<(), RequestError> {
|
|
||||||
let (chan_send, chan_recv) = oneshot::channel();
|
|
||||||
let app_state = app_handle.state::<crate::state::AppState>();
|
|
||||||
let request_id = app_state.register_request(chan_send);
|
|
||||||
|
|
||||||
let peer_addr = match stream.peer_addr()? {
|
|
||||||
std::net::SocketAddr::V4(addr) => addr,
|
|
||||||
_ => unreachable!(), // we only listen on IPv4
|
|
||||||
};
|
|
||||||
let clients = clientinfo::get_clients(peer_addr.port())?;
|
|
||||||
|
|
||||||
// Do we want to panic if this fails? Does that mean the frontend is dead?
|
|
||||||
let req = Request {id: request_id, clients};
|
|
||||||
app_handle.emit_all("credentials-request", req).unwrap();
|
|
||||||
|
|
||||||
let mut buf = [0; 8192]; // it's what tokio's BufReader uses
|
|
||||||
let mut n = 0;
|
|
||||||
loop {
|
|
||||||
n += stream.read(&mut buf[n..]).await?;
|
|
||||||
if &buf[(n - 4)..n] == b"\r\n\r\n" {break;}
|
|
||||||
if n == buf.len() {return Err(RequestError::RequestTooLarge);}
|
|
||||||
}
|
|
||||||
|
|
||||||
println!("{}", std::str::from_utf8(&buf).unwrap());
|
|
||||||
|
|
||||||
stream.write(b"HTTP/1.0 200 OK\r\n").await?;
|
|
||||||
stream.write(b"Content-Type: application/json\r\n").await?;
|
|
||||||
stream.write(b"X-Creddy-delaying-tactic: ").await?;
|
|
||||||
|
|
||||||
let approval = tokio::select!{
|
|
||||||
e = stall(&mut stream) => e?, // this will never return Ok, just Err if it can't write to the stream
|
|
||||||
r = chan_recv => r.unwrap(), // only panics if the sender is dropped without sending, which shouldn't happen
|
|
||||||
};
|
|
||||||
|
|
||||||
if matches!(approval, Approval::Denied) {
|
|
||||||
// because we own the stream, it gets closed when we return.
|
|
||||||
// Unfortunately we've already signaled 200 OK, there's no way around this -
|
|
||||||
// we have to write the status code first thing, and we have to assume that the user
|
|
||||||
// might need more time than that gives us (especially if entering the passphrase).
|
|
||||||
// Fortunately most AWS libs automatically retry if the request dies uncompleted, allowing
|
|
||||||
// us to respond with a proper error status.
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
|
|
||||||
let creds = app_state.get_creds_serialized()?;
|
|
||||||
|
|
||||||
stream.write(b"\r\nContent-Length: ").await?;
|
|
||||||
stream.write(creds.as_bytes().len().to_string().as_bytes()).await?;
|
|
||||||
stream.write(b"\r\n\r\n").await?;
|
|
||||||
stream.write(creds.as_bytes()).await?;
|
|
||||||
stream.write(b"\r\n\r\n").await?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
+121
-30
@@ -1,8 +1,10 @@
|
|||||||
use std::collections::HashMap;
|
use core::time::Duration;
|
||||||
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::sync::RwLock;
|
use std::sync::RwLock;
|
||||||
|
|
||||||
use serde::{Serialize, Deserialize};
|
use serde::{Serialize, Deserialize};
|
||||||
use tokio::sync::oneshot::Sender;
|
use tokio::sync::oneshot::Sender;
|
||||||
|
use tokio::time::sleep;
|
||||||
use sqlx::{SqlitePool, sqlite::SqlitePoolOptions, sqlite::SqliteConnectOptions};
|
use sqlx::{SqlitePool, sqlite::SqlitePoolOptions, sqlite::SqliteConnectOptions};
|
||||||
use sodiumoxide::crypto::{
|
use sodiumoxide::crypto::{
|
||||||
pwhash,
|
pwhash,
|
||||||
@@ -11,12 +13,15 @@ use sodiumoxide::crypto::{
|
|||||||
secretbox::{Nonce, Key}
|
secretbox::{Nonce, Key}
|
||||||
};
|
};
|
||||||
use tauri::async_runtime as runtime;
|
use tauri::async_runtime as runtime;
|
||||||
|
use tauri::Manager;
|
||||||
|
|
||||||
|
use crate::{config, config::AppConfig};
|
||||||
use crate::ipc;
|
use crate::ipc;
|
||||||
|
use crate::clientinfo::Client;
|
||||||
use crate::errors::*;
|
use crate::errors::*;
|
||||||
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
#[serde(untagged)]
|
#[serde(untagged)]
|
||||||
pub enum Credentials {
|
pub enum Credentials {
|
||||||
#[serde(rename_all = "PascalCase")]
|
#[serde(rename_all = "PascalCase")]
|
||||||
@@ -34,6 +39,7 @@ pub enum Credentials {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct LockedCredentials {
|
pub struct LockedCredentials {
|
||||||
access_key_id: String,
|
access_key_id: String,
|
||||||
secret_key_enc: Vec<u8>,
|
secret_key_enc: Vec<u8>,
|
||||||
@@ -42,6 +48,7 @@ pub struct LockedCredentials {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub enum Session {
|
pub enum Session {
|
||||||
Unlocked(Credentials),
|
Unlocked(Credentials),
|
||||||
Locked(LockedCredentials),
|
Locked(LockedCredentials),
|
||||||
@@ -49,36 +56,34 @@ pub enum Session {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// #[derive(Serialize, Deserialize)]
|
#[derive(Debug)]
|
||||||
// pub enum SessionStatus {
|
|
||||||
// Unlocked,
|
|
||||||
// Locked,
|
|
||||||
// Empty,
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
pub struct AppState {
|
pub struct AppState {
|
||||||
|
pub config: RwLock<AppConfig>,
|
||||||
pub session: RwLock<Session>,
|
pub session: RwLock<Session>,
|
||||||
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>>>,
|
||||||
pool: SqlitePool,
|
pool: SqlitePool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AppState {
|
impl AppState {
|
||||||
pub fn new() -> Result<Self, SetupError> {
|
pub async fn load() -> Result<Self, SetupError> {
|
||||||
let conn_opts = SqliteConnectOptions::new()
|
let conn_opts = SqliteConnectOptions::new()
|
||||||
.filename("creddy.db")
|
.filename(config::get_or_create_db_path())
|
||||||
.create_if_missing(true);
|
.create_if_missing(true);
|
||||||
let pool_opts = SqlitePoolOptions::new();
|
let pool_opts = SqlitePoolOptions::new();
|
||||||
|
|
||||||
let pool: SqlitePool = runtime::block_on(pool_opts.connect_with(conn_opts))?;
|
let pool: SqlitePool = pool_opts.connect_with(conn_opts).await?;
|
||||||
runtime::block_on(sqlx::migrate!().run(&pool))?;
|
sqlx::migrate!().run(&pool).await?;
|
||||||
let creds = runtime::block_on(Self::load_creds(&pool))?;
|
let creds = Self::load_creds(&pool).await?;
|
||||||
|
let conf = config::load(&pool).await?;
|
||||||
|
|
||||||
let state = AppState {
|
let state = AppState {
|
||||||
|
config: RwLock::new(conf),
|
||||||
session: RwLock::new(creds),
|
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()),
|
||||||
pool,
|
pool,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -86,7 +91,7 @@ impl AppState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn load_creds(pool: &SqlitePool) -> Result<Session, SetupError> {
|
async fn load_creds(pool: &SqlitePool) -> Result<Session, SetupError> {
|
||||||
let res = sqlx::query!("SELECT * FROM credentials")
|
let res = sqlx::query!("SELECT * FROM credentials ORDER BY created_at desc")
|
||||||
.fetch_optional(pool)
|
.fetch_optional(pool)
|
||||||
.await?;
|
.await?;
|
||||||
let row = match res {
|
let row = match res {
|
||||||
@@ -110,13 +115,17 @@ impl AppState {
|
|||||||
Ok(Session::Locked(creds))
|
Ok(Session::Locked(creds))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn save_creds(&self, creds: Credentials, passphrase: &str) -> Result<(), sqlx::error::Error> {
|
pub async fn save_creds(&self, creds: Credentials, passphrase: &str) -> Result<(), UnlockError> {
|
||||||
let (key_id, secret_key) = match creds {
|
let (key_id, secret_key) = match creds {
|
||||||
Credentials::LongLived {access_key_id, secret_access_key} => {
|
Credentials::LongLived {access_key_id, secret_access_key} => {
|
||||||
(access_key_id, secret_access_key)
|
(access_key_id, secret_access_key)
|
||||||
},
|
},
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// do this first so that if it fails we don't save bad credentials
|
||||||
|
self.new_session(&key_id, &secret_key).await?;
|
||||||
|
|
||||||
let salt = pwhash::gen_salt();
|
let salt = pwhash::gen_salt();
|
||||||
let mut key_buf = [0; secretbox::KEYBYTES];
|
let mut key_buf = [0; secretbox::KEYBYTES];
|
||||||
pwhash::derive_key_interactive(&mut key_buf, passphrase.as_bytes(), &salt).unwrap();
|
pwhash::derive_key_interactive(&mut key_buf, passphrase.as_bytes(), &salt).unwrap();
|
||||||
@@ -124,16 +133,19 @@ impl AppState {
|
|||||||
// not sure we need both salt AND nonce given that we generate a
|
// not sure we need both salt AND nonce given that we generate a
|
||||||
// fresh salt every time we encrypt, but better safe than sorry
|
// fresh salt every time we encrypt, but better safe than sorry
|
||||||
let nonce = secretbox::gen_nonce();
|
let nonce = secretbox::gen_nonce();
|
||||||
let key_enc = secretbox::seal(secret_key.as_bytes(), &nonce, &key);
|
let secret_key_enc = secretbox::seal(secret_key.as_bytes(), &nonce, &key);
|
||||||
|
|
||||||
// insert into database
|
|
||||||
|
|
||||||
// eventually replace this with a temporary session
|
sqlx::query(
|
||||||
let mut session = self.session.write().unwrap();
|
"INSERT INTO credentials (access_key_id, secret_key_enc, salt, nonce, created_at)
|
||||||
*session = Session::Unlocked(Credentials::LongLived {
|
VALUES (?, ?, ?, ?, strftime('%s'))"
|
||||||
access_key_id: key_id,
|
)
|
||||||
secret_access_key: secret_key,
|
.bind(&key_id)
|
||||||
});
|
.bind(&secret_key_enc)
|
||||||
|
.bind(&salt.0[0..])
|
||||||
|
.bind(&nonce.0[0..])
|
||||||
|
.execute(&self.pool)
|
||||||
|
.await?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -150,6 +162,16 @@ impl AppState {
|
|||||||
*count
|
*count
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn unregister_request(&self, id: u64) {
|
||||||
|
let mut open_requests = self.open_requests.write().unwrap();
|
||||||
|
open_requests.remove(&id);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn req_count(&self) -> usize {
|
||||||
|
let open_requests = self.open_requests.read().unwrap();
|
||||||
|
open_requests.len()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn send_response(&self, response: ipc::RequestResponse) -> Result<(), SendResponseError> {
|
pub fn send_response(&self, response: ipc::RequestResponse) -> Result<(), SendResponseError> {
|
||||||
let mut open_requests = self.open_requests.write().unwrap();
|
let mut open_requests = self.open_requests.write().unwrap();
|
||||||
let chan = open_requests
|
let chan = open_requests
|
||||||
@@ -161,7 +183,25 @@ impl AppState {
|
|||||||
.map_err(|_e| SendResponseError::Abandoned)
|
.map_err(|_e| SendResponseError::Abandoned)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn add_ban(&self, client: Option<Client>, app: tauri::AppHandle) {
|
||||||
|
let mut bans = self.bans.write().unwrap();
|
||||||
|
bans.insert(client.clone());
|
||||||
|
|
||||||
|
runtime::spawn(async move {
|
||||||
|
sleep(Duration::from_secs(5)).await;
|
||||||
|
let state = app.state::<AppState>();
|
||||||
|
let mut bans = state.bans.write().unwrap();
|
||||||
|
bans.remove(&client);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_banned(&self, client: &Option<Client>) -> bool {
|
||||||
|
self.bans.read().unwrap().contains(&client)
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn decrypt(&self, passphrase: &str) -> Result<(), UnlockError> {
|
pub async fn decrypt(&self, passphrase: &str) -> Result<(), UnlockError> {
|
||||||
|
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 session = self.session.read().unwrap();
|
||||||
let locked = match *session {
|
let locked = match *session {
|
||||||
Session::Empty => {return Err(UnlockError::NoCredentials);},
|
Session::Empty => {return Err(UnlockError::NoCredentials);},
|
||||||
@@ -176,12 +216,11 @@ impl AppState {
|
|||||||
.map_err(|_e| UnlockError::BadPassphrase)?;
|
.map_err(|_e| UnlockError::BadPassphrase)?;
|
||||||
|
|
||||||
let secret_str = String::from_utf8(decrypted).map_err(|_e| UnlockError::InvalidUtf8)?;
|
let secret_str = String::from_utf8(decrypted).map_err(|_e| UnlockError::InvalidUtf8)?;
|
||||||
let mut session = self.session.write().unwrap();
|
(locked.access_key_id.clone(), secret_str)
|
||||||
let creds = Credentials::LongLived {
|
|
||||||
access_key_id: locked.access_key_id.clone(),
|
|
||||||
secret_access_key: secret_str,
|
|
||||||
};
|
};
|
||||||
*session = Session::Unlocked(creds);
|
|
||||||
|
self.new_session(&key_id, &secret).await?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,4 +232,56 @@ impl AppState {
|
|||||||
Session::Empty => Err(GetCredentialsError::Empty),
|
Session::Empty => Err(GetCredentialsError::Empty),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn new_session(&self, key_id: &str, secret_key: &str) -> Result<(), GetSessionError> {
|
||||||
|
let creds = aws_sdk_sts::Credentials::new(
|
||||||
|
key_id,
|
||||||
|
secret_key,
|
||||||
|
None, // token
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
|
||||||
|
*app_session = Session::Unlocked(session_creds);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
use sodiumoxide::crypto::{pwhash, secretbox};
|
|
||||||
|
|
||||||
use crate::state;
|
|
||||||
|
|
||||||
|
|
||||||
pub fn save(data: &str, passphrase: &str) {
|
|
||||||
let salt = pwhash::Salt([0; 32]); // yes yes, just for now
|
|
||||||
let mut kbuf = [0; secretbox::KEYBYTES];
|
|
||||||
pwhash::derive_key_interactive(&mut kbuf, passphrase.as_bytes(), &salt)
|
|
||||||
.expect("Couldn't compute password hash. Are you out of memory?");
|
|
||||||
let key = secretbox::Key(kbuf);
|
|
||||||
let nonce = secretbox::Nonce([0; 24]); // we don't care about e.g. replay attacks so this might be safe?
|
|
||||||
let encrypted = secretbox::seal(data.as_bytes(), &nonce, &key);
|
|
||||||
|
|
||||||
//todo: store in a database, along with salt, nonce, and hash parameters
|
|
||||||
std::fs::write("credentials.enc", &encrypted).expect("Failed to write file.");
|
|
||||||
|
|
||||||
//todo: key is automatically zeroed, but we should use 'zeroize' or something to zero out passphrase and data
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// pub fn load(passphrase: &str) -> String {
|
|
||||||
// let salt = pwhash::Salt([0; 32]);
|
|
||||||
// let mut kbuf = [0; secretbox::KEYBYTES];
|
|
||||||
// pwhash::derive_key_interactive(&mut kbuf, passphrase.as_bytes(), &salt)
|
|
||||||
// .expect("Couldn't compute password hash. Are you out of memory?");
|
|
||||||
// let key = secretbox::Key(kbuf);
|
|
||||||
// let nonce = secretbox::Nonce([0; 24]);
|
|
||||||
|
|
||||||
// let encrypted = std::fs::read("credentials.enc").expect("Failed to read file.");
|
|
||||||
// let decrypted = secretbox::open(&encrypted, &nonce, &key).expect("Failed to decrypt.");
|
|
||||||
// String::from_utf8(decrypted).expect("Invalid utf-8")
|
|
||||||
// }
|
|
||||||
|
|
||||||
pub fn load(passphrase: &str) -> state::Credentials {
|
|
||||||
state::Credentials::ShortLived {
|
|
||||||
access_key_id: "ASIAZ7WSVLORKQI27QGB".to_string(),
|
|
||||||
secret_access_key: "blah".to_string(),
|
|
||||||
token: "gah".to_string(),
|
|
||||||
expiration: "2022-11-29T10:45:12Z".to_string(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
use tauri::{
|
||||||
|
AppHandle,
|
||||||
|
Manager,
|
||||||
|
SystemTray,
|
||||||
|
SystemTrayEvent,
|
||||||
|
SystemTrayMenu,
|
||||||
|
CustomMenuItem,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
pub fn create() -> SystemTray {
|
||||||
|
let show = CustomMenuItem::new("show".to_string(), "Show");
|
||||||
|
let quit = CustomMenuItem::new("exit".to_string(), "Exit");
|
||||||
|
|
||||||
|
let menu = SystemTrayMenu::new()
|
||||||
|
.add_item(show)
|
||||||
|
.add_item(quit);
|
||||||
|
|
||||||
|
SystemTray::new().with_menu(menu)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub fn handle_event(app: &AppHandle, event: SystemTrayEvent) {
|
||||||
|
match event {
|
||||||
|
SystemTrayEvent::MenuItemClick{ id, .. } => {
|
||||||
|
match id.as_str() {
|
||||||
|
"exit" => app.exit(0),
|
||||||
|
"show" => {
|
||||||
|
let _ = app.get_window("main").map(|w| w.show());
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -29,7 +29,7 @@
|
|||||||
"icons/icon.icns",
|
"icons/icon.icns",
|
||||||
"icons/icon.ico"
|
"icons/icon.ico"
|
||||||
],
|
],
|
||||||
"identifier": "com.tauri.dev",
|
"identifier": "creddy",
|
||||||
"longDescription": "",
|
"longDescription": "",
|
||||||
"macOS": {
|
"macOS": {
|
||||||
"entitlements": null,
|
"entitlements": null,
|
||||||
@@ -58,9 +58,15 @@
|
|||||||
"fullscreen": false,
|
"fullscreen": false,
|
||||||
"height": 600,
|
"height": 600,
|
||||||
"resizable": true,
|
"resizable": true,
|
||||||
|
"label": "main",
|
||||||
"title": "Creddy",
|
"title": "Creddy",
|
||||||
"width": 800
|
"width": 800,
|
||||||
|
"visible": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"systemTray": {
|
||||||
|
"iconPath": "icons/icon.png",
|
||||||
|
"iconAsTemplate": true
|
||||||
}
|
}
|
||||||
]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+12
-27
@@ -1,37 +1,22 @@
|
|||||||
<script>
|
<script>
|
||||||
import { emit, listen } from '@tauri-apps/api/event';
|
import { emit, listen } from '@tauri-apps/api/event';
|
||||||
import queue from './lib/queue.js';
|
|
||||||
|
|
||||||
const VIEWS = import.meta.glob('./views/*.svelte', {eager: true});
|
|
||||||
|
|
||||||
window.emit = emit;
|
|
||||||
window.queue = queue;
|
|
||||||
|
|
||||||
var appState = {
|
|
||||||
currentRequest: null,
|
|
||||||
pendingRequests: queue(),
|
|
||||||
credentialStatus: 'locked',
|
|
||||||
}
|
|
||||||
window.appState = appState;
|
|
||||||
|
|
||||||
|
|
||||||
import { invoke } from '@tauri-apps/api/tauri';
|
import { invoke } from '@tauri-apps/api/tauri';
|
||||||
window.invoke = invoke;
|
|
||||||
|
import { appState } from './lib/state.js';
|
||||||
|
import { navigate, currentView } from './lib/routing.js';
|
||||||
|
|
||||||
|
|
||||||
var currentView = VIEWS['./views/Home.svelte'].default;
|
invoke('get_config').then(config => $appState.config = config);
|
||||||
window.currentView = currentView;
|
|
||||||
window.VIEWS = VIEWS;
|
|
||||||
function navigate(svelteEvent) {
|
|
||||||
const moduleName = `./views/${svelteEvent.detail.target}.svelte`;
|
|
||||||
currentView = VIEWS[moduleName].default;
|
|
||||||
}
|
|
||||||
window.navigate = navigate;
|
|
||||||
|
|
||||||
listen('credentials-request', (tauriEvent) => {
|
listen('credentials-request', (tauriEvent) => {
|
||||||
appState.pendingRequests.put(tauriEvent.payload);
|
$appState.pendingRequests.put(tauriEvent.payload);
|
||||||
console.log('Received request.');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// can't set this in routing.js directly for some reason
|
||||||
|
if (!$currentView) {
|
||||||
|
navigate('Home');
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:component this={currentView} on:navigate={navigate} bind:appState={appState} />
|
|
||||||
|
<svelte:component this="{$currentView}" />
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
export function getRootCause(error) {
|
||||||
|
if (error.source) {
|
||||||
|
return getRootCause(error.source);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import { writable } from 'svelte/store';
|
||||||
|
|
||||||
|
|
||||||
|
const VIEWS = import.meta.glob('../views/*.svelte', {eager: true});
|
||||||
|
export let currentView = writable();
|
||||||
|
|
||||||
|
export function navigate(viewName) {
|
||||||
|
let view = VIEWS[`../views/${viewName}.svelte`].default;
|
||||||
|
currentView.set(view);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getView(viewName) {
|
||||||
|
return VIEWS[`../views/${viewName}.svelte`].default;
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import { writable } from 'svelte/store';
|
||||||
|
|
||||||
|
import queue from './queue.js';
|
||||||
|
|
||||||
|
export let appState = writable({
|
||||||
|
currentRequest: null,
|
||||||
|
pendingRequests: queue(),
|
||||||
|
credentialStatus: 'locked',
|
||||||
|
});
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
<script>
|
||||||
|
import Icon from './Icon.svelte';
|
||||||
|
export let icon = null;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<button>
|
||||||
|
{#if icon}<Icon name={icon} class="w-4 text-gray-200" />{/if}
|
||||||
|
<slot></slot>
|
||||||
|
</button>
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
<script>
|
||||||
|
import { onMount } from 'svelte';
|
||||||
|
import { slide } from 'svelte/transition';
|
||||||
|
|
||||||
|
export let slideDuration = 150;
|
||||||
|
let animationClass = "";
|
||||||
|
|
||||||
|
export function shake() {
|
||||||
|
animationClass = 'shake';
|
||||||
|
window.setTimeout(() => animationClass = "", 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<style>
|
||||||
|
/* animation from https://svelte.dev/repl/e606c27c864045e5a9700691a7417f99?version=3.58.0 */
|
||||||
|
@keyframes shake {
|
||||||
|
0% {
|
||||||
|
transform: translateX(0px);
|
||||||
|
}
|
||||||
|
20% {
|
||||||
|
transform: translateX(10px);
|
||||||
|
}
|
||||||
|
40% {
|
||||||
|
transform: translateX(-10px);
|
||||||
|
}
|
||||||
|
60% {
|
||||||
|
transform: translateX(5px);
|
||||||
|
}
|
||||||
|
80% {
|
||||||
|
transform: translateX(-5px);
|
||||||
|
}
|
||||||
|
90% {
|
||||||
|
transform: translateX(2px);
|
||||||
|
}
|
||||||
|
95% {
|
||||||
|
transform: translateX(-2px);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: translateX(0px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.shake {
|
||||||
|
animation-name: shake;
|
||||||
|
animation-play-state: running;
|
||||||
|
animation-duration: 0.4s;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
|
||||||
|
<div in:slide="{{duration: slideDuration}}" class="alert alert-error shadow-lg {animationClass}">
|
||||||
|
<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>
|
||||||
|
<span>
|
||||||
|
<slot></slot>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{#if $$slots.buttons}
|
||||||
|
<div>
|
||||||
|
<slot name="buttons"></slot>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
<script>
|
||||||
|
const ICONS = import.meta.glob('./icons/*.svelte', {eager: true});
|
||||||
|
|
||||||
|
export let name;
|
||||||
|
let classes = "";
|
||||||
|
export {classes as class};
|
||||||
|
|
||||||
|
let svg = ICONS[`./icons/${name}.svelte`].default;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<svelte:component this={svg} class={classes} />
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
<script>
|
||||||
|
import { navigate, currentView } from '../lib/routing.js';
|
||||||
|
|
||||||
|
export let target;
|
||||||
|
export let hotkey = null;
|
||||||
|
export let ctrl = false
|
||||||
|
export let alt = false;
|
||||||
|
export let shift = false;
|
||||||
|
|
||||||
|
function click() {
|
||||||
|
if (typeof target === 'string') {
|
||||||
|
navigate(target);
|
||||||
|
}
|
||||||
|
else if (typeof target === 'function') {
|
||||||
|
target();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw(`Link target is not a string or a function: ${target}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function handleHotkey(event) {
|
||||||
|
if (!hotkey) return;
|
||||||
|
if (ctrl && !event.ctrlKey) return;
|
||||||
|
if (alt && !event.altKey) return;
|
||||||
|
if (shift && !event.shiftKey) return;
|
||||||
|
|
||||||
|
if (event.code === hotkey) {
|
||||||
|
click();
|
||||||
|
}
|
||||||
|
else if (hotkey === 'Enter' && event.code === 'NumpadEnter') {
|
||||||
|
click();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<svelte:window on:keydown={handleHotkey} />
|
||||||
|
|
||||||
|
<a href="#" on:click="{click}">
|
||||||
|
<slot></slot>
|
||||||
|
</a>
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
<script>
|
||||||
|
import Link from './Link.svelte';
|
||||||
|
import Icon from './Icon.svelte';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<nav class="fixed top-0 grid grid-cols-2 w-full p-2">
|
||||||
|
<div>
|
||||||
|
<Link target="Home">
|
||||||
|
<button class="btn btn-squre btn-ghost align-middle">
|
||||||
|
<Icon name="home" class="w-8 h-8 stroke-2" />
|
||||||
|
</button>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="justify-self-end">
|
||||||
|
<Link target="Settings">
|
||||||
|
<button class="align-middle btn btn-square btn-ghost">
|
||||||
|
<Icon name="cog-8-tooth" class="w-8 h-8 stroke-2" />
|
||||||
|
</button>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
@@ -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>
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
<script>
|
||||||
|
let classes = "";
|
||||||
|
export {classes as class};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<svg class={classes} fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||||
|
</svg>
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
<script>
|
||||||
|
let classes = "";
|
||||||
|
export {classes as class};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<svg class="w-6 h-6 {classes}" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M10.343 3.94c.09-.542.56-.94 1.11-.94h1.093c.55 0 1.02.398 1.11.94l.149.894c.07.424.384.764.78.93.398.164.855.142 1.205-.108l.737-.527a1.125 1.125 0 011.45.12l.773.774c.39.389.44 1.002.12 1.45l-.527.737c-.25.35-.272.806-.107 1.204.165.397.505.71.93.78l.893.15c.543.09.94.56.94 1.109v1.094c0 .55-.397 1.02-.94 1.11l-.893.149c-.425.07-.765.383-.93.78-.165.398-.143.854.107 1.204l.527.738c.32.447.269 1.06-.12 1.45l-.774.773a1.125 1.125 0 01-1.449.12l-.738-.527c-.35-.25-.806-.272-1.203-.107-.397.165-.71.505-.781.929l-.149.894c-.09.542-.56.94-1.11.94h-1.094c-.55 0-1.019-.398-1.11-.94l-.148-.894c-.071-.424-.384-.764-.781-.93-.398-.164-.854-.142-1.204.108l-.738.527c-.447.32-1.06.269-1.45-.12l-.773-.774a1.125 1.125 0 01-.12-1.45l.527-.737c.25-.35.273-.806.108-1.204-.165-.397-.505-.71-.93-.78l-.894-.15c-.542-.09-.94-.56-.94-1.109v-1.094c0-.55.398-1.02.94-1.11l.894-.149c.424-.07.765-.383.93-.78.165-.398.143-.854-.107-1.204l-.527-.738a1.125 1.125 0 01.12-1.45l.773-.773a1.125 1.125 0 011.45-.12l.737.527c.35.25.807.272 1.204.107.397-.165.71-.505.78-.929l.15-.894z" />
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
|
||||||
|
</svg>
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
<script>
|
||||||
|
let classes = "";
|
||||||
|
export {classes as class};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<svg class="w-6 h-6 {classes}" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M2.25 12l8.954-8.955c.44-.439 1.152-.439 1.591 0L21.75 12M4.5 9.75v10.125c0 .621.504 1.125 1.125 1.125H9.75v-4.875c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125V21h4.125c.621 0 1.125-.504 1.125-1.125V9.75M8.25 21h8.25" />
|
||||||
|
</svg>
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
<script>
|
||||||
|
let classes = "";
|
||||||
|
export {classes as class};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<svg class={classes} fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||||
|
</svg>
|
||||||
+39
-19
@@ -1,39 +1,59 @@
|
|||||||
<script>
|
<script>
|
||||||
import { createEventDispatcher } from 'svelte';
|
|
||||||
import { invoke } from '@tauri-apps/api/tauri';
|
import { invoke } from '@tauri-apps/api/tauri';
|
||||||
|
|
||||||
export let appState;
|
import { navigate } from '../lib/routing.js';
|
||||||
|
import { appState } from '../lib/state.js';
|
||||||
|
import Link from '../ui/Link.svelte';
|
||||||
|
import Icon from '../ui/Icon.svelte';
|
||||||
|
|
||||||
const dispatch = createEventDispatcher();
|
|
||||||
|
|
||||||
async function approve() {
|
async function approve() {
|
||||||
let status = await invoke('get_session_status');
|
let status = await invoke('get_session_status');
|
||||||
if (status === 'unlocked') {
|
if (status === 'unlocked') {
|
||||||
dispatch('navigate', {target: 'ShowApproved'});
|
navigate('ShowApproved');
|
||||||
}
|
}
|
||||||
else if (status === 'locked') {
|
else if (status === 'locked') {
|
||||||
dispatch('navigate', {target: 'Unlock'})
|
navigate('Unlock');
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
dispatch('navigate', {target: 'EnterCredentials'});
|
navigate('EnterCredentials');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function deny() {
|
var appName = null;
|
||||||
dispatch('navigate', {target: 'ShowDenied'});
|
if ($appState.currentRequest.clients.length === 1) {
|
||||||
|
let path = $appState.currentRequest.clients[0].exe;
|
||||||
|
let m = path.match(/\/([^/]+?$)|\\([^\\]+?$)/);
|
||||||
|
appName = m[1] || m[2];
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<h2 class="text-3xl text-gray-200">An application would like to access your AWS credentials.</h2>
|
|
||||||
|
|
||||||
<button on:click={approve}>
|
<div class="flex flex-col space-y-4 p-4 m-auto max-w-max h-screen justify-center">
|
||||||
<svg class="w-32 stroke-green-500" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1">
|
<!-- <div class="p-4 rounded-box border-2 border-neutral-content"> -->
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
|
<div class="space-y-1 mb-4">
|
||||||
</svg>
|
<h2 class="text-xl font-bold">{appName ? `"${appName}"` : 'An appplication'} would like to access your AWS credentials.</h2>
|
||||||
</button>
|
{#each $appState.currentRequest.clients as client}
|
||||||
|
<p>Path: {client ? client.exe : 'Unknown'}</p>
|
||||||
|
<p>PID: {client ? client.pid : 'Unknown'}</p>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
|
||||||
<button on:click={deny}>
|
<div class="grid grid-cols-2">
|
||||||
<svg class="w-32 stroke-red-600" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1">
|
<Link target="ShowDenied" hotkey="Escape">
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z" />
|
<button class="btn btn-error justify-self-start">
|
||||||
</svg>
|
Deny
|
||||||
</button>
|
<kbd class="ml-2 normal-case px-1 py-0.5 rounded border border-neutral">Esc</kbd>
|
||||||
|
</button>
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
<Link target="{approve}" hotkey="Enter" shift="{true}">
|
||||||
|
<button class="btn btn-success justify-self-end">
|
||||||
|
Approve
|
||||||
|
<kbd class="ml-2 normal-case px-1 py-0.5 rounded border border-neutral">Shift</kbd>
|
||||||
|
<span class="mx-0.5">+</span>
|
||||||
|
<kbd class="normal-case px-1 py-0.5 rounded border border-neutral">Enter</kbd>
|
||||||
|
</button>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -1,41 +1,62 @@
|
|||||||
<script>
|
<script>
|
||||||
import { onMount, createEventDispatcher } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import { invoke } from '@tauri-apps/api/tauri';
|
import { invoke } from '@tauri-apps/api/tauri';
|
||||||
|
import { getRootCause } from '../lib/errors.js';
|
||||||
|
|
||||||
export let appState;
|
import { appState } from '../lib/state.js';
|
||||||
|
import { navigate } from '../lib/routing.js';
|
||||||
|
import Link from '../ui/Link.svelte';
|
||||||
|
import ErrorAlert from '../ui/ErrorAlert.svelte';
|
||||||
|
|
||||||
const dispatch = createEventDispatcher();
|
|
||||||
|
let errorMsg = null;
|
||||||
|
let alert;
|
||||||
let AccessKeyId, SecretAccessKey, passphrase
|
let AccessKeyId, SecretAccessKey, passphrase
|
||||||
|
|
||||||
async function save() {
|
async function save() {
|
||||||
try {
|
|
||||||
console.log('Saving credentials.');
|
console.log('Saving credentials.');
|
||||||
let credentials = {AccessKeyId, SecretAccessKey};
|
let credentials = {AccessKeyId, SecretAccessKey};
|
||||||
console.log(credentials);
|
|
||||||
|
try {
|
||||||
await invoke('save_credentials', {credentials, passphrase});
|
await invoke('save_credentials', {credentials, passphrase});
|
||||||
if (appState.currentRequest) {
|
if ($appState.currentRequest) {
|
||||||
dispatch('navigate', {target: 'ShowApproved'})
|
navigate('ShowApproved');
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
dispatch('navigate', {target: 'Home'})
|
navigate('Home');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
console.log("Error saving credentials:", e);
|
if (e.code === "GetSession") {
|
||||||
|
let root = getRootCause(e);
|
||||||
|
errorMsg = `Error response from AWS (${root.code}): ${root.msg}`;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
errorMsg = e.msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (alert) {
|
||||||
|
alert.shake();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
<form action="#" on:submit|preventDefault="{save}">
|
|
||||||
<div class="text-gray-200">AWS Access Key ID</div>
|
|
||||||
<input class="text-gray-200 bg-zinc-800" type="text" bind:value="{AccessKeyId}" />
|
|
||||||
|
|
||||||
<div class="text-gray-200">AWS Secret Access Key</div>
|
<form action="#" on:submit|preventDefault="{save}" class="form-control space-y-4 max-w-sm m-auto p-4 h-screen justify-center">
|
||||||
<input class="text-gray-200 bg-zinc-800" type="text" bind:value="{SecretAccessKey}" />
|
<h2 class="text-2xl font-bold text-center">Enter your credentials</h2>
|
||||||
|
|
||||||
<div class="text-gray-200">Passphrase</div>
|
{#if errorMsg}
|
||||||
<input class="text-gray-200 bg-zinc-800" type="text" bind:value="{passphrase}" />
|
<ErrorAlert bind:this="{alert}">{errorMsg}</ErrorAlert>
|
||||||
|
{/if}
|
||||||
|
|
||||||
<input class="text-gray-200" type="submit" />
|
<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="Passphrase" bind:value="{passphrase}" class="input input-bordered" />
|
||||||
|
|
||||||
|
<input type="submit" class="btn btn-primary" />
|
||||||
|
<Link target="Home" hotkey="Escape">
|
||||||
|
<button class="btn btn-sm btn-outline w-full">Cancel</button>
|
||||||
|
</Link>
|
||||||
</form>
|
</form>
|
||||||
+33
-9
@@ -1,18 +1,42 @@
|
|||||||
<script>
|
<script>
|
||||||
import { onMount, createEventDispatcher } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
|
import { invoke } from '@tauri-apps/api/tauri';
|
||||||
|
|
||||||
export let appState;
|
import { appState } from '../lib/state.js';
|
||||||
|
import { navigate } from '../lib/routing.js';
|
||||||
|
import Nav from '../ui/Nav.svelte';
|
||||||
|
import Icon from '../ui/Icon.svelte';
|
||||||
|
import Link from '../ui/Link.svelte';
|
||||||
|
|
||||||
const dispatch = createEventDispatcher();
|
|
||||||
|
|
||||||
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;
|
||||||
console.log('Got credentials request from queue:');
|
navigate('Approve');
|
||||||
console.log(req);
|
|
||||||
dispatch('navigate', {target: 'Approve'});
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<h1 class="text-4xl text-gray-300">Creddy</h1>
|
|
||||||
|
<Nav />
|
||||||
|
|
||||||
|
<div class="flex flex-col h-screen justify-center items-center space-y-4">
|
||||||
|
{#await invoke('get_session_status') then status}
|
||||||
|
{#if status === 'locked'}
|
||||||
|
<img src="/static/padlock-closed.svg" alt="A locked padlock" class="w-32" />
|
||||||
|
<h2 class="text-2xl font-bold">Creddy is locked</h2>
|
||||||
|
<Link target="Unlock">
|
||||||
|
<button class="btn btn-primary">Unlock</button>
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
{:else if status === 'unlocked'}
|
||||||
|
<img src="/static/padlock-open.svg" alt="An unlocked padlock" class="w-24" />
|
||||||
|
<h2 class="text-2xl font-bold">Waiting for requests</h2>
|
||||||
|
|
||||||
|
{:else if status === 'empty'}
|
||||||
|
<Link target="EnterCredentials">
|
||||||
|
<button class="btn btn-primary">Enter Credentials</button>
|
||||||
|
</Link>
|
||||||
|
{/if}
|
||||||
|
{/await}
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
<script>
|
||||||
|
import { invoke } from '@tauri-apps/api/tauri';
|
||||||
|
window.invoke = invoke;
|
||||||
|
|
||||||
|
import { appState } from '../lib/state.js';
|
||||||
|
import Nav from '../ui/Nav.svelte';
|
||||||
|
import Link from '../ui/Link.svelte';
|
||||||
|
import Setting from '../ui/Setting.svelte';
|
||||||
|
import ErrorAlert from '../ui/ErrorAlert.svelte';
|
||||||
|
|
||||||
|
async function save() {
|
||||||
|
try {
|
||||||
|
await invoke('save_config', {config: $appState.config});
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<Nav />
|
||||||
|
|
||||||
|
{#await invoke('get_config') then config}
|
||||||
|
<div class="mx-auto mt-3 max-w-md">
|
||||||
|
<h2 class="text-2xl font-bold text-center">Settings</h2>
|
||||||
|
|
||||||
|
<Setting title="Start minimized">
|
||||||
|
<input slot="input" type="checkbox" bind:checked="{$appState.config.start_minimized}" class="justify-self-end toggle toggle-success" />
|
||||||
|
<svelte:fragment slot="description">Minimize to the system tray at startup.</svelte:fragment>
|
||||||
|
</Setting>
|
||||||
|
|
||||||
|
<div class="divider"></div>
|
||||||
|
<div class="grid grid-cols-2 items-center">
|
||||||
|
<h3 class="text-lg font-bold">Start minimized</h3>
|
||||||
|
<input type="checkbox" bind:checked="{$appState.config.start_minimized}" class="justify-self-end toggle toggle-success" />
|
||||||
|
</div>
|
||||||
|
<p class="mt-3">Minimize to the system tray at startup.</p>
|
||||||
|
|
||||||
|
<div class="divider"></div>
|
||||||
|
<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
|
||||||
|
the window to tray. Only applicable if the window was minimized
|
||||||
|
to tray before the request was received.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="divider"></div>
|
||||||
|
<div class="grid grid-cols-2 items-center">
|
||||||
|
<h3 class="text-lg font-bold">Update credentials</h3>
|
||||||
|
<div class="justify-self-end">
|
||||||
|
<Link target="EnterCredentials">
|
||||||
|
<button class="btn btn-sm btn-primary">Update</button>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p class="mt-3">Update or re-enter your encrypted credentials.</p>
|
||||||
|
</div>
|
||||||
|
{/await}
|
||||||
@@ -1,21 +1,75 @@
|
|||||||
<script>
|
<script>
|
||||||
import { onMount, createEventDispatcher } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
|
import { draw, fade } from 'svelte/transition';
|
||||||
import { emit } from '@tauri-apps/api/event';
|
import { emit } from '@tauri-apps/api/event';
|
||||||
import { invoke } from '@tauri-apps/api/tauri';
|
import { invoke } from '@tauri-apps/api/tauri';
|
||||||
|
|
||||||
export let appState;
|
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';
|
||||||
|
|
||||||
onMount(async () => {
|
let success = false;
|
||||||
|
let error = null;
|
||||||
|
|
||||||
|
async function respond() {
|
||||||
let response = {
|
let response = {
|
||||||
id: appState.currentRequest.id,
|
id: $appState.currentRequest.id,
|
||||||
approval: 'Approved',
|
approval: 'Approved',
|
||||||
}
|
};
|
||||||
await invoke('respond', {response});
|
|
||||||
appState.currentRequest = null;
|
|
||||||
});
|
|
||||||
|
|
||||||
const dispatch = createEventDispatcher();
|
try {
|
||||||
window.setTimeout(() => dispatch('navigate', {target: 'Home'}), 3000);
|
await invoke('respond', {response});
|
||||||
|
success = true;
|
||||||
|
$appState.currentRequest = null;
|
||||||
|
window.setTimeout(() => navigate('Home'), 1000);
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
error = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onMount(respond);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<h1 class="text-4xl text-gray-300">Approved!</h1>
|
<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}
|
||||||
|
-->
|
||||||
+45
-10
@@ -1,21 +1,56 @@
|
|||||||
<script>
|
<script>
|
||||||
import { onMount, createEventDispatcher } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
|
import { draw, fade } from 'svelte/transition';
|
||||||
import { emit } from '@tauri-apps/api/event';
|
import { emit } from '@tauri-apps/api/event';
|
||||||
import { invoke } from '@tauri-apps/api/tauri';
|
import { invoke } from '@tauri-apps/api/tauri';
|
||||||
|
|
||||||
export let appState;
|
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';
|
||||||
|
|
||||||
onMount(async () => {
|
let error = null;
|
||||||
|
|
||||||
|
async function respond() {
|
||||||
let response = {
|
let response = {
|
||||||
id: appState.currentRequest.id,
|
id: $appState.currentRequest.id,
|
||||||
approval: 'Denied',
|
approval: 'Denied',
|
||||||
}
|
}
|
||||||
await invoke('respond', {response});
|
|
||||||
appState.currentRequest = null;
|
|
||||||
});
|
|
||||||
|
|
||||||
const dispatch = createEventDispatcher();
|
try {
|
||||||
window.setTimeout(() => dispatch('navigate', {target: 'Home'}), 3000);
|
await invoke('respond', {response});
|
||||||
|
$appState.currentRequest = null;
|
||||||
|
window.setTimeout(() => navigate('Home'), 1000);
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
error = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onMount(respond);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<h1 class="text-4xl text-gray-300">Denied!</h1>
|
{#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}
|
||||||
+41
-10
@@ -1,25 +1,56 @@
|
|||||||
<script>
|
<script>
|
||||||
import { invoke } from '@tauri-apps/api/tauri';
|
import { invoke } from '@tauri-apps/api/tauri';
|
||||||
import { createEventDispatcher } from 'svelte';
|
|
||||||
|
|
||||||
export let appState;
|
import { appState } from '../lib/state.js';
|
||||||
|
import { navigate } from '../lib/routing.js';
|
||||||
|
import { getRootCause } from '../lib/errors.js';
|
||||||
|
import ErrorAlert from '../ui/ErrorAlert.svelte';
|
||||||
|
import Link from '../ui/Link.svelte';
|
||||||
|
|
||||||
const dispatch = createEventDispatcher();
|
|
||||||
|
|
||||||
|
let errorMsg = null;
|
||||||
|
let alert;
|
||||||
let passphrase = '';
|
let passphrase = '';
|
||||||
async function unlock() {
|
async function unlock() {
|
||||||
console.log('invoking unlock command.')
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await invoke('unlock', {passphrase});
|
let r = await invoke('unlock', {passphrase});
|
||||||
|
$appState.credentialStatus = 'unlocked';
|
||||||
|
if ($appState.currentRequest) {
|
||||||
|
navigate('ShowApproved');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
navigate('Home');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
console.log('Unlock error:', e);
|
window.error = e;
|
||||||
|
if (e.code === 'GetSession') {
|
||||||
|
let root = getRootCause(e);
|
||||||
|
errorMsg = `Error response from AWS (${root.code}): ${root.msg}`;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
errorMsg = e.msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (alert) {
|
||||||
|
alert.shake();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<form action="#" on:submit|preventDefault="{unlock}">
|
|
||||||
<div class="text-gray-200">Enter your passphrase:</div>
|
<form action="#" on:submit|preventDefault="{unlock}" class="form-control space-y-4 max-w-sm m-auto p-4 h-screen justify-center">
|
||||||
<input class="text-gray-200 bg-zinc-800" type="password" placeholder="correct horse battery staple" bind:value="{passphrase}" />
|
<h2 class="font-bold text-2xl text-center">Enter your passphrase</h2>
|
||||||
|
|
||||||
|
{#if errorMsg}
|
||||||
|
<ErrorAlert bind:this="{alert}">{errorMsg}</ErrorAlert>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<input autofocus name="password" type="password" placeholder="correct horse battery staple" bind:value="{passphrase}" class="input input-bordered" />
|
||||||
|
|
||||||
|
<input type="submit" class="btn btn-primary" />
|
||||||
|
<Link target="Home" hotkey="Escape">
|
||||||
|
<button class="btn btn-outline btn-sm w-full">Cancel</button>
|
||||||
|
</Link>
|
||||||
</form>
|
</form>
|
||||||
@@ -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 |
+3
-1
@@ -7,5 +7,7 @@ module.exports = {
|
|||||||
theme: {
|
theme: {
|
||||||
extend: {},
|
extend: {},
|
||||||
},
|
},
|
||||||
plugins: [],
|
plugins: [
|
||||||
|
require('daisyui'),
|
||||||
|
],
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user