diff --git a/Cargo.lock b/Cargo.lock index 80c83dd..2cd2b65 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -72,6 +72,15 @@ dependencies = [ "url", ] +[[package]] +name = "android_system_properties" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae221649c9976a6f6c56ae1facf410f3ddb33cc661c4b7b61020a912d4237fbc" +dependencies = [ + "libc", +] + [[package]] name = "anyhow" version = "1.0.103" @@ -108,7 +117,7 @@ checksum = "3109e49b1e4909e9db6515a30c633684d68cdeaa252f215214cb4fa1a5bfee2c" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.119", "synstructure", ] @@ -120,7 +129,7 @@ checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.119", ] [[package]] @@ -217,7 +226,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.119", ] [[package]] @@ -331,6 +340,12 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "base64" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac07cdecf99051d9a5238b80f35af32cdeba5b336e55d957b318b50137e18da5" + [[package]] name = "base64ct" version = "1.8.3" @@ -407,6 +422,12 @@ dependencies = [ "serde", ] +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + [[package]] name = "bitflags" version = "2.13.0" @@ -422,6 +443,15 @@ dependencies = [ "generic-array", ] +[[package]] +name = "block-buffer" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa" +dependencies = [ + "hybrid-array", +] + [[package]] name = "block-padding" version = "0.3.3" @@ -444,6 +474,15 @@ dependencies = [ "piper", ] +[[package]] +name = "bs58" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" +dependencies = [ + "tinyvec", +] + [[package]] name = "bumpalo" version = "3.20.3" @@ -455,6 +494,9 @@ name = "bytes" version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04" +dependencies = [ + "serde", +] [[package]] name = "cbc" @@ -483,6 +525,12 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" +[[package]] +name = "cfg_aliases" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f079e83a288787bcd14a6aea84cee5c87a67c5a3e660c30f557a3d24761b3527" + [[package]] name = "chacha20" version = "0.10.1" @@ -491,7 +539,19 @@ checksum = "d524456ba66e72eb8b115ff89e01e497f8e6d11d78b70b1aa13c0fbd97540a81" dependencies = [ "cfg-if", "cpufeatures 0.3.0", - "rand_core", + "rand_core 0.10.1", +] + +[[package]] +name = "chrono" +version = "0.4.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327" +dependencies = [ + "iana-time-zone", + "num-traits", + "serde", + "windows-link", ] [[package]] @@ -500,7 +560,7 @@ version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" dependencies = [ - "crypto-common", + "crypto-common 0.1.7", "inout", ] @@ -550,6 +610,12 @@ dependencies = [ "cc", ] +[[package]] +name = "cmov" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c9ea0ac24bc397ab3c98583a3c9ba74fa56b09a4449bbe172b9b1ddb016027a" + [[package]] name = "cms" version = "0.2.3" @@ -649,6 +715,15 @@ dependencies = [ "libc", ] +[[package]] +name = "crc32c" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a47af21622d091a8f0fb295b88bc886ac74efcc613efc19f5d0b21de5c89e47" +dependencies = [ + "rustc_version", +] + [[package]] name = "critical-section" version = "1.2.0" @@ -689,12 +764,95 @@ dependencies = [ "typenum", ] +[[package]] +name = "crypto-common" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453" +dependencies = [ + "hybrid-array", +] + +[[package]] +name = "ctutils" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d5515a3834141de9eafb9717ad39eea8247b5674e6066c404e8c4b365d2a29e" +dependencies = [ + "cmov", +] + +[[package]] +name = "darling" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9865a50f7c335f53564bb694ef660825eb8610e0a53d3e11bf1b0d3df31e03b0" +dependencies = [ + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.119", +] + +[[package]] +name = "darling_macro" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.119", +] + [[package]] name = "data-encoding" version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4ae5f15dda3c708c0ade84bfee31ccab44a3da4f88015ed22f63732abe300c8" +[[package]] +name = "defmt" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2953bfe4f93bbd20cc71198842756f77d161884c99ebbabc41d80231ded88d1" +dependencies = [ + "bitflags 1.3.2", + "defmt-macros", +] + +[[package]] +name = "defmt-macros" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bad9c72e7ca2137e0dc3813245a0d282fd6daad32fd800af018306a9169b5fe8" +dependencies = [ + "defmt-parser", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "defmt-parser" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10d60334b3b2e7c9d91ef8150abfb6fa4c1c39ebbcf4a81c2e346aad939fee3e" +dependencies = [ + "thiserror 2.0.18", +] + [[package]] name = "der" version = "0.7.10" @@ -730,7 +888,7 @@ checksum = "8034092389675178f570469e6c3b0465d3d30b4505c294a6550db47f3c17ad18" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.119", ] [[package]] @@ -738,6 +896,9 @@ name = "deranged" version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" +dependencies = [ + "serde_core", +] [[package]] name = "des" @@ -754,11 +915,22 @@ version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer", - "crypto-common", + "block-buffer 0.10.4", + "crypto-common 0.1.7", "subtle", ] +[[package]] +name = "digest" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" +dependencies = [ + "block-buffer 0.12.1", + "crypto-common 0.2.2", + "ctutils", +] + [[package]] name = "displaydoc" version = "0.2.6" @@ -767,7 +939,7 @@ checksum = "1ac70aa55017e108007fbaf5aa0f54b021c98f92ff8af59d42eda9da96e3dd4f" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.119", ] [[package]] @@ -776,6 +948,12 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" +[[package]] +name = "dyn-clone" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" + [[package]] name = "either" version = "1.16.0" @@ -854,7 +1032,7 @@ checksum = "ee93edf3c501f0035bbeffeccfed0b79e14c311f12195ec0e661e114a0f60da4" dependencies = [ "futures", "portable-atomic", - "rand", + "rand 0.10.2", "tokio", "web-time", ] @@ -984,7 +1162,7 @@ checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.119", ] [[package]] @@ -1044,8 +1222,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" dependencies = [ "cfg-if", + "js-sys", "libc", "wasi", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi 5.3.0", + "wasip2", ] [[package]] @@ -1055,9 +1247,231 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" dependencies = [ "cfg-if", + "js-sys", "libc", - "r-efi", - "rand_core", + "r-efi 6.0.0", + "rand_core 0.10.1", + "wasm-bindgen", +] + +[[package]] +name = "google-cloud-auth" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff461519b1a948200f163574be072753bcfb462a323f0eb426629d89872dd685" +dependencies = [ + "async-trait", + "base64 0.23.1", + "bytes", + "google-cloud-gax", + "hex", + "hmac 0.13.0", + "http", + "jiff", + "reqwest", + "rustc_version", + "rustls", + "rustls-pki-types", + "serde", + "serde_json", + "sha2 0.11.0", + "thiserror 2.0.18", + "time", + "tokio", + "url", +] + +[[package]] +name = "google-cloud-gax" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5615cff28ee59cfe52fbb4c11b8b1e77f650296e2ea4f4c2b7757ac6b19e752" +dependencies = [ + "bytes", + "futures", + "google-cloud-rpc", + "google-cloud-wkt", + "http", + "pin-project", + "rand 0.10.2", + "serde", + "serde_json", + "thiserror 2.0.18", + "tokio", + "tokio-stream", +] + +[[package]] +name = "google-cloud-gax-internal" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2766757d877a7a8ac23da9884cb0e3f10ed9b75a0ce59801ce6b19bf9d5819e" +dependencies = [ + "bytes", + "futures", + "google-cloud-auth", + "google-cloud-gax", + "google-cloud-rpc", + "google-cloud-wkt", + "h2", + "http", + "http-body", + "http-body-util", + "hyper", + "lazy_static", + "opentelemetry", + "opentelemetry-semantic-conventions", + "opentelemetry_sdk", + "percent-encoding", + "pin-project", + "prost", + "prost-types", + "reqwest", + "rustc_version", + "serde", + "serde_json", + "thiserror 2.0.18", + "tokio", + "tokio-stream", + "tonic", + "tonic-prost", + "tower", + "tracing", + "tracing-opentelemetry", +] + +[[package]] +name = "google-cloud-iam-v1" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f962b40234b1531e6ef73f7558871c96e117231e962086c98804323fb8d2c82" +dependencies = [ + "async-trait", + "bytes", + "google-cloud-gax", + "google-cloud-gax-internal", + "google-cloud-type", + "google-cloud-wkt", + "serde", + "serde_json", + "serde_with", + "tracing", +] + +[[package]] +name = "google-cloud-longrunning" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c0363c5389ffda2b55cd8a86eef4b19a3481a48467c91dc5d77f626a9572766" +dependencies = [ + "async-trait", + "bytes", + "google-cloud-gax", + "google-cloud-gax-internal", + "google-cloud-rpc", + "google-cloud-wkt", + "serde", + "serde_json", + "serde_with", + "tracing", +] + +[[package]] +name = "google-cloud-lro" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47af3deef75c14a2983c430898d960c765bddbcc9f9188ca0563108e9227cfe7" +dependencies = [ + "google-cloud-gax", + "google-cloud-gax-internal", + "google-cloud-longrunning", + "google-cloud-rpc", + "google-cloud-wkt", + "serde", + "tokio", + "tracing", +] + +[[package]] +name = "google-cloud-rpc" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2162c08a89118130979ba261080e960e44cdcb2d6e2ab8ca9b1da245285d353" +dependencies = [ + "bytes", + "google-cloud-wkt", + "serde", + "serde_json", + "serde_with", +] + +[[package]] +name = "google-cloud-storage" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "973399251b245c63f1d02d0768772833dcf1372ee358f593fb9159de8fe9c7d4" +dependencies = [ + "async-trait", + "base64 0.23.1", + "bytes", + "crc32c", + "futures", + "google-cloud-auth", + "google-cloud-gax", + "google-cloud-gax-internal", + "google-cloud-iam-v1", + "google-cloud-longrunning", + "google-cloud-lro", + "google-cloud-rpc", + "google-cloud-type", + "google-cloud-wkt", + "hex", + "http", + "http-body", + "jiff", + "md5", + "percent-encoding", + "prost", + "prost-types", + "serde", + "serde_json", + "serde_with", + "sha2 0.11.0", + "thiserror 2.0.18", + "tokio", + "tokio-stream", + "tracing", + "url", + "uuid", +] + +[[package]] +name = "google-cloud-type" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63acc3a92a85f96bab021c3a3e29b53bbacc97651e1b524d4c2991960a63eb82" +dependencies = [ + "bytes", + "google-cloud-wkt", + "serde", + "serde_json", + "serde_with", +] + +[[package]] +name = "google-cloud-wkt" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fccf98cfd5481a5f5a285181ab0c62123d7d47cd2bb7299448440649349e4e7" +dependencies = [ + "base64 0.22.1", + "bytes", + "serde", + "serde_json", + "serde_with", + "thiserror 2.0.18", + "time", + "url", ] [[package]] @@ -1072,13 +1486,19 @@ dependencies = [ "futures-core", "futures-sink", "http", - "indexmap", + "indexmap 2.14.0", "slab", "tokio", "tokio-util", "tracing", ] +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + [[package]] name = "hashbrown" version = "0.15.5" @@ -1146,7 +1566,7 @@ dependencies = [ "idna", "ipnet", "jni", - "rand", + "rand 0.10.2", "thiserror 2.0.18", "tinyvec", "tokio", @@ -1166,7 +1586,7 @@ dependencies = [ "jni", "once_cell", "prefix-trie", - "rand", + "rand 0.10.2", "ring", "thiserror 2.0.18", "tinyvec", @@ -1191,7 +1611,7 @@ dependencies = [ "ndk-context", "once_cell", "parking_lot", - "rand", + "rand 0.10.2", "resolv-conf", "smallvec", "system-configuration", @@ -1206,7 +1626,16 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ - "digest", + "digest 0.10.7", +] + +[[package]] +name = "hmac" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6303bc9732ae41b04cb554b844a762b4115a61bfaa81e3e83050991eeb56863f" +dependencies = [ + "digest 0.11.3", ] [[package]] @@ -1254,6 +1683,15 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" +[[package]] +name = "hybrid-array" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "707114b52a152fa7bdb290cd7cd5912d9467273b6d74e21b8d81aca1f8533f6b" +dependencies = [ + "typenum", +] + [[package]] name = "hyper" version = "1.10.1" @@ -1276,6 +1714,21 @@ dependencies = [ "want", ] +[[package]] +name = "hyper-rustls" +version = "0.27.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ca68d021ef39cf6463ab54c1d0f5daf03377b70561305bb89a8f83aab66e0f" +dependencies = [ + "http", + "hyper", + "hyper-util", + "rustls", + "tokio", + "tokio-rustls", + "tower-service", +] + [[package]] name = "hyper-timeout" version = "0.5.2" @@ -1295,13 +1748,16 @@ version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" dependencies = [ + "base64 0.22.1", "bytes", "futures-channel", "futures-util", "http", "http-body", "hyper", + "ipnet", "libc", + "percent-encoding", "pin-project-lite", "socket2", "tokio", @@ -1309,6 +1765,30 @@ dependencies = [ "tracing", ] +[[package]] +name = "iana-time-zone" +version = "0.1.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + [[package]] name = "icu_collections" version = "2.2.0" @@ -1391,6 +1871,12 @@ dependencies = [ "zerovec", ] +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + [[package]] name = "idna" version = "1.1.0" @@ -1412,6 +1898,17 @@ dependencies = [ "icu_properties", ] +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", + "serde", +] + [[package]] name = "indexmap" version = "2.14.0" @@ -1420,6 +1917,8 @@ checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" dependencies = [ "equivalent", "hashbrown 0.17.1", + "serde", + "serde_core", ] [[package]] @@ -1469,6 +1968,59 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" +[[package]] +name = "jiff" +version = "0.2.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "668b7183bd07af9a4885f5c35b0cc5c83c4607a913c16b7e17291832910d2dcc" +dependencies = [ + "defmt", + "jiff-core", + "jiff-static", + "jiff-tzdb-platform", + "log", + "portable-atomic", + "portable-atomic-util", + "serde_core", + "windows-link", +] + +[[package]] +name = "jiff-core" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7feca88439efe53da3754500c1851dedf3cb36c524dd5cf8225cc0794de95d09" +dependencies = [ + "defmt", +] + +[[package]] +name = "jiff-static" +version = "0.2.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a69dcb3a21cfb32ce1cd056169337ca284af0766dd766e7878819b251a49204" +dependencies = [ + "jiff-core", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "jiff-tzdb" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "142bd39932ad231f10513df9ab62661fead8719872150b7ad02a2df79f4e141e" + +[[package]] +name = "jiff-tzdb-platform" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "875a5a69ac2bab1a891711cf5eccbec1ce0341ea805560dcd90b7a2e925132e8" +dependencies = [ + "jiff-tzdb", +] + [[package]] name = "jni" version = "0.22.4" @@ -1496,7 +2048,7 @@ dependencies = [ "quote", "rustc_version", "simd_cesu8", - "syn", + "syn 2.0.119", ] [[package]] @@ -1515,7 +2067,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264" dependencies = [ "quote", - "syn", + "syn 2.0.119", ] [[package]] @@ -1596,6 +2148,12 @@ version = "0.4.33" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad" +[[package]] +name = "lru-slab" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" + [[package]] name = "matchers" version = "0.2.0" @@ -1611,6 +2169,12 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" +[[package]] +name = "md5" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ebb8d8732c6a6df3d8f032a82911cfc747e00efb95cc46e8d0acd5b5b88570c" + [[package]] name = "memchr" version = "2.8.3" @@ -1638,6 +2202,16 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +[[package]] +name = "mime_guess" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" +dependencies = [ + "mime", + "unicase", +] + [[package]] name = "minimal-lexical" version = "0.2.1" @@ -1771,25 +2345,61 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" +[[package]] +name = "opentelemetry" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0142c63252a9e054e68a4c61a5778f7b14f576274d593f8ce883d191a099682" +dependencies = [ + "futures-core", + "futures-sink", + "js-sys", + "pin-project-lite", + "thiserror 2.0.18", + "tracing", +] + +[[package]] +name = "opentelemetry-semantic-conventions" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c913ac17a6c451661ee255f4625d143e51647ae78ebd969b75e41c4442f4fe47" + +[[package]] +name = "opentelemetry_sdk" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b59f80e1ac4d5ff7a2db8fb6c80badb7f0f3f858211fba08dd9aaec750894f9" +dependencies = [ + "futures-channel", + "futures-executor", + "futures-util", + "opentelemetry", + "percent-encoding", + "portable-atomic", + "rand 0.9.5", + "thiserror 2.0.18", +] + [[package]] name = "p12-keystore" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffb9bf5222606eb712d3bb30e01bc9420545b00859970897e70c682353a034f2" dependencies = [ - "base64", + "base64 0.22.1", "cbc", "cms", "der", "des", "hex", - "hmac", + "hmac 0.12.1", "pkcs12", "pkcs5", - "rand", + "rand 0.10.2", "rc2", "sha1", - "sha2", + "sha2 0.10.9", "thiserror 2.0.18", "x509-parser", ] @@ -1835,8 +2445,8 @@ version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" dependencies = [ - "digest", - "hmac", + "digest 0.10.7", + "hmac 0.12.1", ] [[package]] @@ -1862,7 +2472,7 @@ checksum = "8701b58ea97060d5e5b155d383a69952a60943f0e6dfe30b04c287beb0b27455" dependencies = [ "fixedbitset", "hashbrown 0.15.5", - "indexmap", + "indexmap 2.14.0", ] [[package]] @@ -1882,7 +2492,7 @@ checksum = "c96395f0a926bc13b1c17622aaddda1ecb55d49c8f1bf9777e4d877800a43f8b" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.119", ] [[package]] @@ -1911,7 +2521,7 @@ dependencies = [ "cms", "const-oid", "der", - "digest", + "digest 0.10.7", "spki", "x509-cert", "zeroize", @@ -1928,7 +2538,7 @@ dependencies = [ "der", "pbkdf2", "scrypt", - "sha2", + "sha2 0.10.9", "spki", ] @@ -1944,6 +2554,15 @@ version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" +[[package]] +name = "portable-atomic-util" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a106d1259c23fac8e543272398ae0e3c0b8d33c88ed73d0cc71b0f1d902618" +dependencies = [ + "portable-atomic", +] + [[package]] name = "potential_utf" version = "0.1.5" @@ -1959,6 +2578,15 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" 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]] name = "prefix-trie" version = "0.8.4" @@ -1977,7 +2605,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" dependencies = [ "proc-macro2", - "syn", + "syn 2.0.119", ] [[package]] @@ -2031,7 +2659,7 @@ dependencies = [ "pulldown-cmark", "pulldown-cmark-to-cmark", "regex", - "syn", + "syn 2.0.119", "tempfile", ] @@ -2045,7 +2673,7 @@ dependencies = [ "itertools", "proc-macro2", "quote", - "syn", + "syn 2.0.119", ] [[package]] @@ -2083,7 +2711,7 @@ version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e9f068eba8e7071c5f9511831b44f32c740d5adf574e990f946ddb53db2f314e" dependencies = [ - "bitflags", + "bitflags 2.13.0", "memchr", "unicase", ] @@ -2097,6 +2725,63 @@ dependencies = [ "pulldown-cmark", ] +[[package]] +name = "quinn" +version = "0.11.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c1a41e437b6bbd489372cd4971de128e85c855f56c57f283d20ff016cf7c0a8" +dependencies = [ + "bytes", + "cfg_aliases", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash", + "rustls", + "socket2", + "thiserror 2.0.18", + "tokio", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-proto" +version = "0.11.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04759210543be93709136e28212294a659ef5001836ff4eab4d663e4529bba83" +dependencies = [ + "aws-lc-rs", + "bytes", + "getrandom 0.4.3", + "lru-slab", + "rand 0.10.2", + "rand_pcg", + "ring", + "rustc-hash", + "rustls", + "rustls-pki-types", + "slab", + "thiserror 2.0.18", + "tinyvec", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-udp" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35a133f956daabe89a61a685c2649f13d82d5aa4bd5d12d1277e1072a21c0694" +dependencies = [ + "cfg_aliases", + "libc", + "once_cell", + "socket2", + "tracing", + "windows-sys 0.61.2", +] + [[package]] name = "quote" version = "1.0.46" @@ -2106,12 +2791,28 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + [[package]] name = "r-efi" version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" +[[package]] +name = "rand" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9ef1d0d795eb7d84685bca4f72f3649f064e6641543d3a8c415898726a57b41" +dependencies = [ + "rand_chacha", + "rand_core 0.9.5", +] + [[package]] name = "rand" version = "0.10.2" @@ -2120,7 +2821,26 @@ checksum = "c7f5fa3a058cd35567ef9bfa5e75732bee0f9e4c55fa90477bef2dfcdbc4be80" dependencies = [ "chacha20", "getrandom 0.4.3", - "rand_core", + "rand_core 0.10.1", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.5", +] + +[[package]] +name = "rand_core" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" +dependencies = [ + "getrandom 0.3.4", ] [[package]] @@ -2129,6 +2849,15 @@ version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" +[[package]] +name = "rand_pcg" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caa0f4137e1c0a72f4c651489402276c8e8e1cf081f3b0ba156d2cbeef09e86a" +dependencies = [ + "rand_core 0.10.1", +] + [[package]] name = "rc2" version = "0.8.1" @@ -2144,7 +2873,27 @@ version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags", + "bitflags 2.13.0", +] + +[[package]] +name = "ref-cast" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e440fb4e4b4147295338efb76001ab9e4efc0e5839df2c47fc5ac2381d365c3" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92ecd8964f8453721699a1ed72037b0db49ce2f5a5138486ee89bed6f67cdf3a" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.4", ] [[package]] @@ -2176,6 +2925,48 @@ version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" +[[package]] +name = "reqwest" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "219c5811de6525e5416c7d5d53bb656d3afdbc6c5af816e0802bcfa42dbdc1c3" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures-core", + "futures-util", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-rustls", + "hyper-util", + "js-sys", + "log", + "mime_guess", + "percent-encoding", + "pin-project-lite", + "quinn", + "rustls", + "rustls-pki-types", + "rustls-platform-verifier", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tokio-rustls", + "tokio-util", + "tower", + "tower-http", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-streams", + "web-sys", +] + [[package]] name = "resolv-conf" version = "0.7.6" @@ -2196,6 +2987,29 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "rpc-log-plugin" +version = "0.1.0" +dependencies = [ + "anyhow", + "base64 0.23.1", + "cln-plugin", + "cln-rpc", + "google-cloud-auth", + "google-cloud-storage", + "serde", + "serde_json", + "time", + "tokio", + "uuid", +] + +[[package]] +name = "rustc-hash" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d" + [[package]] name = "rustc_version" version = "0.4.1" @@ -2220,7 +3034,7 @@ version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" dependencies = [ - "bitflags", + "bitflags 2.13.0", "errno", "libc", "linux-raw-sys", @@ -2234,6 +3048,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c54fcab019b409d04215d3a17cb438fd7fbf192ee61461f20f4fe18704bc138" dependencies = [ "aws-lc-rs", + "log", "once_cell", "rustls-pki-types", "rustls-webpki", @@ -2274,6 +3089,7 @@ version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "764899a24af3980067ee14bc143654f297b22eaebfe3c7b6b211920a5a59b046" dependencies = [ + "web-time", "zeroize", ] @@ -2355,6 +3171,30 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "schemars" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd191f9397d57d581cddd31014772520aa448f65ef991055d7f61582c65165f" +dependencies = [ + "dyn-clone", + "ref-cast", + "serde", + "serde_json", +] + +[[package]] +name = "schemars" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "687274d293b6cdc6e73e0fee520bf2049650090d7164f87672d212a3c530cf4a" +dependencies = [ + "dyn-clone", + "ref-cast", + "serde", + "serde_json", +] + [[package]] name = "scopeguard" version = "1.2.0" @@ -2369,7 +3209,7 @@ checksum = "0516a385866c09368f0b5bcd1caff3366aace790fcd46e2bb032697bb172fd1f" dependencies = [ "pbkdf2", "salsa20", - "sha2", + "sha2 0.10.9", ] [[package]] @@ -2398,7 +3238,7 @@ version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" dependencies = [ - "bitflags", + "bitflags 2.13.0", "core-foundation 0.10.1", "core-foundation-sys", "libc", @@ -2448,7 +3288,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.119", ] [[package]] @@ -2496,6 +3336,39 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_with" +version = "3.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee78f1fbe43ac4a0e47aadb3dbd357b69eb0d3793e948624cd03dd2750ab1c0a" +dependencies = [ + "base64 0.22.1", + "bs58", + "chrono", + "hex", + "indexmap 1.9.3", + "indexmap 2.14.0", + "jiff", + "schemars 0.9.0", + "schemars 1.2.2", + "serde_core", + "serde_json", + "serde_with_macros", + "time", +] + +[[package]] +name = "serde_with_macros" +version = "3.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8705578779c2b6bd90d84d66eb2e206b708b1a4d7b9f17641b293545bf1c7e46" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.119", +] + [[package]] name = "sha1" version = "0.10.7" @@ -2504,7 +3377,7 @@ checksum = "a978451301f4db1d02937a4ab3ccce137717b81826e79b7d49ffe3244a13c3b8" dependencies = [ "cfg-if", "cpufeatures 0.2.17", - "digest", + "digest 0.10.7", ] [[package]] @@ -2515,7 +3388,18 @@ checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", "cpufeatures 0.2.17", - "digest", + "digest 0.10.7", +] + +[[package]] +name = "sha2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.0", + "digest 0.11.3", ] [[package]] @@ -2606,6 +3490,12 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + [[package]] name = "subtle" version = "2.6.1" @@ -2623,11 +3513,25 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn" +version = "3.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6275cddf4610d1775e6d1fe9469b2e77d0f39fd98fb7450901b821e0c53649f" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "sync_wrapper" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] [[package]] name = "synstructure" @@ -2637,7 +3541,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.119", ] [[package]] @@ -2646,7 +3550,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a13f3d0daba03132c0aa9767f98351b3488edc2c100cda2d2ec2b04f3d8d3c8b" dependencies = [ - "bitflags", + "bitflags 2.13.0", "core-foundation 0.9.4", "system-configuration-sys", ] @@ -2719,7 +3623,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.119", ] [[package]] @@ -2730,7 +3634,7 @@ checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.119", ] [[package]] @@ -2822,7 +3726,17 @@ checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.119", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" +dependencies = [ + "rustls", + "tokio", ] [[package]] @@ -2834,6 +3748,7 @@ dependencies = [ "futures-core", "pin-project-lite", "tokio", + "tokio-util", ] [[package]] @@ -2888,7 +3803,7 @@ checksum = "ac2a5518c70fa84342385732db33fb3f44bc4cc748936eb5833d2df34d6445ef" dependencies = [ "async-trait", "axum", - "base64", + "base64 0.22.1", "bytes", "h2", "http", @@ -2899,9 +3814,11 @@ dependencies = [ "hyper-util", "percent-encoding", "pin-project", + "rustls-native-certs", "socket2", "sync_wrapper", "tokio", + "tokio-rustls", "tokio-stream", "tower", "tower-layer", @@ -2918,7 +3835,18 @@ dependencies = [ "prettyplease", "proc-macro2", "quote", - "syn", + "syn 2.0.119", +] + +[[package]] +name = "tonic-prost" +version = "0.14.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50849f68853be452acf590cde0b146665b8d507b3b8af17261df47e02c209ea0" +dependencies = [ + "bytes", + "prost", + "tonic", ] [[package]] @@ -2932,7 +3860,7 @@ dependencies = [ "prost-build", "prost-types", "quote", - "syn", + "syn 2.0.119", "tempfile", "tonic-build", ] @@ -2945,7 +3873,7 @@ checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" dependencies = [ "futures-core", "futures-util", - "indexmap", + "indexmap 2.14.0", "pin-project-lite", "slab", "sync_wrapper", @@ -2956,6 +3884,24 @@ dependencies = [ "tracing", ] +[[package]] +name = "tower-http" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840" +dependencies = [ + "bitflags 2.13.0", + "bytes", + "futures-util", + "http", + "http-body", + "pin-project-lite", + "tower", + "tower-layer", + "tower-service", + "url", +] + [[package]] name = "tower-layer" version = "0.3.3" @@ -2988,7 +3934,7 @@ checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.119", ] [[package]] @@ -3012,6 +3958,20 @@ dependencies = [ "tracing-core", ] +[[package]] +name = "tracing-opentelemetry" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adbc64cba7137545b8044cb1fe9814f7aacf3c6b5f9b45be8bb5db538befdb26" +dependencies = [ + "js-sys", + "opentelemetry", + "tracing", + "tracing-core", + "tracing-subscriber", + "web-time", +] + [[package]] name = "tracing-subscriber" version = "0.3.23" @@ -3126,6 +4086,15 @@ version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" +[[package]] +name = "wasip2" +version = "1.0.4+wasi-0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487" +dependencies = [ + "wit-bindgen", +] + [[package]] name = "wasm-bindgen" version = "0.2.126" @@ -3139,6 +4108,16 @@ dependencies = [ "wasm-bindgen-shared", ] +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.76" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c62df1340f32221cb9c54d6a27b030e3dba64361d4a95bed55f9aacb44da291d" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "wasm-bindgen-macro" version = "0.2.126" @@ -3158,7 +4137,7 @@ dependencies = [ "bumpalo", "proc-macro2", "quote", - "syn", + "syn 2.0.119", "wasm-bindgen-shared", ] @@ -3171,6 +4150,29 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "wasm-streams" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1ec4f6517c9e11ae630e200b2b65d193279042e28edd4a2cda233e46670bbb" +dependencies = [ + "futures-util", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "web-sys" +version = "0.3.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8622dcb61c0bcc9fffa6938bed81210af2da9a7e4a1a834b2e37a59b6dfb6141" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "web-time" version = "1.1.0" @@ -3205,6 +4207,41 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "windows-core" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + [[package]] name = "windows-link" version = "0.2.1" @@ -3331,6 +4368,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "wit-bindgen" +version = "0.57.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" + [[package]] name = "writeable" version = "0.6.3" @@ -3384,10 +4427,30 @@ checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.119", "synstructure", ] +[[package]] +name = "zerocopy" +version = "0.8.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "556764e583adb45a9f8d413c2a147fa7e8d821e48e12b14fd560b607998b75eb" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2ab42fc20575779bd240faa45f94a74256f755c0fa9e89f0ede20d91d0cdfc1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + [[package]] name = "zerofrom" version = "0.1.8" @@ -3405,7 +4468,7 @@ checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.119", "synstructure", ] @@ -3445,7 +4508,7 @@ checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.119", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index d40d9e4..425d0f1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,7 @@ [workspace] resolver = "3" members = [ + "rpc-log-plugin", "event-plugin", "metrics-plugin" ] diff --git a/README.md b/README.md index 827f92e..1f43ccd 100644 --- a/README.md +++ b/README.md @@ -17,15 +17,16 @@ A growing collection of plugins for [Core Lightning](https://github.com/Elements Running a Core Lightning node often means connecting it to the rest of your infrastructure: monitoring, event pipelines, dashboards, alerts, and more. This repository keeps those integrations small, composable, and open source. -Each plugin lives in its own workspace crate and can be built, configured, and run independently. There are two plugins +Each plugin lives in its own workspace crate and can be built, configured, and run independently. There are three plugins today—and the collection is designed to grow. ## Plugins -| Plugin | What it does | Integrates with | -|--------------------------------------|------------------------------------------------------------------|-----------------| -| [`event-plugin`](./event-plugin) | Publishes CLN events and hook data to a message broker | RabbitMQ | -| [`metrics-plugin`](./metrics-plugin) | Exposes node, funds, liquidity, channel, peer, and event metrics | Prometheus | +| Plugin | What it does | Integrates with | +|--------------------------------------|--------------------------------------------------------------------|----------------------| +| [`event-plugin`](./event-plugin) | Publishes CLN events and hook data to a message broker | RabbitMQ | +| [`metrics-plugin`](./metrics-plugin) | Exposes node, funds, liquidity, channel, peer, and event metrics | Prometheus | +| [`rpc-log-plugin`](./rpc-log-plugin) | Stores selected, sanitized RPC requests as individual JSON objects | Google Cloud Storage | ### Event plugin @@ -45,6 +46,18 @@ Use it as the foundation for dashboards, alerts, and day-to-day node monitoring. [Configuration and metric reference →](./metrics-plugin/README.md) +### RPC log plugin + +Keep a durable audit trail of requests made to your node. The plugin observes selected calls through CLN's +`rpc_command` hook, redacts known sensitive fields, and uploads each request as a separate JSON object to Google Cloud +Storage. + +It logs `checkrune` by default, making it useful for auditing rune-authorized calls received through the commando +plugin. The method list is configurable, and rune comments in the form `operator#Name` can identify callers without +retaining the rune itself. + +[Configuration, security, and bucket setup →](./rpc-log-plugin/README.md) + ## Quick start ### Prerequisites @@ -52,7 +65,7 @@ Use it as the foundation for dashboards, alerts, and day-to-day node monitoring. - A working Core Lightning node - A recent stable Rust toolchain - Protocol Buffers compiler (`protoc`) to build `event-plugin` -- RabbitMQ for `event-plugin`, or Prometheus for `metrics-plugin` +- RabbitMQ for `event-plugin`, Prometheus for `metrics-plugin`, or a Google Cloud Storage bucket for `rpc-log-plugin` ### Build @@ -69,6 +82,7 @@ The executables are created in `target/release/`: ```text target/release/event-plugin target/release/metrics-plugin +target/release/rpc-log-plugin ``` You can also build only the plugin you need: diff --git a/rpc-log-plugin/Cargo.toml b/rpc-log-plugin/Cargo.toml new file mode 100644 index 0000000..fcb9684 --- /dev/null +++ b/rpc-log-plugin/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "rpc-log-plugin" +version = "0.1.0" +edition = "2024" +license.workspace = true + +[dependencies] +cln-plugin = { version = "0.7" } +tokio = { version = "1", features = ["full"] } +anyhow = { version = "1" } +serde = { version = "1", features = ["derive"] } +serde_json = { version = "1" } +cln-rpc = { version = "0.7" } +google-cloud-storage = "1" +google-cloud-auth = { version = "1", default-features = false } +time = { version = "0.3", features = ["formatting"] } +uuid = { version = "1", features = ["v4"] } +base64 = "0.23" \ No newline at end of file diff --git a/rpc-log-plugin/README.md b/rpc-log-plugin/README.md new file mode 100644 index 0000000..2f85bed --- /dev/null +++ b/rpc-log-plugin/README.md @@ -0,0 +1,158 @@ +# RPC Log Plugin + +The `rpc-log-plugin` records Core Lightning RPC requests as JSON objects in Google Cloud Storage. + +It is useful when you need a durable audit trail for debugging, operational analysis, or investigating how a node is +being used. The plugin observes selected calls through the `rpc_command` hook, replaces values of known sensitive +fields with `"***"`, and uploads each request as a separate object. + +Objects are stored under the following prefix: + +```text +rpc/-.json +``` + +The UUID makes every object name unique, so the plugin never needs to overwrite an existing log. + +## Security model + +The plugin recursively redacts named JSON fields whose keys contain one of the configured sensitive terms, including +`rune`, `hsmsecret`, `preimage`, `payment_secret`, `private_key`, `seed`, and `mnemonic`. Matching is +case-insensitive. + +This is a defensive filter, not a complete data-loss-prevention system. In particular, positional RPC parameters do +not contain field names and therefore cannot be identified by the current sanitizer. Unknown plugin RPCs may also use +different names for sensitive values. Review the resulting data before enabling the plugin on a production node. + +For least privilege, grant the plugin only the `roles/storage.objectCreator` role on its bucket. This allows it to +create objects but not read, list, delete, or overwrite them. Bucket creation must be performed separately by a +deployment or administrator identity. + +## Build + +From the repository root: + +```bash +cargo build --release --package rpc-log-plugin +``` + +The executable is created at: + +```text +target/release/rpc-log-plugin +``` + +## Create the bucket + +The following commands must be run with an identity that can create buckets and manage bucket IAM policies: + +```bash +PROJECT_ID="my-project" +BUCKET="my-cln-rpc-logs" +REGION="europe-west1" +WRITER_SA="cln-log-writer@${PROJECT_ID}.iam.gserviceaccount.com" + +gcloud services enable storage.googleapis.com \ + --project="${PROJECT_ID}" + +gcloud storage buckets create "gs://${BUCKET}" \ + --project="${PROJECT_ID}" \ + --location="${REGION}" \ + --uniform-bucket-level-access + +gcloud storage buckets add-iam-policy-binding "gs://${BUCKET}" \ + --member="serviceAccount:${WRITER_SA}" \ + --role="roles/storage.objectCreator" +``` + +Bucket names are globally unique. Choose a different value if the requested name is already taken. + +The plugin accepts the plain bucket ID through `log-bucket`, for example `my-cln-rpc-logs`. Do not pass `gs://` or the +full `projects/_/buckets/...` resource name; the plugin adds the resource-name prefix internally. + +## Authentication + +The Google Cloud client uses Application Default Credentials (ADC). No credential path is configured in the plugin. + +### GKE + +Use Workload Identity Federation for GKE and associate the pod's Kubernetes service account with the Google service +account that received `roles/storage.objectCreator`. The pod then obtains short-lived credentials automatically; do +not mount a downloaded service-account key in the container. + +### Local development + +Authenticate ADC with the Google Cloud CLI: + +```bash +gcloud auth application-default login +``` + +The authenticated development identity must have permission to create objects in the selected bucket. + +## Configure Core Lightning + +Add the plugin and bucket ID to `lightningd`'s configuration: + +```ini +plugin=/absolute/path/to/target/release/rpc-log-plugin +log-bucket=my-cln-rpc-logs +log-rpc-list=checkrune,commando,pay +``` + +Alternatively, pass the same options on the command line: + +```bash +lightningd \ + --plugin=/absolute/path/to/target/release/rpc-log-plugin \ + --log-bucket=my-cln-rpc-logs \ + --log-rpc-list=checkrune,commando,pay +``` + +The bucket must already exist when RPC requests are logged. Authentication failures, missing buckets, and upload +errors are returned by the hook, so verify the setup outside production before relying on it. + +### Select RPC methods + +`log-rpc-list` controls which RPC methods are logged. The default is `checkrune`. Use a comma-separated list to select +more than one method: + +```ini +log-rpc-list=checkrune,commando,pay +``` + +Whitespace around method names is ignored. Method names must otherwise match exactly. Calls to methods not present in +this list continue normally without being uploaded. + +## Log format + +Each uploaded object contains one JSON document: + +```json +{ + "method": "pay", + "request_id": 42, + "body": { + "bolt11": "lnbc...", + "payment_secret": "***" + }, + "caller": "Name", + "peer_id": "02..." +} +``` + +The `caller` field contains the value of the first `operator#` comment found in a rune passed through named JSON +parameters. The caller field exists only if the request has rune, the rune can be decoded and has such tag. + +Create a rune carrying this comment with: + +```bash +lightning-cli createrune -k restrictions='[["operator#Name"]]' +``` + +When that rune is supplied as a named `rune` parameter, the plugin records `"Name"` in `caller` and redacts the rune +itself from `body`. The comment is descriptive metadata and does not restrict authorization. + +The request body may still contain financially or personally sensitive information that is not covered by the danger +field list, such as invoices, labels, descriptions, addresses, routes, and payment hashes. Restrict access to the +bucket and configure retention and deletion policies appropriate for your environment. diff --git a/rpc-log-plugin/src/main.rs b/rpc-log-plugin/src/main.rs new file mode 100644 index 0000000..824ea31 --- /dev/null +++ b/rpc-log-plugin/src/main.rs @@ -0,0 +1,312 @@ +mod rune; + +use crate::rune::rune_tag; +use anyhow::{Context, Result}; +use cln_plugin::options::{ConfigOption, DefaultStringConfigOption, StringConfigOption}; +use cln_plugin::{Builder, Plugin}; +use cln_rpc::hooks::events::RpcCommandEvent; +use cln_rpc::primitives::{JsonObjectOrArray, JsonScalar}; +use google_cloud_auth::credentials::anonymous::Builder as AnonymousCredentials; +use google_cloud_storage::client::Storage; +use serde::Serialize; +use serde_json::{Value as JsonValue, json}; +use std::collections::HashSet; +use time::OffsetDateTime; +use time::format_description::well_known::Rfc3339; +use uuid::Uuid; + +const RUNE_KEY: &str = "rune"; + +// A list of fields to remove from logs. +const DANGER_FIELDS: [&str; 13] = [ + "rune", + "hsmsecret", + "passphrase", + "preimage", + "payment_preimage", + "payment_secret", + "session_key", + "shared_secrets", + "payer_metadata", + "secret", + "private_key", + "seed", + "mnemonic", +]; + +const EMULATOR_OPTION_NAME: &str = "log-emulator-host"; +pub const EMULATOR_OPTION: StringConfigOption = ConfigOption::new_str_no_default( + EMULATOR_OPTION_NAME, + "If specified - plugin will send logs to the local bucket emulator (see tests)", +); + +const RPC_LIST_OPTION_NAME: &str = "log-rpc-list"; +const RPC_LIST_OPTION: DefaultStringConfigOption = ConfigOption::new_str_with_default( + RPC_LIST_OPTION_NAME, + "checkrune", + "A list of comma separated rpc commands to log", +); + +const BUCKET_OPTION_NAME: &str = "log-bucket"; +const BUCKET_OPTION: StringConfigOption = + ConfigOption::new_str_no_default(BUCKET_OPTION_NAME, "A GCS bucket to store logs in"); + +// According to google_cloud_storage::client::Storage::write_object documentation +const GCS_RESOURCE_NAME_PREFIX: &str = "projects/_/buckets/"; + +#[derive(Clone)] +struct State { + bucket_name: String, + client: Storage, + rpc_list: HashSet, +} + +impl State { + fn method_in_log_list(&self, method: &str) -> bool { + if self.rpc_list.is_empty() { + return true; + } + + self.rpc_list.contains(method) + } +} + +#[tokio::main] +async fn main() -> Result<()> { + let configured = Builder::new(tokio::io::stdin(), tokio::io::stdout()) + .option(BUCKET_OPTION) + .option(RPC_LIST_OPTION) + .option(EMULATOR_OPTION) + .hook("rpc_command", on_hook_rpc_command) + .dynamic() + .configure() + .await?; + + let Some(configured) = configured else { + // CLN shut down during configuration + return Ok(()); + }; + + let rpc_list = configured + .option(&RPC_LIST_OPTION)? + .split(',') + .map(str::trim) + .filter(|method| !method.is_empty()) + .map(str::to_owned) + .collect(); + + let state = State { + bucket_name: format!( + "{}{}", + GCS_RESOURCE_NAME_PREFIX, + configured + .option(&BUCKET_OPTION)? + .context("No bucket name provided")? + ), + client: storage_client(configured.option(&EMULATOR_OPTION)?).await?, + rpc_list, + }; + + let plugin = configured.start(state).await?; + plugin.join().await?; + + Ok(()) +} + +async fn storage_client(emulator_endpoint: Option) -> Result { + let builder = Storage::builder(); + + if let Some(endpoint) = emulator_endpoint { + // Using local emulator without auth + return Ok(builder + .with_endpoint(endpoint) + .with_credentials(AnonymousCredentials::new().build()) + .build() + .await?); + } + + // Uses Application Default Credentials. + // In GKE, these come from Workload Identity. + Ok(builder.build().await?) +} + +async fn on_hook_rpc_command(p: Plugin, v: JsonValue) -> Result { + let rpc_command_hook: RpcCommandEvent = serde_json::from_value(v)?; + + if p.state() + .method_in_log_list(&rpc_command_hook.rpc_command.method) + { + let operator = rune_from_json_array(&rpc_command_hook.rpc_command.params); + let body = sanitize_json_array(rpc_command_hook.rpc_command.params); + + upload_rpc_log( + &p.state().client, + &p.state().bucket_name, + &RpcLog { + method: &rpc_command_hook.rpc_command.method, + caller: operator, + request_id: rpc_command_hook.rpc_command.id, + body, + }, + ) + .await?; + } + + // We do not interrupt command execution + Ok(json!({"result": "continue"})) +} + +#[derive(Serialize)] +struct RpcLog<'a> { + method: &'a str, + request_id: JsonScalar, + body: JsonObjectOrArray, + #[serde(skip_serializing_if = "Option::is_none")] + caller: Option, +} + +async fn upload_rpc_log(client: &Storage, bucket: &str, log: &RpcLog<'_>) -> Result { + let timestamp = OffsetDateTime::now_utc(); + let id = Uuid::new_v4(); + let object_name = format!("rpc/{}-{id}.json", timestamp.format(&Rfc3339)?,); + + client + .write_object(bucket, &object_name, serde_json::to_string(log)?) + .send_buffered() + .await?; + + Ok(object_name) +} + +/// Recursively checks JSON (JsonObjectOrArray) for rune and outputs its operator tag if present +/// (We need this because rpc_command hook defines params as JsonObjectOrArray) +fn rune_from_json_array(value: &JsonObjectOrArray) -> Option { + match value { + JsonObjectOrArray::Object(map) => map.iter().find_map(|(k, v)| rune_from_json_value(k, v)), + JsonObjectOrArray::Array(arr) => arr.iter().find_map(|v| rune_from_json_value("", v)), + } +} + +/// Recursively checks JSON (Value) for rune and outputs its operator tag if present +fn rune_from_json_value(key: &str, value: &JsonValue) -> Option { + if key.to_lowercase().contains(RUNE_KEY) + && let Some(rune) = value.as_str() + && let Ok(result) = rune_tag(rune) + && let Some(operator) = result + { + return Some(operator); + } + + match value { + JsonValue::Object(map) => map.iter().find_map(|(k, v)| rune_from_json_value(k, v)), + JsonValue::Array(arr) => arr.iter().find_map(|v| rune_from_json_value("", v)), + _ => None, + } +} + +/// Recursively checks JSON (JsonObjectOrArray) for sensitive (danger) keys and fills their values with "***" +/// (We need this because rpc_command hook defines params as JsonObjectOrArray) +fn sanitize_json_array(value: JsonObjectOrArray) -> JsonObjectOrArray { + match value { + JsonObjectOrArray::Object(map) => JsonObjectOrArray::Object( + map.into_iter() + .map(|(k, v)| { + let result = sanitize_json_value(&k, v); + (k, result) + }) + .collect(), + ), + JsonObjectOrArray::Array(arr) => JsonObjectOrArray::Array( + arr.into_iter() + .map(|v| sanitize_json_value("", v)) + .collect(), + ), + } +} + +/// Recursively checks JSON (Value) for sensitive (danger) keys and fills their values with "***" +/// Credits to @erdoganishe +fn sanitize_json_value(key: &str, value: JsonValue) -> JsonValue { + if is_sensitive_key(key) { + return JsonValue::String("***".into()); + } + + match value { + JsonValue::Object(map) => JsonValue::Object( + map.into_iter() + .map(|(k, v)| { + let result = sanitize_json_value(&k, v); + (k, result) + }) + .collect(), + ), + JsonValue::Array(arr) => JsonValue::Array( + arr.into_iter() + .map(|v| sanitize_json_value("", v)) + .collect(), + ), + other => other, + } +} + +fn is_sensitive_key(key_to_check: &str) -> bool { + for key in DANGER_FIELDS.iter() { + if key_to_check.to_lowercase().contains(key) { + return true; + } + } + false +} + +#[cfg(test)] +mod tests { + use crate::{rune_from_json_value, sanitize_json_value}; + use anyhow::Result; + + #[test] + fn test_sanitize_json() -> Result<()> { + let example = r#"{"rune":"12345"}"#; + let sanitize_example = sanitize_json_value("", serde_json::from_str(example)?); + let result_json = sanitize_example.to_string(); + assert_eq!(result_json, r#"{"rune":"***"}"#); + Ok(()) + } + + #[test] + fn test_sanitize_json_arr() -> Result<()> { + let example = r#"{"key":[{"rune_1":"12345"},{"rune_2":"12345"}]}"#; + let sanitize_example = sanitize_json_value("", serde_json::from_str(example)?); + let result_json = sanitize_example.to_string(); + assert_eq!( + result_json, + r#"{"key":[{"rune_1":"***"},{"rune_2":"***"}]}"# + ); + Ok(()) + } + + #[test] + fn test_sanitize_json_full_object() -> Result<()> { + let example = r#"{"secret":{"key":"value"}}"#; + let sanitize_example = sanitize_json_value("", serde_json::from_str(example)?); + let result_json = sanitize_example.to_string(); + assert_eq!(result_json, r#"{"secret":"***"}"#); + Ok(()) + } + + #[test] + fn test_find_operator() -> Result<()> { + let example = + r#"{"params":{"rune":"_A7OO-xeVLnHX-zRLOhNGg3DDDMCvET1DZN-72WkbkVvcGVyYXRvciNPbGVn"}}"#; + let result_json = rune_from_json_value("", &serde_json::from_str(example)?); + assert_eq!(result_json, Some("Oleg".to_owned())); + Ok(()) + } + + #[test] + fn test_find_operator_in_arr() -> Result<()> { + let example = r#"{"params":[{"rune":"_A7OO-xeVLnHX-zRLOhNGg3DDDMCvET1DZN-72WkbkVvcGVyYXRvciNPbGVn"}]}"#; + let result_json = rune_from_json_value("", &serde_json::from_str(example)?); + assert_eq!(result_json, Some("Oleg".to_owned())); + Ok(()) + } +} diff --git a/rpc-log-plugin/src/rune.rs b/rpc-log-plugin/src/rune.rs new file mode 100644 index 0000000..0a1d070 --- /dev/null +++ b/rpc-log-plugin/src/rune.rs @@ -0,0 +1,38 @@ +use anyhow::{Context, Result}; +use base64::{Engine, engine::general_purpose::URL_SAFE}; + +const OPERATOR_RUNE_TAG: &str = "operator#"; +const RUNE_PREFIX_BYTES: usize = 32; + +/// Searches for tag `operator#name` in the rune. +/// Returns error if failed to parse provided rune. +/// Returns None if no such tag. +pub(crate) fn rune_tag(rune: &str) -> Result> { + // Rune uses RFC 4648 URL-safe Base64 alphabet + let decoded = URL_SAFE.decode(rune).context("invalid rune")?; + + let metadata = decoded + .get(RUNE_PREFIX_BYTES..) + .and_then(|bytes| std::str::from_utf8(bytes).ok()) + .context("invalid rune metadata")?; + + Ok(metadata + .split(['&', '|']) + .find_map(|part| part.strip_prefix(OPERATOR_RUNE_TAG)) + .map(str::to_owned)) +} + +#[cfg(test)] +mod tests { + use crate::rune_tag; + use anyhow::Result; + + #[test] + fn test_parse_rune_operator() -> Result<()> { + let example_rune = "_A7OO-xeVLnHX-zRLOhNGg3DDDMCvET1DZN-72WkbkVvcGVyYXRvciNPbGVn"; + let operator = rune_tag(example_rune)?; + assert!(operator.is_some()); + assert_eq!(operator.unwrap(), "Oleg".to_owned()); + Ok(()) + } +} diff --git a/rpc-log-plugin/tests/test_plugin.py b/rpc-log-plugin/tests/test_plugin.py new file mode 100644 index 0000000..5cfff27 --- /dev/null +++ b/rpc-log-plugin/tests/test_plugin.py @@ -0,0 +1,147 @@ +import json +import subprocess +import time +import urllib.error +import urllib.parse +import urllib.request +from pathlib import Path + +import pytest +from pyln.testing.fixtures import * # noqa: F403,F401 + +PLUGIN_PATH = Path(__file__).parents[2] / "target" / "release" / "rpc-log-plugin" +GCS_ENDPOINT = "http://127.0.0.1:4443" + +PROJECT = "test-project" + +CHECKRUNE_BUCKET = "rpc-log-plugin-test" +COMMANDO_BUCKET = "rpc-log-plugin-commando-test" + + +def gcs_request(method, path, body=None): + data = None if body is None else json.dumps(body).encode() + request = urllib.request.Request( + f"{GCS_ENDPOINT}{path}", + data=data, + headers={"Content-Type": "application/json"}, + method=method, + ) + with urllib.request.urlopen(request, timeout=5) as response: + payload = response.read() + return json.loads(payload) if payload else None + + +@pytest.fixture(scope="module") +def fake_gcs(): + container_id = subprocess.run( + [ + "docker", + "run", + "--rm", + "--detach", + "--publish", + "4443:4443", + "fsouza/fake-gcs-server", + "-scheme", + "http", + "-port", + "4443", + ], + check=True, + capture_output=True, + text=True, + ).stdout.strip() + + try: + for _ in range(50): + try: + gcs_request("GET", f"/storage/v1/b?project={PROJECT}") + break + except (OSError, urllib.error.URLError): + time.sleep(0.1) + else: + pytest.fail("fake-gcs-server did not become ready") + + for bucket in (CHECKRUNE_BUCKET, COMMANDO_BUCKET): + gcs_request("POST", f"/storage/v1/b?project={PROJECT}", {"name": bucket}) + yield + finally: + subprocess.run( + ["docker", "rm", "--force", container_id], + check=False, + capture_output=True, + ) + + +def only_log(bucket): + objects = gcs_request("GET", f"/storage/v1/b/{bucket}/o").get("items", []) + assert len(objects) == 1 + + object_name = objects[0]["name"] + encoded_name = urllib.parse.quote(object_name, safe="") + log = gcs_request("GET", f"/storage/v1/b/{bucket}/o/{encoded_name}?alt=media") + print("\n\nLog file content:", log, "\n\n") + return log + + +def test_checkrune_is_uploaded(node_factory, fake_gcs): # noqa: F811 + assert PLUGIN_PATH.exists(), f"Build the plugin first: {PLUGIN_PATH}" + node = node_factory.get_node( + options={ + "plugin": str(PLUGIN_PATH), + "log-bucket": CHECKRUNE_BUCKET, + "log-emulator-host": GCS_ENDPOINT, + }, + start=True, + ) + + rune = node.rpc.createrune(restrictions=[["operator#IntegrationTest"]])["rune"] + result = node.rpc.checkrune(rune=rune) + assert result["valid"] + + log = only_log(CHECKRUNE_BUCKET) + + assert log["method"] == "checkrune" + assert log["caller"] == "IntegrationTest" + assert log["body"] == {"rune": "***"} + + +def test_invoice_through_commando_is_uploaded(node_factory, fake_gcs): # noqa: F811 + assert PLUGIN_PATH.exists(), f"Build the plugin first: {PLUGIN_PATH}" + plugin_options = { + "plugin": str(PLUGIN_PATH), + "log-bucket": COMMANDO_BUCKET, + "log-emulator-host": GCS_ENDPOINT, + } + target, caller = node_factory.line_graph( + 2, + fundchannel=False, + opts=[plugin_options, {}], + ) + + rune = target.rpc.createrune(restrictions=[["operator#CommandoTest"]])["rune"] + invoice_params = { + "amount_msat": 1000, + "label": "commando-integration-test", + "description": "Created through commando", + } + result = caller.rpc.call( + method="commando", + payload={ + "peer_id": target.info["id"], + "rune": rune, + "method": "invoice", + "params": invoice_params, + }, + ) + assert "bolt11" in result + + log = only_log(COMMANDO_BUCKET) + assert log["method"] == "checkrune" + assert log["caller"] == "CommandoTest" + assert log["body"] == { + "nodeid": caller.info["id"], + "rune": "***", + "method": "invoice", + "params": invoice_params, + }