From b61a91586775cf59232133e3b656040ccc86d78c Mon Sep 17 00:00:00 2001 From: Oleh Fomenko Date: Mon, 31 Aug 2026 18:37:49 +0300 Subject: [PATCH 1/8] Adding RPC log plugin: catch each rpc request and send log into GCS bucket. WIP Co-authored-by: Mykhailo Khotian Co-authored-by: Oleg Fomenko --- Cargo.lock | 1193 ++++++++++++++++++++++++++++++++++-- Cargo.toml | 1 + rpc-log-plugin/Cargo.toml | 16 + rpc-log-plugin/src/main.rs | 207 +++++++ 4 files changed, 1360 insertions(+), 57 deletions(-) create mode 100644 rpc-log-plugin/Cargo.toml create mode 100644 rpc-log-plugin/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index 87388d3..cf8c06d 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.118", "synstructure", ] @@ -120,7 +129,7 @@ checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.118", ] [[package]] @@ -217,7 +226,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.118", ] [[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" @@ -408,6 +423,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" @@ -423,6 +444,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" @@ -445,6 +475,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" @@ -456,6 +495,9 @@ name = "bytes" version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04" +dependencies = [ + "serde", +] [[package]] name = "cbc" @@ -484,6 +526,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" @@ -492,7 +540,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]] @@ -501,7 +561,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", ] @@ -542,6 +602,24 @@ dependencies = [ "tokio-util", ] +[[package]] +name = "cln-rpc" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d9f5e26f0a2713ea1393eb3117c148295fa4c5f7db529713b20323ca7cc37aa" +dependencies = [ + "anyhow", + "bitcoin", + "bytes", + "futures-util", + "hex", + "log", + "serde", + "serde_json", + "tokio", + "tokio-util", +] + [[package]] name = "cmake" version = "0.1.58" @@ -551,6 +629,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" @@ -638,6 +722,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" @@ -678,12 +771,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.118", +] + +[[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.118", +] + [[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.118", +] + +[[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" @@ -719,7 +895,7 @@ checksum = "8034092389675178f570469e6c3b0465d3d30b4505c294a6550db47f3c17ad18" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.118", ] [[package]] @@ -727,6 +903,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" @@ -743,11 +922,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" @@ -756,7 +946,7 @@ checksum = "1ac70aa55017e108007fbaf5aa0f54b021c98f92ff8af59d42eda9da96e3dd4f" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.118", ] [[package]] @@ -765,6 +955,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" @@ -842,7 +1038,7 @@ checksum = "ee93edf3c501f0035bbeffeccfed0b79e14c311f12195ec0e661e114a0f60da4" dependencies = [ "futures", "portable-atomic", - "rand", + "rand 0.10.2", "tokio", "web-time", ] @@ -972,7 +1168,7 @@ checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.118", ] [[package]] @@ -1032,8 +1228,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]] @@ -1043,9 +1253,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]] @@ -1060,13 +1492,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" @@ -1134,7 +1572,7 @@ dependencies = [ "idna", "ipnet", "jni", - "rand", + "rand 0.10.2", "thiserror 2.0.18", "tinyvec", "tokio", @@ -1154,7 +1592,7 @@ dependencies = [ "jni", "once_cell", "prefix-trie", - "rand", + "rand 0.10.2", "ring", "thiserror 2.0.18", "tinyvec", @@ -1179,7 +1617,7 @@ dependencies = [ "ndk-context", "once_cell", "parking_lot", - "rand", + "rand 0.10.2", "resolv-conf", "smallvec", "system-configuration", @@ -1194,7 +1632,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]] @@ -1242,6 +1689,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" @@ -1264,6 +1720,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" @@ -1283,13 +1754,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", @@ -1297,6 +1771,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" @@ -1379,6 +1877,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" @@ -1400,6 +1904,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" @@ -1408,6 +1923,8 @@ checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" dependencies = [ "equivalent", "hashbrown 0.17.1", + "serde", + "serde_core", ] [[package]] @@ -1457,6 +1974,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.118", +] + +[[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" @@ -1484,7 +2054,7 @@ dependencies = [ "quote", "rustc_version", "simd_cesu8", - "syn", + "syn 2.0.118", ] [[package]] @@ -1503,7 +2073,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264" dependencies = [ "quote", - "syn", + "syn 2.0.118", ] [[package]] @@ -1584,6 +2154,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" @@ -1599,6 +2175,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" @@ -1612,7 +2194,7 @@ dependencies = [ "anyhow", "axum", "cln-plugin", - "cln-rpc", + "cln-rpc 0.6.0", "prometheus", "serde", "serde_json", @@ -1626,6 +2208,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" @@ -1759,25 +2351,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", ] @@ -1817,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]] @@ -1844,7 +2472,7 @@ checksum = "8701b58ea97060d5e5b155d383a69952a60943f0e6dfe30b04c287beb0b27455" dependencies = [ "fixedbitset", "hashbrown 0.15.5", - "indexmap", + "indexmap 2.14.0", ] [[package]] @@ -1864,7 +2492,7 @@ checksum = "c96395f0a926bc13b1c17622aaddda1ecb55d49c8f1bf9777e4d877800a43f8b" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.118", ] [[package]] @@ -1893,7 +2521,7 @@ dependencies = [ "cms", "const-oid", "der", - "digest", + "digest 0.10.7", "spki", "x509-cert", "zeroize", @@ -1910,7 +2538,7 @@ dependencies = [ "der", "pbkdf2", "scrypt", - "sha2", + "sha2 0.10.9", "spki", ] @@ -1926,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" @@ -1941,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" @@ -1959,7 +2605,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" dependencies = [ "proc-macro2", - "syn", + "syn 2.0.118", ] [[package]] @@ -2013,7 +2659,7 @@ dependencies = [ "pulldown-cmark", "pulldown-cmark-to-cmark", "regex", - "syn", + "syn 2.0.118", "tempfile", ] @@ -2027,7 +2673,7 @@ dependencies = [ "itertools", "proc-macro2", "quote", - "syn", + "syn 2.0.118", ] [[package]] @@ -2065,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", ] @@ -2079,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" @@ -2088,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" @@ -2102,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]] @@ -2111,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" @@ -2126,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]] @@ -2158,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" @@ -2178,6 +2987,27 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "rpc-log-plugin" +version = "0.1.0" +dependencies = [ + "anyhow", + "cln-plugin", + "cln-rpc 0.7.0", + "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" @@ -2202,7 +3032,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", @@ -2216,6 +3046,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", @@ -2256,6 +3087,7 @@ version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "764899a24af3980067ee14bc143654f297b22eaebfe3c7b6b211920a5a59b046" dependencies = [ + "web-time", "zeroize", ] @@ -2337,6 +3169,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" @@ -2351,7 +3207,7 @@ checksum = "0516a385866c09368f0b5bcd1caff3366aace790fcd46e2bb032697bb172fd1f" dependencies = [ "pbkdf2", "salsa20", - "sha2", + "sha2 0.10.9", ] [[package]] @@ -2380,7 +3236,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", @@ -2430,7 +3286,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.118", ] [[package]] @@ -2469,6 +3325,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.118", +] + [[package]] name = "sha1" version = "0.10.7" @@ -2477,7 +3366,7 @@ checksum = "a978451301f4db1d02937a4ab3ccce137717b81826e79b7d49ffe3244a13c3b8" dependencies = [ "cfg-if", "cpufeatures 0.2.17", - "digest", + "digest 0.10.7", ] [[package]] @@ -2488,7 +3377,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]] @@ -2579,6 +3479,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" @@ -2596,11 +3502,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" @@ -2610,7 +3530,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.118", ] [[package]] @@ -2619,7 +3539,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", ] @@ -2692,7 +3612,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.118", ] [[package]] @@ -2703,7 +3623,7 @@ checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.118", ] [[package]] @@ -2795,7 +3715,17 @@ checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.118", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" +dependencies = [ + "rustls", + "tokio", ] [[package]] @@ -2807,6 +3737,7 @@ dependencies = [ "futures-core", "pin-project-lite", "tokio", + "tokio-util", ] [[package]] @@ -2830,7 +3761,7 @@ checksum = "ac2a5518c70fa84342385732db33fb3f44bc4cc748936eb5833d2df34d6445ef" dependencies = [ "async-trait", "axum", - "base64", + "base64 0.22.1", "bytes", "h2", "http", @@ -2841,9 +3772,11 @@ dependencies = [ "hyper-util", "percent-encoding", "pin-project", + "rustls-native-certs", "socket2", "sync_wrapper", "tokio", + "tokio-rustls", "tokio-stream", "tower", "tower-layer", @@ -2860,7 +3793,18 @@ dependencies = [ "prettyplease", "proc-macro2", "quote", - "syn", + "syn 2.0.118", +] + +[[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]] @@ -2874,7 +3818,7 @@ dependencies = [ "prost-build", "prost-types", "quote", - "syn", + "syn 2.0.118", "tempfile", "tonic-build", ] @@ -2887,7 +3831,7 @@ checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" dependencies = [ "futures-core", "futures-util", - "indexmap", + "indexmap 2.14.0", "pin-project-lite", "slab", "sync_wrapper", @@ -2898,6 +3842,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" @@ -2930,7 +3892,7 @@ checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.118", ] [[package]] @@ -2954,6 +3916,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" @@ -3068,6 +4044,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" @@ -3081,6 +4066,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" @@ -3100,7 +4095,7 @@ dependencies = [ "bumpalo", "proc-macro2", "quote", - "syn", + "syn 2.0.118", "wasm-bindgen-shared", ] @@ -3113,6 +4108,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" @@ -3147,6 +4165,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.118", +] + +[[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.118", +] + [[package]] name = "windows-link" version = "0.2.1" @@ -3264,6 +4317,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[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" @@ -3317,10 +4376,30 @@ checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.118", "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.118", +] + [[package]] name = "zerofrom" version = "0.1.8" @@ -3338,7 +4417,7 @@ checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.118", "synstructure", ] @@ -3378,7 +4457,7 @@ checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.118", ] [[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/rpc-log-plugin/Cargo.toml b/rpc-log-plugin/Cargo.toml new file mode 100644 index 0000000..3f1de0e --- /dev/null +++ b/rpc-log-plugin/Cargo.toml @@ -0,0 +1,16 @@ +[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" +time = { version = "0.3", features = ["formatting"] } +uuid = { version = "1", features = ["v4"] } \ No newline at end of file diff --git a/rpc-log-plugin/src/main.rs b/rpc-log-plugin/src/main.rs new file mode 100644 index 0000000..516eb77 --- /dev/null +++ b/rpc-log-plugin/src/main.rs @@ -0,0 +1,207 @@ +use anyhow::{Context, Result}; +use cln_plugin::options::{ConfigOption, StringConfigOption}; +use cln_plugin::{Builder, Plugin}; +use cln_rpc::ClnRpc; +use cln_rpc::hooks::events::RpcCommandEvent; +use cln_rpc::model::requests::GetinfoRequest; +use cln_rpc::primitives::{JsonObjectOrArray, JsonScalar, PublicKey}; +use google_cloud_storage::client::Storage; +use serde::{Deserialize, Serialize}; +use serde_json::{Value as JsonValue, json}; +use std::fmt; +use std::fmt::{Debug, Display, Formatter}; +use std::path::{Path, PathBuf}; +use time::OffsetDateTime; +use time::format_description::well_known::Rfc3339; +use uuid::Uuid; + +// 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 SILENT_OPTION_NAME: &str = "silent"; +// pub const SILENT_OPTION: DefaultBooleanConfigOption = ConfigOption::new_bool_with_default( +// SILENT_OPTION_NAME, +// false, +// "If specified - plugin will not send logs to the GCS bucket", +// ); + +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/"; + +/// A wrapper around a String variable that is intended to hold a password. +/// It implements [`Display`] which hides the password for being accidentally +/// printed. +#[derive(Deserialize, Clone)] +pub struct Password(String); + +impl Password { + pub fn inner(&self) -> &str { + self.0.as_str() + } +} + +impl Debug for Password { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!(f, "*****") + } +} + +impl Display for Password { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!(f, "*****") + } +} + +#[derive(Clone)] +pub struct State { + pub cln_rpc_path: PathBuf, + pub peer_id: PublicKey, + pub bucket_name: String, + pub client: Storage, +} + +#[tokio::main] +async fn main() -> Result<()> { + let configured = Builder::new(tokio::io::stdin(), tokio::io::stdout()) + .option(BUCKET_OPTION) + .hook("rpc_command", on_hook_rpc_command) + .dynamic() + .configure() + .await?; + + let Some(configured) = configured else { + // CLN shut down during configuration + return Ok(()); + }; + + let cfg = configured.configuration(); + let rpc_path = Path::new(&cfg.lightning_dir).join(&cfg.rpc_file); + let peer_id = get_my_peer_id(rpc_path.clone()).await?; + + let state = State { + cln_rpc_path: rpc_path.clone(), + bucket_name: format!( + "{}{}", + GCS_RESOURCE_NAME_PREFIX, + configured + .option(&BUCKET_OPTION)? + .context("No bucket name provided")? + ), + // Automatically uses Application Default Credentials. + // In GKE, these come from Workload Identity. + client: Storage::builder().build().await?, + peer_id, + }; + + let plugin = configured.start(state).await?; + plugin.join().await?; + + Ok(()) +} + +pub async fn on_hook_rpc_command(p: Plugin, v: JsonValue) -> Result { + let rpc_command_hook: RpcCommandEvent = serde_json::from_value(v)?; + + let body = match rpc_command_hook.rpc_command.params { + JsonObjectOrArray::Object(object) => JsonObjectOrArray::Object( + object + .into_iter() + .map(|(key, object)| (key, sanitize_json(object))) + .collect(), + ), + JsonObjectOrArray::Array(array) => { + JsonObjectOrArray::Array(array.into_iter().map(sanitize_json).collect()) + } + }; + + upload_rpc_log( + &p.state().client, + &p.state().bucket_name, + &RpcLog { + method: &rpc_command_hook.rpc_command.method, + caller: None, + request_id: rpc_command_hook.rpc_command.id, + body, + peer_id: &p.state().peer_id.to_string(), + }, + ) + .await?; + + // We do not interrupt command execution + Ok(json!({"result": "continue"})) +} + +#[derive(Serialize)] +struct RpcLog<'a> { + method: &'a str, + request_id: JsonScalar, + body: JsonObjectOrArray, + caller: Option<&'a str>, + peer_id: &'a str, +} + +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) +} + +async fn get_my_peer_id(rpc_path: PathBuf) -> Result { + let mut cln_rpc = ClnRpc::new(&rpc_path).await?; + let info = cln_rpc.call_typed(&GetinfoRequest {}).await?; + Ok(info.id) +} + +/// Recursively checks JSON for sensitive (danger) keys and fills their values with "***" +/// Credits to @erdoganishe +fn sanitize_json(value: JsonValue) -> JsonValue { + match value { + JsonValue::Object(map) => JsonValue::Object( + map.into_iter() + .map(|(k, v)| { + if is_sensitive_key(&k) { + (k, JsonValue::String("***".into())) + } else { + (k, sanitize_json(v)) + } + }) + .collect(), + ), + JsonValue::Array(arr) => JsonValue::Array(arr.into_iter().map(sanitize_json).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 +} From a564064828f57cbb60dc30885995b4c67151433b Mon Sep 17 00:00:00 2001 From: Oleh Fomenko Date: Mon, 31 Aug 2026 19:28:08 +0300 Subject: [PATCH 2/8] Small refactoring: removed unused code Co-authored-by: Oleg Fomenko --- rpc-log-plugin/src/main.rs | 36 ++++-------------------------------- 1 file changed, 4 insertions(+), 32 deletions(-) diff --git a/rpc-log-plugin/src/main.rs b/rpc-log-plugin/src/main.rs index 516eb77..40faafd 100644 --- a/rpc-log-plugin/src/main.rs +++ b/rpc-log-plugin/src/main.rs @@ -6,10 +6,8 @@ use cln_rpc::hooks::events::RpcCommandEvent; use cln_rpc::model::requests::GetinfoRequest; use cln_rpc::primitives::{JsonObjectOrArray, JsonScalar, PublicKey}; use google_cloud_storage::client::Storage; -use serde::{Deserialize, Serialize}; +use serde::Serialize; use serde_json::{Value as JsonValue, json}; -use std::fmt; -use std::fmt::{Debug, Display, Formatter}; use std::path::{Path, PathBuf}; use time::OffsetDateTime; use time::format_description::well_known::Rfc3339; @@ -46,33 +44,8 @@ const BUCKET_OPTION: StringConfigOption = // According to google_cloud_storage::client::Storage::write_object documentation const GCS_RESOURCE_NAME_PREFIX: &str = "projects/_/buckets/"; -/// A wrapper around a String variable that is intended to hold a password. -/// It implements [`Display`] which hides the password for being accidentally -/// printed. -#[derive(Deserialize, Clone)] -pub struct Password(String); - -impl Password { - pub fn inner(&self) -> &str { - self.0.as_str() - } -} - -impl Debug for Password { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - write!(f, "*****") - } -} - -impl Display for Password { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - write!(f, "*****") - } -} - #[derive(Clone)] -pub struct State { - pub cln_rpc_path: PathBuf, +struct State { pub peer_id: PublicKey, pub bucket_name: String, pub client: Storage, @@ -94,10 +67,9 @@ async fn main() -> Result<()> { let cfg = configured.configuration(); let rpc_path = Path::new(&cfg.lightning_dir).join(&cfg.rpc_file); - let peer_id = get_my_peer_id(rpc_path.clone()).await?; + let peer_id = get_my_peer_id(rpc_path).await?; let state = State { - cln_rpc_path: rpc_path.clone(), bucket_name: format!( "{}{}", GCS_RESOURCE_NAME_PREFIX, @@ -117,7 +89,7 @@ async fn main() -> Result<()> { Ok(()) } -pub async fn on_hook_rpc_command(p: Plugin, v: JsonValue) -> Result { +async fn on_hook_rpc_command(p: Plugin, v: JsonValue) -> Result { let rpc_command_hook: RpcCommandEvent = serde_json::from_value(v)?; let body = match rpc_command_hook.rpc_command.params { From 4ea79af5602dc03c86bd79cd9d1e362408e8d88f Mon Sep 17 00:00:00 2001 From: Oleh Fomenko Date: Mon, 31 Aug 2026 19:30:27 +0300 Subject: [PATCH 3/8] Adding plugin readme Co-authored-by: Oleg Fomenko --- rpc-log-plugin/README.md | 132 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 rpc-log-plugin/README.md diff --git a/rpc-log-plugin/README.md b/rpc-log-plugin/README.md new file mode 100644 index 0000000..4f1ded1 --- /dev/null +++ b/rpc-log-plugin/README.md @@ -0,0 +1,132 @@ +# 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 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 +``` + +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 +``` + +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. + +## Log format + +Each uploaded object contains one JSON document: + +```json +{ + "method": "pay", + "request_id": 42, + "body": { + "bolt11": "lnbc...", + "payment_secret": "***" + }, + "caller": null, + "peer_id": "02..." +} +``` + +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. From 471f97ba7a0828756a549e25dde0af2e33cf7df6 Mon Sep 17 00:00:00 2001 From: Oleh Fomenko Date: Tue, 1 Sep 2026 03:45:52 +0300 Subject: [PATCH 4/8] Adding logic for obtaining rune operator if present. It searches for runes in rpc call params and tries to parse it. Co-authored-by: Oleg Fomenko --- Cargo.lock | 1 + rpc-log-plugin/Cargo.toml | 3 +- rpc-log-plugin/README.md | 11 ++- rpc-log-plugin/src/main.rs | 142 +++++++++++++++++++++++++++++++------ rpc-log-plugin/src/rune.rs | 38 ++++++++++ 5 files changed, 172 insertions(+), 23 deletions(-) create mode 100644 rpc-log-plugin/src/rune.rs diff --git a/Cargo.lock b/Cargo.lock index cf8c06d..a85242e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2992,6 +2992,7 @@ name = "rpc-log-plugin" version = "0.1.0" dependencies = [ "anyhow", + "base64 0.23.1", "cln-plugin", "cln-rpc 0.7.0", "google-cloud-storage", diff --git a/rpc-log-plugin/Cargo.toml b/rpc-log-plugin/Cargo.toml index 3f1de0e..047f6f2 100644 --- a/rpc-log-plugin/Cargo.toml +++ b/rpc-log-plugin/Cargo.toml @@ -13,4 +13,5 @@ serde_json = { version = "1" } cln-rpc = { version = "0.7" } google-cloud-storage = "1" time = { version = "0.3", features = ["formatting"] } -uuid = { version = "1", features = ["v4"] } \ No newline at end of file +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 index 4f1ded1..b8984ba 100644 --- a/rpc-log-plugin/README.md +++ b/rpc-log-plugin/README.md @@ -122,11 +122,20 @@ Each uploaded object contains one JSON document: "bolt11": "lnbc...", "payment_secret": "***" }, - "caller": null, + "caller": "Name", "peer_id": "02..." } ``` +The `caller` field contains a value of `operator` tag (if present in rune). Returns the first finding. You can create +such runes as follows: + +```shell +lightning-cli createrune -k "restrictions"='[["operator#Name"]]' +``` + +Then, for the given rune plugin will save "Name" in the `caller` log field. + 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 index 40faafd..5ff7cc7 100644 --- a/rpc-log-plugin/src/main.rs +++ b/rpc-log-plugin/src/main.rs @@ -1,3 +1,6 @@ +mod rune; + +use crate::rune::rune_tag; use anyhow::{Context, Result}; use cln_plugin::options::{ConfigOption, StringConfigOption}; use cln_plugin::{Builder, Plugin}; @@ -13,6 +16,8 @@ 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", @@ -92,24 +97,15 @@ async fn main() -> Result<()> { async fn on_hook_rpc_command(p: Plugin, v: JsonValue) -> Result { let rpc_command_hook: RpcCommandEvent = serde_json::from_value(v)?; - let body = match rpc_command_hook.rpc_command.params { - JsonObjectOrArray::Object(object) => JsonObjectOrArray::Object( - object - .into_iter() - .map(|(key, object)| (key, sanitize_json(object))) - .collect(), - ), - JsonObjectOrArray::Array(array) => { - JsonObjectOrArray::Array(array.into_iter().map(sanitize_json).collect()) - } - }; + 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: None, + caller: operator, request_id: rpc_command_hook.rpc_command.id, body, peer_id: &p.state().peer_id.to_string(), @@ -126,7 +122,7 @@ struct RpcLog<'a> { method: &'a str, request_id: JsonScalar, body: JsonObjectOrArray, - caller: Option<&'a str>, + caller: Option, peer_id: &'a str, } @@ -149,22 +145,73 @@ async fn get_my_peer_id(rpc_path: PathBuf) -> Result { Ok(info.id) } -/// Recursively checks JSON for sensitive (danger) keys and fills their values with "***" +/// 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: JsonValue) -> JsonValue { +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)| { - if is_sensitive_key(&k) { - (k, JsonValue::String("***".into())) - } else { - (k, sanitize_json(v)) - } + let result = sanitize_json_value(&k, v); + (k, result) }) .collect(), ), - JsonValue::Array(arr) => JsonValue::Array(arr.into_iter().map(sanitize_json).collect()), + JsonValue::Array(arr) => JsonValue::Array( + arr.into_iter() + .map(|v| sanitize_json_value("", v)) + .collect(), + ), other => other, } } @@ -177,3 +224,56 @@ fn is_sensitive_key(key_to_check: &str) -> bool { } 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(()) + } +} From def3963f8033e6252455542c00b764c608db1bb0 Mon Sep 17 00:00:00 2001 From: Oleh Fomenko Date: Tue, 1 Sep 2026 03:47:58 +0300 Subject: [PATCH 5/8] Sync with master branch Co-authored-by: Oleg Fomenko --- Cargo.lock | 1174 +++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 1118 insertions(+), 56 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 80c83dd..4c14dd7 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,28 @@ 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-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 +3033,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 +3047,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 +3088,7 @@ version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "764899a24af3980067ee14bc143654f297b22eaebfe3c7b6b211920a5a59b046" dependencies = [ + "web-time", "zeroize", ] @@ -2355,6 +3170,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 +3208,7 @@ checksum = "0516a385866c09368f0b5bcd1caff3366aace790fcd46e2bb032697bb172fd1f" dependencies = [ "pbkdf2", "salsa20", - "sha2", + "sha2 0.10.9", ] [[package]] @@ -2398,7 +3237,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 +3287,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.119", ] [[package]] @@ -2496,6 +3335,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 +3376,7 @@ checksum = "a978451301f4db1d02937a4ab3ccce137717b81826e79b7d49ffe3244a13c3b8" dependencies = [ "cfg-if", "cpufeatures 0.2.17", - "digest", + "digest 0.10.7", ] [[package]] @@ -2515,7 +3387,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 +3489,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 +3512,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 +3540,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.119", ] [[package]] @@ -2646,7 +3549,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 +3622,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.119", ] [[package]] @@ -2730,7 +3633,7 @@ checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.119", ] [[package]] @@ -2822,7 +3725,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 +3747,7 @@ dependencies = [ "futures-core", "pin-project-lite", "tokio", + "tokio-util", ] [[package]] @@ -2888,7 +3802,7 @@ checksum = "ac2a5518c70fa84342385732db33fb3f44bc4cc748936eb5833d2df34d6445ef" dependencies = [ "async-trait", "axum", - "base64", + "base64 0.22.1", "bytes", "h2", "http", @@ -2899,9 +3813,11 @@ dependencies = [ "hyper-util", "percent-encoding", "pin-project", + "rustls-native-certs", "socket2", "sync_wrapper", "tokio", + "tokio-rustls", "tokio-stream", "tower", "tower-layer", @@ -2918,7 +3834,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 +3859,7 @@ dependencies = [ "prost-build", "prost-types", "quote", - "syn", + "syn 2.0.119", "tempfile", "tonic-build", ] @@ -2945,7 +3872,7 @@ checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" dependencies = [ "futures-core", "futures-util", - "indexmap", + "indexmap 2.14.0", "pin-project-lite", "slab", "sync_wrapper", @@ -2956,6 +3883,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 +3933,7 @@ checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.119", ] [[package]] @@ -3012,6 +3957,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 +4085,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 +4107,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 +4136,7 @@ dependencies = [ "bumpalo", "proc-macro2", "quote", - "syn", + "syn 2.0.119", "wasm-bindgen-shared", ] @@ -3171,6 +4149,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 +4206,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 +4367,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 +4426,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 +4467,7 @@ checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.119", "synstructure", ] @@ -3445,7 +4507,7 @@ checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.119", ] [[package]] From dd9b28167561d95fbf3a7208ac5bcd6903abc659 Mon Sep 17 00:00:00 2001 From: Oleh Fomenko Date: Tue, 1 Sep 2026 04:22:08 +0300 Subject: [PATCH 6/8] Adding a plugin option to specify the list of rpc commands for logging. By default - only checkrune rpc command will be logged. Co-authored-by: Oleg Fomenko --- rpc-log-plugin/README.md | 33 ++++++++++++++----- rpc-log-plugin/src/main.rs | 66 +++++++++++++++++++++++++++++--------- 2 files changed, 75 insertions(+), 24 deletions(-) diff --git a/rpc-log-plugin/README.md b/rpc-log-plugin/README.md index b8984ba..2f85bed 100644 --- a/rpc-log-plugin/README.md +++ b/rpc-log-plugin/README.md @@ -3,8 +3,8 @@ 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 the `rpc_command` hook, replaces values of known sensitive fields with `"***"`, and -uploads each request as a separate object. +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: @@ -97,6 +97,7 @@ 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: @@ -104,12 +105,25 @@ 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-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: @@ -127,14 +141,17 @@ Each uploaded object contains one JSON document: } ``` -The `caller` field contains a value of `operator` tag (if present in rune). Returns the first finding. You can create -such runes as follows: +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. -```shell -lightning-cli createrune -k "restrictions"='[["operator#Name"]]' +Create a rune carrying this comment with: + +```bash +lightning-cli createrune -k restrictions='[["operator#Name"]]' ``` -Then, for the given rune plugin will save "Name" in the `caller` log field. +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 diff --git a/rpc-log-plugin/src/main.rs b/rpc-log-plugin/src/main.rs index 5ff7cc7..0be483f 100644 --- a/rpc-log-plugin/src/main.rs +++ b/rpc-log-plugin/src/main.rs @@ -2,7 +2,7 @@ mod rune; use crate::rune::rune_tag; use anyhow::{Context, Result}; -use cln_plugin::options::{ConfigOption, StringConfigOption}; +use cln_plugin::options::{ConfigOption, DefaultStringConfigOption, StringConfigOption}; use cln_plugin::{Builder, Plugin}; use cln_rpc::ClnRpc; use cln_rpc::hooks::events::RpcCommandEvent; @@ -11,6 +11,7 @@ use cln_rpc::primitives::{JsonObjectOrArray, JsonScalar, PublicKey}; use google_cloud_storage::client::Storage; use serde::Serialize; use serde_json::{Value as JsonValue, json}; +use std::collections::HashSet; use std::path::{Path, PathBuf}; use time::OffsetDateTime; use time::format_description::well_known::Rfc3339; @@ -42,6 +43,13 @@ const DANGER_FIELDS: [&str; 13] = [ // "If specified - plugin will not send logs to the GCS bucket", // ); +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"); @@ -54,12 +62,24 @@ struct State { pub peer_id: PublicKey, pub bucket_name: String, pub client: Storage, + pub 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) .hook("rpc_command", on_hook_rpc_command) .dynamic() .configure() @@ -74,6 +94,14 @@ async fn main() -> Result<()> { let rpc_path = Path::new(&cfg.lightning_dir).join(&cfg.rpc_file); let peer_id = get_my_peer_id(rpc_path).await?; + 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!( "{}{}", @@ -86,6 +114,7 @@ async fn main() -> Result<()> { // In GKE, these come from Workload Identity. client: Storage::builder().build().await?, peer_id, + rpc_list, }; let plugin = configured.start(state).await?; @@ -97,21 +126,25 @@ async fn main() -> Result<()> { async fn on_hook_rpc_command(p: Plugin, v: JsonValue) -> Result { let rpc_command_hook: RpcCommandEvent = serde_json::from_value(v)?; - 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, - peer_id: &p.state().peer_id.to_string(), - }, - ) - .await?; + 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, + peer_id: &p.state().peer_id.to_string(), + }, + ) + .await?; + } // We do not interrupt command execution Ok(json!({"result": "continue"})) @@ -122,6 +155,7 @@ struct RpcLog<'a> { method: &'a str, request_id: JsonScalar, body: JsonObjectOrArray, + #[serde(skip_serializing_if = "Option::is_none")] caller: Option, peer_id: &'a str, } From 177267c3c42e87d765c0c5542dc7a6a99bb97a35 Mon Sep 17 00:00:00 2001 From: Oleh Fomenko Date: Tue, 1 Sep 2026 15:34:28 +0300 Subject: [PATCH 7/8] Adding ability to use public bucket via log-emulator-host option. Adding integration tests. Co-authored-by: Oleg Fomenko --- Cargo.lock | 1 + rpc-log-plugin/Cargo.toml | 1 + rpc-log-plugin/src/main.rs | 59 ++++++----- rpc-log-plugin/tests/test_plugin.py | 147 ++++++++++++++++++++++++++++ 4 files changed, 178 insertions(+), 30 deletions(-) create mode 100644 rpc-log-plugin/tests/test_plugin.py diff --git a/Cargo.lock b/Cargo.lock index 4c14dd7..2cd2b65 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2995,6 +2995,7 @@ dependencies = [ "base64 0.23.1", "cln-plugin", "cln-rpc", + "google-cloud-auth", "google-cloud-storage", "serde", "serde_json", diff --git a/rpc-log-plugin/Cargo.toml b/rpc-log-plugin/Cargo.toml index 047f6f2..fcb9684 100644 --- a/rpc-log-plugin/Cargo.toml +++ b/rpc-log-plugin/Cargo.toml @@ -12,6 +12,7 @@ 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/src/main.rs b/rpc-log-plugin/src/main.rs index 0be483f..824ea31 100644 --- a/rpc-log-plugin/src/main.rs +++ b/rpc-log-plugin/src/main.rs @@ -4,15 +4,13 @@ use crate::rune::rune_tag; use anyhow::{Context, Result}; use cln_plugin::options::{ConfigOption, DefaultStringConfigOption, StringConfigOption}; use cln_plugin::{Builder, Plugin}; -use cln_rpc::ClnRpc; use cln_rpc::hooks::events::RpcCommandEvent; -use cln_rpc::model::requests::GetinfoRequest; -use cln_rpc::primitives::{JsonObjectOrArray, JsonScalar, PublicKey}; +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 std::path::{Path, PathBuf}; use time::OffsetDateTime; use time::format_description::well_known::Rfc3339; use uuid::Uuid; @@ -36,12 +34,11 @@ const DANGER_FIELDS: [&str; 13] = [ "mnemonic", ]; -// const SILENT_OPTION_NAME: &str = "silent"; -// pub const SILENT_OPTION: DefaultBooleanConfigOption = ConfigOption::new_bool_with_default( -// SILENT_OPTION_NAME, -// false, -// "If specified - plugin will not send logs to the GCS bucket", -// ); +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( @@ -59,10 +56,9 @@ const GCS_RESOURCE_NAME_PREFIX: &str = "projects/_/buckets/"; #[derive(Clone)] struct State { - pub peer_id: PublicKey, - pub bucket_name: String, - pub client: Storage, - pub rpc_list: HashSet, + bucket_name: String, + client: Storage, + rpc_list: HashSet, } impl State { @@ -80,6 +76,7 @@ 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() @@ -90,10 +87,6 @@ async fn main() -> Result<()> { return Ok(()); }; - let cfg = configured.configuration(); - let rpc_path = Path::new(&cfg.lightning_dir).join(&cfg.rpc_file); - let peer_id = get_my_peer_id(rpc_path).await?; - let rpc_list = configured .option(&RPC_LIST_OPTION)? .split(',') @@ -110,10 +103,7 @@ async fn main() -> Result<()> { .option(&BUCKET_OPTION)? .context("No bucket name provided")? ), - // Automatically uses Application Default Credentials. - // In GKE, these come from Workload Identity. - client: Storage::builder().build().await?, - peer_id, + client: storage_client(configured.option(&EMULATOR_OPTION)?).await?, rpc_list, }; @@ -123,6 +113,23 @@ async fn main() -> Result<()> { 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)?; @@ -140,7 +147,6 @@ async fn on_hook_rpc_command(p: Plugin, v: JsonValue) -> Result { body: JsonObjectOrArray, #[serde(skip_serializing_if = "Option::is_none")] caller: Option, - peer_id: &'a str, } async fn upload_rpc_log(client: &Storage, bucket: &str, log: &RpcLog<'_>) -> Result { @@ -173,12 +178,6 @@ async fn upload_rpc_log(client: &Storage, bucket: &str, log: &RpcLog<'_>) -> Res Ok(object_name) } -async fn get_my_peer_id(rpc_path: PathBuf) -> Result { - let mut cln_rpc = ClnRpc::new(&rpc_path).await?; - let info = cln_rpc.call_typed(&GetinfoRequest {}).await?; - Ok(info.id) -} - /// 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 { 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, + } From bfafd3942c39ba05ec245c436f79e9bd6befee10 Mon Sep 17 00:00:00 2001 From: Oleh Fomenko Date: Thu, 3 Sep 2026 16:35:46 +0300 Subject: [PATCH 8/8] Update README.md Co-authored-by: Oleg Fomenko --- README.md | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) 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: