mirror of
https://github.com/NotAShelf/stash.git
synced 2026-04-12 14:07:42 +00:00
Compare commits
4 commits
main
...
notashelf/
| Author | SHA1 | Date | |
|---|---|---|---|
|
7866af166e |
|||
|
d013901396 |
|||
|
d78cbd6741 |
|||
|
5153b4d19c |
4 changed files with 912 additions and 30 deletions
645
Cargo.lock
generated
645
Cargo.lock
generated
|
|
@ -17,6 +17,59 @@ version = "2.0.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
|
checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aead"
|
||||||
|
version = "0.5.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0"
|
||||||
|
dependencies = [
|
||||||
|
"crypto-common",
|
||||||
|
"generic-array",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "age"
|
||||||
|
version = "0.11.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bf640be7658959746f1f0f2faab798f6098a9436a8e18e148d18bc9875e13c4b"
|
||||||
|
dependencies = [
|
||||||
|
"age-core",
|
||||||
|
"base64 0.21.7",
|
||||||
|
"bech32",
|
||||||
|
"chacha20poly1305",
|
||||||
|
"cookie-factory",
|
||||||
|
"hmac",
|
||||||
|
"i18n-embed",
|
||||||
|
"i18n-embed-fl",
|
||||||
|
"lazy_static",
|
||||||
|
"nom 7.1.3",
|
||||||
|
"pin-project",
|
||||||
|
"rand",
|
||||||
|
"rust-embed",
|
||||||
|
"scrypt",
|
||||||
|
"sha2",
|
||||||
|
"subtle",
|
||||||
|
"x25519-dalek",
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "age-core"
|
||||||
|
version = "0.11.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e2bf6a89c984ca9d850913ece2da39e1d200563b0a94b002b253beee4c5acf99"
|
||||||
|
dependencies = [
|
||||||
|
"base64 0.21.7",
|
||||||
|
"chacha20poly1305",
|
||||||
|
"cookie-factory",
|
||||||
|
"hkdf",
|
||||||
|
"io_tee",
|
||||||
|
"nom 7.1.3",
|
||||||
|
"rand",
|
||||||
|
"secrecy",
|
||||||
|
"sha2",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aho-corasick"
|
name = "aho-corasick"
|
||||||
version = "1.1.4"
|
version = "1.1.4"
|
||||||
|
|
@ -286,12 +339,33 @@ dependencies = [
|
||||||
"windows-link 0.2.1",
|
"windows-link 0.2.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "base64"
|
||||||
|
version = "0.21.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "base64"
|
name = "base64"
|
||||||
version = "0.22.1"
|
version = "0.22.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
|
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "basic-toml"
|
||||||
|
version = "0.1.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ba62675e8242a4c4e806d12f11d136e626e6c8361d6b829310732241652a178a"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bech32"
|
||||||
|
version = "0.9.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bit-set"
|
name = "bit-set"
|
||||||
version = "0.5.3"
|
version = "0.5.3"
|
||||||
|
|
@ -393,6 +467,41 @@ version = "0.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
|
checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "chacha20"
|
||||||
|
version = "0.9.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"cipher",
|
||||||
|
"cpufeatures",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "chacha20poly1305"
|
||||||
|
version = "0.10.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35"
|
||||||
|
dependencies = [
|
||||||
|
"aead",
|
||||||
|
"chacha20",
|
||||||
|
"cipher",
|
||||||
|
"poly1305",
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cipher"
|
||||||
|
version = "0.4.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
|
||||||
|
dependencies = [
|
||||||
|
"crypto-common",
|
||||||
|
"inout",
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "4.6.0"
|
version = "4.6.0"
|
||||||
|
|
@ -508,6 +617,15 @@ dependencies = [
|
||||||
"unicode-segmentation",
|
"unicode-segmentation",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cookie-factory"
|
||||||
|
version = "0.3.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9885fa71e26b8ab7855e2ec7cae6e9b380edff76cd052e07c683a0319d51b3a2"
|
||||||
|
dependencies = [
|
||||||
|
"futures",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cpufeatures"
|
name = "cpufeatures"
|
||||||
version = "0.2.17"
|
version = "0.2.17"
|
||||||
|
|
@ -581,6 +699,32 @@ dependencies = [
|
||||||
"windows-sys",
|
"windows-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "curve25519-dalek"
|
||||||
|
version = "4.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"cpufeatures",
|
||||||
|
"curve25519-dalek-derive",
|
||||||
|
"fiat-crypto",
|
||||||
|
"rustc_version",
|
||||||
|
"subtle",
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "curve25519-dalek-derive"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.117",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "darling"
|
name = "darling"
|
||||||
version = "0.23.0"
|
version = "0.23.0"
|
||||||
|
|
@ -660,6 +804,7 @@ checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"block-buffer",
|
"block-buffer",
|
||||||
"crypto-common",
|
"crypto-common",
|
||||||
|
"subtle",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -867,6 +1012,12 @@ version = "2.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
|
checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fiat-crypto"
|
||||||
|
version = "0.2.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "filedescriptor"
|
name = "filedescriptor"
|
||||||
version = "0.8.3"
|
version = "0.8.3"
|
||||||
|
|
@ -878,6 +1029,15 @@ dependencies = [
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "find-crate"
|
||||||
|
version = "0.6.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "59a98bbaacea1c0eb6a0876280051b892eb73594fd90cf3b20e9c817029c57d2"
|
||||||
|
dependencies = [
|
||||||
|
"toml",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "find-msvc-tools"
|
name = "find-msvc-tools"
|
||||||
version = "0.1.9"
|
version = "0.1.9"
|
||||||
|
|
@ -902,6 +1062,50 @@ version = "0.5.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99"
|
checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fluent"
|
||||||
|
version = "0.16.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bb74634707bebd0ce645a981148e8fb8c7bccd4c33c652aeffd28bf2f96d555a"
|
||||||
|
dependencies = [
|
||||||
|
"fluent-bundle",
|
||||||
|
"unic-langid",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fluent-bundle"
|
||||||
|
version = "0.15.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7fe0a21ee80050c678013f82edf4b705fe2f26f1f9877593d13198612503f493"
|
||||||
|
dependencies = [
|
||||||
|
"fluent-langneg",
|
||||||
|
"fluent-syntax",
|
||||||
|
"intl-memoizer",
|
||||||
|
"intl_pluralrules",
|
||||||
|
"rustc-hash 1.1.0",
|
||||||
|
"self_cell 0.10.3",
|
||||||
|
"smallvec",
|
||||||
|
"unic-langid",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fluent-langneg"
|
||||||
|
version = "0.13.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7eebbe59450baee8282d71676f3bfed5689aeab00b27545e83e5f14b1195e8b0"
|
||||||
|
dependencies = [
|
||||||
|
"unic-langid",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fluent-syntax"
|
||||||
|
version = "0.11.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2a530c4694a6a8d528794ee9bbd8ba0122e779629ac908d15ad5a7ae7763a33d"
|
||||||
|
dependencies = [
|
||||||
|
"thiserror 1.0.69",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fnv"
|
name = "fnv"
|
||||||
version = "1.0.7"
|
version = "1.0.7"
|
||||||
|
|
@ -1129,12 +1333,96 @@ 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 = "hkdf"
|
||||||
|
version = "0.12.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7"
|
||||||
|
dependencies = [
|
||||||
|
"hmac",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hmac"
|
||||||
|
version = "0.12.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
|
||||||
|
dependencies = [
|
||||||
|
"digest",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "humantime"
|
name = "humantime"
|
||||||
version = "2.3.0"
|
version = "2.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "135b12329e5e3ce057a9f972339ea52bc954fe1e9358ef27f95e89716fbc5424"
|
checksum = "135b12329e5e3ce057a9f972339ea52bc954fe1e9358ef27f95e89716fbc5424"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "i18n-config"
|
||||||
|
version = "0.4.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3e06b90c8a0d252e203c94344b21e35a30f3a3a85dc7db5af8f8df9f3e0c63ef"
|
||||||
|
dependencies = [
|
||||||
|
"basic-toml",
|
||||||
|
"log",
|
||||||
|
"serde",
|
||||||
|
"serde_derive",
|
||||||
|
"thiserror 1.0.69",
|
||||||
|
"unic-langid",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "i18n-embed"
|
||||||
|
version = "0.15.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "669ffc2c93f97e6ddf06ddbe999fcd6782e3342978bb85f7d3c087c7978404c4"
|
||||||
|
dependencies = [
|
||||||
|
"arc-swap",
|
||||||
|
"fluent",
|
||||||
|
"fluent-langneg",
|
||||||
|
"fluent-syntax",
|
||||||
|
"i18n-embed-impl",
|
||||||
|
"intl-memoizer",
|
||||||
|
"log",
|
||||||
|
"parking_lot",
|
||||||
|
"rust-embed",
|
||||||
|
"thiserror 1.0.69",
|
||||||
|
"unic-langid",
|
||||||
|
"walkdir",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "i18n-embed-fl"
|
||||||
|
version = "0.9.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "04b2969d0b3fc6143776c535184c19722032b43e6a642d710fa3f88faec53c2d"
|
||||||
|
dependencies = [
|
||||||
|
"find-crate",
|
||||||
|
"fluent",
|
||||||
|
"fluent-syntax",
|
||||||
|
"i18n-config",
|
||||||
|
"i18n-embed",
|
||||||
|
"proc-macro-error2",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"strsim",
|
||||||
|
"syn 2.0.117",
|
||||||
|
"unic-langid",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "i18n-embed-impl"
|
||||||
|
version = "0.8.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0f2cc0e0523d1fe6fc2c6f66e5038624ea8091b3e7748b5e8e0c84b1698db6c2"
|
||||||
|
dependencies = [
|
||||||
|
"find-crate",
|
||||||
|
"i18n-config",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.117",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "icu_collections"
|
name = "icu_collections"
|
||||||
version = "2.2.0"
|
version = "2.2.0"
|
||||||
|
|
@ -1283,6 +1571,15 @@ dependencies = [
|
||||||
"rustversion",
|
"rustversion",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "inout"
|
||||||
|
version = "0.1.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01"
|
||||||
|
dependencies = [
|
||||||
|
"generic-array",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "inquire"
|
name = "inquire"
|
||||||
version = "0.9.4"
|
version = "0.9.4"
|
||||||
|
|
@ -1309,6 +1606,31 @@ dependencies = [
|
||||||
"syn 2.0.117",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "intl-memoizer"
|
||||||
|
version = "0.5.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "310da2e345f5eb861e7a07ee182262e94975051db9e4223e909ba90f392f163f"
|
||||||
|
dependencies = [
|
||||||
|
"type-map",
|
||||||
|
"unic-langid",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "intl_pluralrules"
|
||||||
|
version = "7.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "078ea7b7c29a2b4df841a7f6ac8775ff6074020c6776d48491ce2268e068f972"
|
||||||
|
dependencies = [
|
||||||
|
"unic-langid",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "io_tee"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4b3f7cef34251886990511df1c61443aa928499d598a9473929ab5a90a527304"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "is_terminal_polyfill"
|
name = "is_terminal_polyfill"
|
||||||
version = "1.70.2"
|
version = "1.70.2"
|
||||||
|
|
@ -1709,6 +2031,12 @@ version = "1.70.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
|
checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "opaque-debug"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "option-ext"
|
name = "option-ext"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
|
|
@ -1779,6 +2107,16 @@ dependencies = [
|
||||||
"windows-link 0.2.1",
|
"windows-link 0.2.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pbkdf2"
|
||||||
|
version = "0.12.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2"
|
||||||
|
dependencies = [
|
||||||
|
"digest",
|
||||||
|
"hmac",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "percent-encoding"
|
name = "percent-encoding"
|
||||||
version = "2.3.2"
|
version = "2.3.2"
|
||||||
|
|
@ -1891,6 +2229,26 @@ dependencies = [
|
||||||
"siphasher",
|
"siphasher",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pin-project"
|
||||||
|
version = "1.1.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f1749c7ed4bcaf4c3d0a3efc28538844fb29bcdd7d2b67b2be7e20ba861ff517"
|
||||||
|
dependencies = [
|
||||||
|
"pin-project-internal",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pin-project-internal"
|
||||||
|
version = "1.1.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d9b20ed30f105399776b9c883e68e536ef602a16ae6f596d2c473591d6ad64c6"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.117",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pin-project-lite"
|
name = "pin-project-lite"
|
||||||
version = "0.2.17"
|
version = "0.2.17"
|
||||||
|
|
@ -1928,6 +2286,17 @@ dependencies = [
|
||||||
"windows-sys",
|
"windows-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "poly1305"
|
||||||
|
version = "0.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf"
|
||||||
|
dependencies = [
|
||||||
|
"cpufeatures",
|
||||||
|
"opaque-debug",
|
||||||
|
"universal-hash",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "portable-atomic"
|
name = "portable-atomic"
|
||||||
version = "1.13.1"
|
version = "1.13.1"
|
||||||
|
|
@ -1958,6 +2327,15 @@ version = "0.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
|
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ppv-lite86"
|
||||||
|
version = "0.2.21"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
|
||||||
|
dependencies = [
|
||||||
|
"zerocopy",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "prettyplease"
|
name = "prettyplease"
|
||||||
version = "0.2.37"
|
version = "0.2.37"
|
||||||
|
|
@ -1977,6 +2355,28 @@ dependencies = [
|
||||||
"toml_edit",
|
"toml_edit",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro-error-attr2"
|
||||||
|
version = "2.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro-error2"
|
||||||
|
version = "2.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro-error-attr2",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.117",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.106"
|
version = "1.0.106"
|
||||||
|
|
@ -2031,6 +2431,18 @@ version = "0.8.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"rand_chacha",
|
||||||
|
"rand_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_chacha"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||||
|
dependencies = [
|
||||||
|
"ppv-lite86",
|
||||||
"rand_core",
|
"rand_core",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -2039,6 +2451,9 @@ name = "rand_core"
|
||||||
version = "0.6.4"
|
version = "0.6.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom 0.2.17",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ratatui"
|
name = "ratatui"
|
||||||
|
|
@ -2199,12 +2614,58 @@ dependencies = [
|
||||||
"sqlite-wasm-rs",
|
"sqlite-wasm-rs",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rust-embed"
|
||||||
|
version = "8.11.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "04113cb9355a377d83f06ef1f0a45b8ab8cd7d8b1288160717d66df5c7988d27"
|
||||||
|
dependencies = [
|
||||||
|
"rust-embed-impl",
|
||||||
|
"rust-embed-utils",
|
||||||
|
"walkdir",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rust-embed-impl"
|
||||||
|
version = "8.11.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "da0902e4c7c8e997159ab384e6d0fc91c221375f6894346ae107f47dd0f3ccaa"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"rust-embed-utils",
|
||||||
|
"syn 2.0.117",
|
||||||
|
"walkdir",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rust-embed-utils"
|
||||||
|
version = "8.11.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5bcdef0be6fe7f6fa333b1073c949729274b05f123a0ad7efcb8efd878e5c3b1"
|
||||||
|
dependencies = [
|
||||||
|
"sha2",
|
||||||
|
"walkdir",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustc-demangle"
|
name = "rustc-demangle"
|
||||||
version = "0.1.27"
|
version = "0.1.27"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d"
|
checksum = "b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustc-hash"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustc-hash"
|
||||||
|
version = "2.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustc_version"
|
name = "rustc_version"
|
||||||
version = "0.4.1"
|
version = "0.4.1"
|
||||||
|
|
@ -2239,12 +2700,65 @@ version = "1.0.23"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f"
|
checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "salsa20"
|
||||||
|
version = "0.10.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213"
|
||||||
|
dependencies = [
|
||||||
|
"cipher",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "same-file"
|
||||||
|
version = "1.0.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
|
||||||
|
dependencies = [
|
||||||
|
"winapi-util",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "scopeguard"
|
name = "scopeguard"
|
||||||
version = "1.2.0"
|
version = "1.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "scrypt"
|
||||||
|
version = "0.11.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0516a385866c09368f0b5bcd1caff3366aace790fcd46e2bb032697bb172fd1f"
|
||||||
|
dependencies = [
|
||||||
|
"pbkdf2",
|
||||||
|
"salsa20",
|
||||||
|
"sha2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "secrecy"
|
||||||
|
version = "0.10.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e891af845473308773346dc847b2c23ee78fe442e0472ac50e22a18a93d3ae5a"
|
||||||
|
dependencies = [
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "self_cell"
|
||||||
|
version = "0.10.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e14e4d63b804dc0c7ec4a1e52bcb63f02c7ac94476755aa579edac21e01f915d"
|
||||||
|
dependencies = [
|
||||||
|
"self_cell 1.2.2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "self_cell"
|
||||||
|
version = "1.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b12e76d157a900eb52e81bc6e9f3069344290341720e9178cde2407113ac8d89"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "semver"
|
name = "semver"
|
||||||
version = "1.0.27"
|
version = "1.0.27"
|
||||||
|
|
@ -2419,8 +2933,9 @@ checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596"
|
||||||
name = "stash-clipboard"
|
name = "stash-clipboard"
|
||||||
version = "0.3.6"
|
version = "0.3.6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"age",
|
||||||
"arc-swap",
|
"arc-swap",
|
||||||
"base64",
|
"base64 0.22.1",
|
||||||
"blocking",
|
"blocking",
|
||||||
"clap",
|
"clap",
|
||||||
"clap-verbosity-flag",
|
"clap-verbosity-flag",
|
||||||
|
|
@ -2485,6 +3000,12 @@ dependencies = [
|
||||||
"syn 2.0.117",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "subtle"
|
||||||
|
version = "2.6.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "1.0.109"
|
version = "1.0.109"
|
||||||
|
|
@ -2571,7 +3092,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4676b37242ccbd1aabf56edb093a4827dc49086c0ffd764a5705899e0f35f8f7"
|
checksum = "4676b37242ccbd1aabf56edb093a4827dc49086c0ffd764a5705899e0f35f8f7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"base64",
|
"base64 0.22.1",
|
||||||
"bitflags 2.11.0",
|
"bitflags 2.11.0",
|
||||||
"fancy-regex",
|
"fancy-regex",
|
||||||
"filedescriptor",
|
"filedescriptor",
|
||||||
|
|
@ -2683,9 +3204,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d"
|
checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"displaydoc",
|
"displaydoc",
|
||||||
|
"serde_core",
|
||||||
"zerovec",
|
"zerovec",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "toml"
|
||||||
|
version = "0.5.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml_datetime"
|
name = "toml_datetime"
|
||||||
version = "1.1.1+spec-1.1.0"
|
version = "1.1.1+spec-1.1.0"
|
||||||
|
|
@ -2780,6 +3311,15 @@ dependencies = [
|
||||||
"petgraph",
|
"petgraph",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "type-map"
|
||||||
|
version = "0.5.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cb30dbbd9036155e74adad6812e9898d03ec374946234fbcebd5dfc7b9187b90"
|
||||||
|
dependencies = [
|
||||||
|
"rustc-hash 2.1.2",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "typenum"
|
name = "typenum"
|
||||||
version = "1.19.0"
|
version = "1.19.0"
|
||||||
|
|
@ -2803,6 +3343,25 @@ dependencies = [
|
||||||
"windows-sys",
|
"windows-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unic-langid"
|
||||||
|
version = "0.9.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a28ba52c9b05311f4f6e62d5d9d46f094bd6e84cb8df7b3ef952748d752a7d05"
|
||||||
|
dependencies = [
|
||||||
|
"unic-langid-impl",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unic-langid-impl"
|
||||||
|
version = "0.9.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dce1bf08044d4b7a94028c93786f8566047edc11110595914de93362559bc658"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
"tinystr",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-ident"
|
name = "unicode-ident"
|
||||||
version = "1.0.24"
|
version = "1.0.24"
|
||||||
|
|
@ -2838,6 +3397,16 @@ version = "0.2.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
|
checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "universal-hash"
|
||||||
|
version = "0.5.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea"
|
||||||
|
dependencies = [
|
||||||
|
"crypto-common",
|
||||||
|
"subtle",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "url"
|
name = "url"
|
||||||
version = "2.5.8"
|
version = "2.5.8"
|
||||||
|
|
@ -2902,6 +3471,16 @@ dependencies = [
|
||||||
"utf8parse",
|
"utf8parse",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "walkdir"
|
||||||
|
version = "2.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
|
||||||
|
dependencies = [
|
||||||
|
"same-file",
|
||||||
|
"winapi-util",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasi"
|
name = "wasi"
|
||||||
version = "0.11.1+wasi-snapshot-preview1"
|
version = "0.11.1+wasi-snapshot-preview1"
|
||||||
|
|
@ -3164,6 +3743,15 @@ version = "0.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-util"
|
||||||
|
version = "0.1.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
|
||||||
|
dependencies = [
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winapi-x86_64-pc-windows-gnu"
|
name = "winapi-x86_64-pc-windows-gnu"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
|
|
@ -3435,6 +4023,18 @@ version = "0.6.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4"
|
checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "x25519-dalek"
|
||||||
|
version = "2.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c7e468321c81fb07fa7f4c636c3972b9100f0346e5b6a9f2bd0603a52f7ed277"
|
||||||
|
dependencies = [
|
||||||
|
"curve25519-dalek",
|
||||||
|
"rand_core",
|
||||||
|
"serde",
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "yoke"
|
name = "yoke"
|
||||||
version = "0.8.2"
|
version = "0.8.2"
|
||||||
|
|
@ -3519,6 +4119,26 @@ dependencies = [
|
||||||
"zvariant",
|
"zvariant",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zerocopy"
|
||||||
|
version = "0.8.48"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9"
|
||||||
|
dependencies = [
|
||||||
|
"zerocopy-derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zerocopy-derive"
|
||||||
|
version = "0.8.48"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.117",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerofrom"
|
name = "zerofrom"
|
||||||
version = "0.1.7"
|
version = "0.1.7"
|
||||||
|
|
@ -3540,6 +4160,26 @@ dependencies = [
|
||||||
"synstructure",
|
"synstructure",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zeroize"
|
||||||
|
version = "1.8.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0"
|
||||||
|
dependencies = [
|
||||||
|
"zeroize_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zeroize_derive"
|
||||||
|
version = "1.4.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.117",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerotrie"
|
name = "zerotrie"
|
||||||
version = "0.2.4"
|
version = "0.2.4"
|
||||||
|
|
@ -3557,6 +4197,7 @@ version = "0.11.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239"
|
checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"serde",
|
||||||
"yoke",
|
"yoke",
|
||||||
"zerofrom",
|
"zerofrom",
|
||||||
"zerovec-derive",
|
"zerovec-derive",
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ name = "stash" # actual binary name for Nix, Cargo, etc.
|
||||||
path = "src/main.rs"
|
path = "src/main.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
age = "0.11.2"
|
||||||
arc-swap = { version = "1.9.0", optional = true }
|
arc-swap = { version = "1.9.0", optional = true }
|
||||||
base64 = "0.22.1"
|
base64 = "0.22.1"
|
||||||
blocking = "1.6.2"
|
blocking = "1.6.2"
|
||||||
|
|
|
||||||
119
README.md
119
README.md
|
|
@ -20,9 +20,10 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
Lightweight & feature-rich Wayland clipboard "manager" with fast persistent history and
|
Lightweight & feature-rich Wayland clipboard "manager" with fast persistent
|
||||||
robust multi-media support. Stores and previews clipboard entries (text, images)
|
history and robust multi-media support. Stores and previews clipboard
|
||||||
on the clipboard with a neat TUI and advanced scripting capabilities.
|
entries (text, images) on the clipboard with a neat TUI and advanced scripting
|
||||||
|
capabilities.
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
|
|
@ -52,6 +53,7 @@ with many features such as but not necessarily limited to:
|
||||||
- Drop-in replacement for `wl-clipboard` tools (`wl-copy` and `wl-paste`)
|
- Drop-in replacement for `wl-clipboard` tools (`wl-copy` and `wl-paste`)
|
||||||
- Sensitive clipboard filtering via regex (see below)
|
- Sensitive clipboard filtering via regex (see below)
|
||||||
- Sensitive clipboard filtering by application (see below)
|
- Sensitive clipboard filtering by application (see below)
|
||||||
|
- Database encryption using age (see below)
|
||||||
|
|
||||||
on top of the existing features of Cliphist, which are as follows:
|
on top of the existing features of Cliphist, which are as follows:
|
||||||
|
|
||||||
|
|
@ -357,21 +359,38 @@ sensitive pattern, using a regular expression. This is useful for preventing
|
||||||
accidental storage of secrets, passwords, or other sensitive data. You don't
|
accidental storage of secrets, passwords, or other sensitive data. You don't
|
||||||
want sensitive data ending up in your persistent clipboard, right?
|
want sensitive data ending up in your persistent clipboard, right?
|
||||||
|
|
||||||
The filter can be configured in one of three ways, as part of two separate
|
The filter can be configured in several ways, as part of two separate features.
|
||||||
features.
|
|
||||||
|
|
||||||
#### Clipboard Filtering by Entry Regex
|
#### Clipboard Filtering by Entry Regex
|
||||||
|
|
||||||
This can be configured in one of two ways. You can use the **environment
|
This can be configured in one of several ways. You can use the **environment
|
||||||
variable** `STASTH_SENSITIVE_REGEX` to a valid regex pattern, and if the
|
variable** `STASH_SENSITIVE_REGEX` to a valid regex pattern, and if the
|
||||||
clipboard text matches the regex it will not be stored. This can be used for
|
clipboard text matches the regex it will not be stored. This can be used for
|
||||||
trivial secrets such as but not limited to GitHub tokens or secrets that follow
|
trivial secrets such as but not limited to GitHub tokens or secrets that follow
|
||||||
a rule, e.g. a prefix. You would typically set this in your `~/.bashrc` or
|
a rule, e.g. a prefix. You would typically set this in your `~/.bashrc` or
|
||||||
similar but in some cases this might be a security flaw.
|
similar but in some cases this might be a security flaw.
|
||||||
|
|
||||||
The safer alternative to this is using **Systemd LoadCrediental**. If Stash is
|
The _less-insecure_ [^1] alternative to this is using
|
||||||
running as a Systemd service, you can provide a regex pattern using a crediental
|
`STASH_SENSITIVE_REGEX_FILE` to read the regex from a file path. This is useful
|
||||||
file. For example, add to your `stash.service`:
|
for NixOS secrets managers like agenix or sops-nix.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# You can set this in your configuration with `environment.sessionVariables`
|
||||||
|
# or similar, pointing to the *decryption path*.
|
||||||
|
$ export STASH_SENSITIVE_REGEX_FILE=/run/secrets/stash/clipboard_filter
|
||||||
|
```
|
||||||
|
|
||||||
|
Or use `STASH_SENSITIVE_REGEX_COMMAND` to execute a command that returns the
|
||||||
|
regex pattern. This works well with password managers:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Stash will execute the command and consume the result
|
||||||
|
$ export STASH_SENSITIVE_REGEX_COMMAND="pass show stash/clipboard-filter"
|
||||||
|
```
|
||||||
|
|
||||||
|
The safest option is using **Systemd LoadCredential**. If Stash is running as a
|
||||||
|
Systemd service, you can provide a regex pattern using a credential file. For
|
||||||
|
example, add to your `stash.service`:
|
||||||
|
|
||||||
```dosini
|
```dosini
|
||||||
LoadCredential=clipboard_filter:/etc/stash/clipboard_filter
|
LoadCredential=clipboard_filter:/etc/stash/clipboard_filter
|
||||||
|
|
@ -382,9 +401,9 @@ quotes). This is done automatically in the
|
||||||
[vendored Systemd service](./contrib/stash.service). Remember to set the
|
[vendored Systemd service](./contrib/stash.service). Remember to set the
|
||||||
appropriate file permissions if using this option.
|
appropriate file permissions if using this option.
|
||||||
|
|
||||||
The service will check the credential file first, then the environment variable.
|
The service will check the credential file first, then the command, then the
|
||||||
If a clipboard entry matches the regex, it will be skipped and a warning will be
|
file path, then the environment variable. If a clipboard entry matches the
|
||||||
logged.
|
regex, it will be skipped and a warning will be logged.
|
||||||
|
|
||||||
> [!TIP]
|
> [!TIP]
|
||||||
> **Example regex to block common password patterns**:
|
> **Example regex to block common password patterns**:
|
||||||
|
|
@ -393,17 +412,21 @@ logged.
|
||||||
>
|
>
|
||||||
> For security reasons, you are recommended to use the regex only for generic
|
> For security reasons, you are recommended to use the regex only for generic
|
||||||
> tokens that follow a specific rule, for example a generic prefix or suffix.
|
> tokens that follow a specific rule, for example a generic prefix or suffix.
|
||||||
|
> For blocking entries from applications that emit sensitive data, such as
|
||||||
|
> password managers, filter by application class instead.
|
||||||
|
|
||||||
#### Clipboard Filtering by Application Class
|
#### Clipboard Filtering by Application Class
|
||||||
|
|
||||||
Stash allows blocking an entry from the persistent history if it has been copied
|
Stash allows blocking an entry from the persistent history if it has been copied
|
||||||
from certain applications. This depends on the `use-toplevel` feature flag and
|
from certain applications. This depends on the `use-toplevel` feature flag and
|
||||||
uses the the `wlr-foreign-toplevel-management-v1` protocol for precise focus
|
uses the the `wlr-foreign-toplevel-management-v1` protocol for precise focus
|
||||||
detection. While this feature flag is enabled (the default) you may use
|
detection.
|
||||||
`--excluded-apps` in, e.g., `stash watch` or set the `STASH_EXCLUDED_APPS`
|
|
||||||
environment variable to block entries from persisting in the database if they
|
While this feature flag is enabled (the default) you may use `--excluded-apps`
|
||||||
are coming from your password manager for example. The entry is still copied to
|
in, e.g., `stash watch` or set the `STASH_EXCLUDED_APPS` environment variable to
|
||||||
the clipboard, but it will never be put inside the database.
|
block entries from persisting in the database if they are coming from your
|
||||||
|
password manager for example. The entry is still copied to the clipboard, but it
|
||||||
|
will never be put inside the database.
|
||||||
|
|
||||||
This is a more robust alternative to using the regex method above, since you
|
This is a more robust alternative to using the regex method above, since you
|
||||||
likely do not want to catch your passwords with a regex. Simply pass your
|
likely do not want to catch your passwords with a regex. Simply pass your
|
||||||
|
|
@ -516,6 +539,66 @@ figured out something new, e.g. a neat shell trick, feel free to add it here!
|
||||||
the packagers. While building from source, you may link
|
the packagers. While building from source, you may link
|
||||||
`target/release/stash` manually.
|
`target/release/stash` manually.
|
||||||
|
|
||||||
|
### Database Encryption
|
||||||
|
|
||||||
|
Stash supports encrypting clipboard entries at rest using the
|
||||||
|
[age](https://age-encryption.org/) encryption format. This provides protection
|
||||||
|
for sensitive data stored in the database.
|
||||||
|
|
||||||
|
> [!WARNING]
|
||||||
|
> If you enable encryption after already having entries in the database, the
|
||||||
|
> existing entries will remain unencrypted. Only new entries added after
|
||||||
|
> configuring encryption will be encrypted. To encrypt existing entries, you
|
||||||
|
> would need to wipe the database and re-copy your clipboard contents.
|
||||||
|
|
||||||
|
Encryption is **opt-in** and only takes effect when a passphrase is configured.
|
||||||
|
When one _is_ configured, all new clipboard entries are encrypted before being
|
||||||
|
stored in the database. Entries without encryption configured are stored in
|
||||||
|
plaintext instead.
|
||||||
|
|
||||||
|
Encrypted entries are detected by the `age-encryption.org/v1` header and
|
||||||
|
decrypted automatically on retrieval. Search operations (e.g.,
|
||||||
|
`stash delete --type query`) decrypt entries on-the-fly to match queries;
|
||||||
|
entries that fail decryption are skipped with a warning
|
||||||
|
|
||||||
|
#### Configuration
|
||||||
|
|
||||||
|
Encryption is configured using a passphrase, which can be provided in one of
|
||||||
|
several ways. The simplest is using the **environment variable**
|
||||||
|
`STASH_ENCRYPTION_PASSPHRASE`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export STASH_ENCRYPTION_PASSPHRASE="your-secure-passphrase"
|
||||||
|
```
|
||||||
|
|
||||||
|
Alternatively, you can use `STASH_ENCRYPTION_PASSPHRASE_FILE` to read the
|
||||||
|
passphrase from a file path. This is useful for NixOS secrets managers:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export STASH_ENCRYPTION_PASSPHRASE_FILE=/run/secrets/stash/encryption_passphrase
|
||||||
|
```
|
||||||
|
|
||||||
|
Or use `STASH_ENCRYPTION_PASSPHRASE_COMMAND` to execute a command that returns
|
||||||
|
the passphrase. This works well with password managers:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export STASH_ENCRYPTION_PASSPHRASE_COMMAND="pass show stash/encryption-key"
|
||||||
|
```
|
||||||
|
|
||||||
|
The safest option is using **Systemd LoadCredential**. If Stash is running as a
|
||||||
|
Systemd service, you can provide the passphrase using a credential file:
|
||||||
|
|
||||||
|
```dosini
|
||||||
|
LoadCredential=stash_encryption_passphrase:/etc/stash/encryption_passphrase
|
||||||
|
```
|
||||||
|
|
||||||
|
This is done automatically in the
|
||||||
|
[vendored Systemd service](./contrib/stash.service).
|
||||||
|
|
||||||
|
> [!TIP]
|
||||||
|
> When using encryption, make sure to back up your passphrase. Without it, you
|
||||||
|
> will not be able to recover encrypted entries.
|
||||||
|
|
||||||
### Entry Expiration
|
### Entry Expiration
|
||||||
|
|
||||||
Stash supports time-to-live (TTL) for clipboard entries. When an entry's
|
Stash supports time-to-live (TTL) for clipboard entries. When an entry's
|
||||||
|
|
|
||||||
177
src/db/mod.rs
177
src/db/mod.rs
|
|
@ -215,12 +215,18 @@ pub enum StashError {
|
||||||
QueryDelete(Box<str>),
|
QueryDelete(Box<str>),
|
||||||
#[error("Failed to delete entry with id {0}: {1}")]
|
#[error("Failed to delete entry with id {0}: {1}")]
|
||||||
DeleteEntry(i64, Box<str>),
|
DeleteEntry(i64, Box<str>),
|
||||||
|
|
||||||
|
#[error("Encryption error: {0}")]
|
||||||
|
Encryption(Box<str>),
|
||||||
|
#[error("Decryption error: {0}")]
|
||||||
|
Decryption(Box<str>),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ClipboardDb {
|
pub trait ClipboardDb {
|
||||||
/// Store a new clipboard entry.
|
/// Store a new clipboard entry.
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
|
///
|
||||||
/// * `input` - Reader for the clipboard content
|
/// * `input` - Reader for the clipboard content
|
||||||
/// * `max_dedupe_search` - Maximum number of recent entries to check for
|
/// * `max_dedupe_search` - Maximum number of recent entries to check for
|
||||||
/// duplicates
|
/// duplicates
|
||||||
|
|
@ -595,11 +601,24 @@ impl SqliteClipboardDb {
|
||||||
.get(2)
|
.get(2)
|
||||||
.map_err(|e| StashError::ListDecode(e.to_string().into()))?;
|
.map_err(|e| StashError::ListDecode(e.to_string().into()))?;
|
||||||
|
|
||||||
|
let decrypted_contents = if contents.starts_with(b"age-encryption.org/v1")
|
||||||
|
{
|
||||||
|
match decrypt_data(&contents) {
|
||||||
|
Ok(decrypted) => decrypted,
|
||||||
|
Err(e) => {
|
||||||
|
warn!("skipping entry {id}: decryption failed: {e}");
|
||||||
|
continue;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
contents
|
||||||
|
};
|
||||||
|
|
||||||
let contents_str = match mime.as_deref() {
|
let contents_str = match mime.as_deref() {
|
||||||
Some(m) if m.starts_with("text/") || m == "application/json" => {
|
Some(m) if m.starts_with("text/") || m == "application/json" => {
|
||||||
String::from_utf8_lossy(&contents).into_owned()
|
String::from_utf8_lossy(&decrypted_contents).into_owned()
|
||||||
},
|
},
|
||||||
_ => base64::prelude::BASE64_STANDARD.encode(&contents),
|
_ => base64::prelude::BASE64_STANDARD.encode(&decrypted_contents),
|
||||||
};
|
};
|
||||||
entries.push(serde_json::json!({
|
entries.push(serde_json::json!({
|
||||||
"id": id,
|
"id": id,
|
||||||
|
|
@ -689,13 +708,22 @@ impl ClipboardDb for SqliteClipboardDb {
|
||||||
None => None,
|
None => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let encrypted_buf = if load_encryption_passphrase().is_some() {
|
||||||
|
Some(encrypt_data(&buf)?)
|
||||||
|
} else {
|
||||||
|
debug!("No encryption passphrase configured, storing entry unencrypted");
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
let contents_to_store = encrypted_buf.unwrap_or(buf);
|
||||||
|
|
||||||
self
|
self
|
||||||
.conn
|
.conn
|
||||||
.execute(
|
.execute(
|
||||||
"INSERT INTO clipboard (contents, mime, content_hash, last_accessed, \
|
"INSERT INTO clipboard (contents, mime, content_hash, last_accessed, \
|
||||||
mime_types) VALUES (?1, ?2, ?3, ?4, ?5)",
|
mime_types) VALUES (?1, ?2, ?3, ?4, ?5)",
|
||||||
params![
|
params![
|
||||||
buf,
|
contents_to_store,
|
||||||
mime,
|
mime,
|
||||||
content_hash,
|
content_hash,
|
||||||
std::time::SystemTime::now()
|
std::time::SystemTime::now()
|
||||||
|
|
@ -837,8 +865,20 @@ impl ClipboardDb for SqliteClipboardDb {
|
||||||
let mime: Option<String> = row
|
let mime: Option<String> = row
|
||||||
.get(2)
|
.get(2)
|
||||||
.map_err(|e| StashError::ListDecode(e.to_string().into()))?;
|
.map_err(|e| StashError::ListDecode(e.to_string().into()))?;
|
||||||
|
let preview_contents = if contents.starts_with(&[0x01u8]) {
|
||||||
|
match decrypt_data(&contents) {
|
||||||
|
Ok(decrypted) => decrypted,
|
||||||
|
Err(e) => {
|
||||||
|
warn!("skipping entry {id}: decryption failed: {e}");
|
||||||
|
continue;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
contents
|
||||||
|
};
|
||||||
|
|
||||||
let preview = preview_entry(&contents, mime.as_deref(), preview_width);
|
let preview =
|
||||||
|
preview_entry(&preview_contents, mime.as_deref(), preview_width);
|
||||||
if writeln!(out, "{id}\t{preview}").is_ok() {
|
if writeln!(out, "{id}\t{preview}").is_ok() {
|
||||||
listed += 1;
|
listed += 1;
|
||||||
}
|
}
|
||||||
|
|
@ -872,8 +912,15 @@ impl ClipboardDb for SqliteClipboardDb {
|
||||||
|row| Ok((row.get(0)?, row.get(1)?)),
|
|row| Ok((row.get(0)?, row.get(1)?)),
|
||||||
)
|
)
|
||||||
.map_err(|e| StashError::DecodeGet(e.to_string().into()))?;
|
.map_err(|e| StashError::DecodeGet(e.to_string().into()))?;
|
||||||
|
|
||||||
|
let decrypted_contents = if contents.starts_with(&[0x01u8]) {
|
||||||
|
decrypt_data(&contents)?
|
||||||
|
} else {
|
||||||
|
contents
|
||||||
|
};
|
||||||
|
|
||||||
out
|
out
|
||||||
.write_all(&contents)
|
.write_all(&decrypted_contents)
|
||||||
.map_err(|e| StashError::DecodeWrite(e.to_string().into()))?;
|
.map_err(|e| StashError::DecodeWrite(e.to_string().into()))?;
|
||||||
log::info!("decoded entry with id {id}");
|
log::info!("decoded entry with id {id}");
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -898,7 +945,23 @@ impl ClipboardDb for SqliteClipboardDb {
|
||||||
let contents: Vec<u8> = row
|
let contents: Vec<u8> = row
|
||||||
.get(1)
|
.get(1)
|
||||||
.map_err(|e| StashError::QueryDelete(e.to_string().into()))?;
|
.map_err(|e| StashError::QueryDelete(e.to_string().into()))?;
|
||||||
if contents.windows(query.len()).any(|w| w == query.as_bytes()) {
|
|
||||||
|
let searchable_contents = if contents.starts_with(&[0x01u8]) {
|
||||||
|
match decrypt_data(&contents) {
|
||||||
|
Ok(decrypted) => decrypted,
|
||||||
|
Err(e) => {
|
||||||
|
warn!("skipping entry {id}: decryption failed: {e}");
|
||||||
|
continue;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
contents
|
||||||
|
};
|
||||||
|
|
||||||
|
if searchable_contents
|
||||||
|
.windows(query.len())
|
||||||
|
.any(|w| w == query.as_bytes())
|
||||||
|
{
|
||||||
self
|
self
|
||||||
.conn
|
.conn
|
||||||
.execute("DELETE FROM clipboard WHERE id = ?1", params![id])
|
.execute("DELETE FROM clipboard WHERE id = ?1", params![id])
|
||||||
|
|
@ -963,7 +1026,13 @@ impl ClipboardDb for SqliteClipboardDb {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok((id, contents, mime))
|
let decrypted_contents = if contents.starts_with(&[0x01u8]) {
|
||||||
|
decrypt_data(&contents)?
|
||||||
|
} else {
|
||||||
|
contents
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok((id, decrypted_contents, mime))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1038,7 +1107,20 @@ impl SqliteClipboardDb {
|
||||||
let mime: Option<String> = row
|
let mime: Option<String> = row
|
||||||
.get(2)
|
.get(2)
|
||||||
.map_err(|e| StashError::ListDecode(e.to_string().into()))?;
|
.map_err(|e| StashError::ListDecode(e.to_string().into()))?;
|
||||||
let preview = preview_entry(&contents, mime.as_deref(), preview_width);
|
let decrypted_contents = if contents.starts_with(&[0x01u8]) {
|
||||||
|
match decrypt_data(&contents) {
|
||||||
|
Ok(decrypted) => decrypted,
|
||||||
|
Err(e) => {
|
||||||
|
warn!("skipping entry {id}: decryption failed: {e}");
|
||||||
|
continue;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
contents
|
||||||
|
};
|
||||||
|
|
||||||
|
let preview =
|
||||||
|
preview_entry(&decrypted_contents, mime.as_deref(), preview_width);
|
||||||
let mime_str = mime.unwrap_or_default();
|
let mime_str = mime.unwrap_or_default();
|
||||||
window.push((id, preview, mime_str));
|
window.push((id, preview, mime_str));
|
||||||
}
|
}
|
||||||
|
|
@ -1155,10 +1237,23 @@ impl SqliteClipboardDb {
|
||||||
/// changes made after daemon startup. Regex compilation is cached by
|
/// changes made after daemon startup. Regex compilation is cached by
|
||||||
/// pattern to avoid recompilation.
|
/// pattern to avoid recompilation.
|
||||||
fn load_sensitive_regex() -> Option<Regex> {
|
fn load_sensitive_regex() -> Option<Regex> {
|
||||||
|
use std::process::Command;
|
||||||
|
|
||||||
// Get the current pattern from env vars
|
// Get the current pattern from env vars
|
||||||
let pattern = if let Ok(regex_path) = env::var("CREDENTIALS_DIRECTORY") {
|
let pattern = if let Ok(cred_dir) = env::var("CREDENTIALS_DIRECTORY") {
|
||||||
let file = format!("{regex_path}/clipboard_filter");
|
let file = format!("{cred_dir}/clipboard_filter");
|
||||||
fs::read_to_string(&file).ok().map(|s| s.trim().to_string())
|
fs::read_to_string(&file).ok().map(|s| s.trim().to_string())
|
||||||
|
} else if let Ok(cmd) = env::var("STASH_SENSITIVE_REGEX_COMMAND") {
|
||||||
|
Command::new("sh")
|
||||||
|
.args(["-c", &cmd])
|
||||||
|
.output()
|
||||||
|
.ok()
|
||||||
|
.filter(|o| o.status.success())
|
||||||
|
.map(|o| String::from_utf8_lossy(&o.stdout).trim().to_string())
|
||||||
|
} else if let Ok(file_path) = env::var("STASH_SENSITIVE_REGEX_FILE") {
|
||||||
|
fs::read_to_string(&file_path)
|
||||||
|
.ok()
|
||||||
|
.map(|s| s.trim().to_string())
|
||||||
} else {
|
} else {
|
||||||
env::var("STASH_SENSITIVE_REGEX").ok()
|
env::var("STASH_SENSITIVE_REGEX").ok()
|
||||||
}?;
|
}?;
|
||||||
|
|
@ -1185,6 +1280,68 @@ fn load_sensitive_regex() -> Option<Regex> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn load_encryption_passphrase() -> Option<age::secrecy::SecretString> {
|
||||||
|
use std::process::Command;
|
||||||
|
|
||||||
|
static PASSPHRASE_CACHE: OnceLock<age::secrecy::SecretString> =
|
||||||
|
OnceLock::new();
|
||||||
|
|
||||||
|
if let Some(cached) = PASSPHRASE_CACHE.get() {
|
||||||
|
return Some(cached.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
let passphrase = if let Ok(cred_dir) = env::var("CREDENTIALS_DIRECTORY") {
|
||||||
|
let file = format!("{cred_dir}/stash_encryption_passphrase");
|
||||||
|
fs::read_to_string(&file).ok().map(|s| s.trim().to_owned())
|
||||||
|
} else if let Ok(cmd) = env::var("STASH_ENCRYPTION_PASSPHRASE_COMMAND") {
|
||||||
|
Command::new("sh")
|
||||||
|
.args(["-c", &cmd])
|
||||||
|
.output()
|
||||||
|
.ok()
|
||||||
|
.filter(|o| o.status.success())
|
||||||
|
.map(|o| String::from_utf8_lossy(&o.stdout).trim().to_owned())
|
||||||
|
} else if let Ok(file_path) = env::var("STASH_ENCRYPTION_PASSPHRASE_FILE") {
|
||||||
|
fs::read_to_string(&file_path)
|
||||||
|
.ok()
|
||||||
|
.map(|s| s.trim().to_owned())
|
||||||
|
} else {
|
||||||
|
env::var("STASH_ENCRYPTION_PASSPHRASE").ok()
|
||||||
|
}?;
|
||||||
|
|
||||||
|
let secret = age::secrecy::SecretString::from(passphrase);
|
||||||
|
let _ = PASSPHRASE_CACHE.set(secret.clone());
|
||||||
|
Some(secret)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn encrypt_data(data: &[u8]) -> Result<Vec<u8>, StashError> {
|
||||||
|
let passphrase = load_encryption_passphrase().ok_or_else(|| {
|
||||||
|
StashError::Encryption("No encryption passphrase configured".into())
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let recipient = age::scrypt::Recipient::new(passphrase);
|
||||||
|
let encrypted = age::encrypt(&recipient, data)
|
||||||
|
.map_err(|e| StashError::Encryption(e.to_string().into()))?;
|
||||||
|
// Prepend marker byte to identify our encrypted data
|
||||||
|
let mut result = Vec::with_capacity(1 + encrypted.len());
|
||||||
|
result.push(0x01u8);
|
||||||
|
result.extend_from_slice(&encrypted);
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn decrypt_data(encrypted: &[u8]) -> Result<Vec<u8>, StashError> {
|
||||||
|
let passphrase = load_encryption_passphrase().ok_or_else(|| {
|
||||||
|
StashError::Decryption("No encryption passphrase configured".into())
|
||||||
|
})?;
|
||||||
|
|
||||||
|
// Strip our marker byte if present
|
||||||
|
let data_to_decrypt = encrypted.strip_prefix(&[0x01u8]).unwrap_or(encrypted);
|
||||||
|
|
||||||
|
let identity = age::scrypt::Identity::new(passphrase);
|
||||||
|
let decrypted = age::decrypt(&identity, data_to_decrypt)
|
||||||
|
.map_err(|e| StashError::Decryption(e.to_string().into()))?;
|
||||||
|
Ok(decrypted)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn extract_id(input: &str) -> Result<i64, &'static str> {
|
pub fn extract_id(input: &str) -> Result<i64, &'static str> {
|
||||||
let id_str = input.split('\t').next().unwrap_or("");
|
let id_str = input.split('\t').next().unwrap_or("");
|
||||||
id_str.parse().map_err(|_| "invalid id")
|
id_str.parse().map_err(|_| "invalid id")
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue