From ffdfbadd10769b99f392617f0d691fcd45dcdafb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maximilian=20Sch=C3=B6nenberg?= Date: Thu, 2 Nov 2023 17:07:19 +0100 Subject: [PATCH 1/5] feat(ch-app): Remove Blockchain, add integration tests --- clearing-house-app/Cargo.lock | 299 ++++++++---------- clearing-house-app/Cargo.toml | 11 +- clearing-house-app/src/db/doc_store.rs | 18 +- clearing-house-app/src/lib.rs | 85 +++++ clearing-house-app/src/main.rs | 89 +----- clearing-house-app/src/model/claims.rs | 49 ++- clearing-house-app/src/model/document.rs | 70 +--- clearing-house-app/src/model/ids/message.rs | 3 +- clearing-house-app/src/model/ids/mod.rs | 15 +- clearing-house-app/src/model/mod.rs | 2 +- clearing-house-app/src/model/process.rs | 4 - .../src/services/document_service.rs | 31 +- .../src/services/logging_service.rs | 81 ++--- clearing-house-app/src/services/mod.rs | 4 +- clearing-house-app/src/util.rs | 4 +- clearing-house-app/tests/README.md | 5 + clearing-house-app/tests/log.rs | 87 +++++ clearing-house-app/tests/public_key.rs | 21 ++ 18 files changed, 432 insertions(+), 446 deletions(-) create mode 100644 clearing-house-app/src/lib.rs create mode 100644 clearing-house-app/tests/README.md create mode 100644 clearing-house-app/tests/log.rs create mode 100644 clearing-house-app/tests/public_key.rs diff --git a/clearing-house-app/Cargo.lock b/clearing-house-app/Cargo.lock index db42cd09..ea752e89 100644 --- a/clearing-house-app/Cargo.lock +++ b/clearing-house-app/Cargo.lock @@ -96,15 +96,6 @@ version = "1.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" -[[package]] -name = "arrayvec" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9" -dependencies = [ - "nodrop", -] - [[package]] name = "async-trait" version = "0.1.74" @@ -113,7 +104,7 @@ checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -238,16 +229,6 @@ dependencies = [ "wyz", ] -[[package]] -name = "blake2-rfc" -version = "0.2.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d6d530bdd2d52966a6d03b7a964add7ae1a288d25214066fd4b600f0f796400" -dependencies = [ - "arrayvec", - "constant_time_eq", -] - [[package]] name = "block-buffer" version = "0.10.4" @@ -345,13 +326,13 @@ dependencies = [ "axum", "base64 0.21.5", "biscuit", - "blake2-rfc", "chrono", "config", "futures", "generic-array", "hex", "hkdf", + "hyper", "mongodb", "num-bigint", "once_cell", @@ -366,6 +347,7 @@ dependencies = [ "tempfile", "thiserror", "tokio", + "tower", "tracing", "tracing-subscriber", "uuid", @@ -373,9 +355,9 @@ dependencies = [ [[package]] name = "config" -version = "0.13.3" +version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d379af7f68bfc21714c6c7dea883544201741d2ce8274bb12fa54f89507f52a7" +checksum = "23738e11972c7643e4ec947840fc463b6a571afcd3e735bdfce7d03c7a784aca" dependencies = [ "async-trait", "lazy_static", @@ -385,12 +367,6 @@ dependencies = [ "toml", ] -[[package]] -name = "constant_time_eq" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" - [[package]] name = "convert_case" version = "0.4.0" @@ -415,9 +391,9 @@ checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" [[package]] name = "cpufeatures" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fbc60abd742b35f2492f808e1abbb83d45f72db402e14c55057edc9c7b1e9e4" +checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0" dependencies = [ "libc", ] @@ -492,9 +468,9 @@ dependencies = [ [[package]] name = "data-encoding" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308" +checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5" [[package]] name = "debugid" @@ -579,9 +555,9 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.5" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3e13f66a2f95e32a39eaa81f6b95d42878ca0e1db0c7543723dfe12557e860" +checksum = "f258a7194e7f7c2a7837a8913aeab7fd8c383457034fa20ce4dd3dcb813e8eb8" dependencies = [ "libc", "windows-sys", @@ -649,9 +625,9 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" +checksum = "da0290714b38af9b4a7b094b8a37086d1b4e61f2df9122c3cad2577669145335" dependencies = [ "futures-channel", "futures-core", @@ -664,9 +640,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" +checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb" dependencies = [ "futures-core", "futures-sink", @@ -674,15 +650,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" +checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c" [[package]] name = "futures-executor" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" +checksum = "0f4fb8693db0cf099eadcca0efe2a5a22e4550f98ed16aba6c48700da29597bc" dependencies = [ "futures-core", "futures-task", @@ -691,38 +667,38 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" +checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa" [[package]] name = "futures-macro" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" +checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] name = "futures-sink" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" +checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817" [[package]] name = "futures-task" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" +checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2" [[package]] name = "futures-util" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" +checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104" dependencies = [ "futures-channel", "futures-core", @@ -748,9 +724,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" dependencies = [ "cfg-if", "libc", @@ -765,9 +741,9 @@ checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" [[package]] name = "h2" -version = "0.3.21" +version = "0.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91fc23aa11be92976ef4729127f1a74adf36d8436f7816b185d18df956790833" +checksum = "4d6250322ef6e60f93f9a2162799302cd6f68f79f6e5d85c8c16f14d1d958178" dependencies = [ "bytes", "fnv", @@ -775,7 +751,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap 1.9.3", + "indexmap 2.1.0", "slab", "tokio", "tokio-util", @@ -843,9 +819,9 @@ dependencies = [ [[package]] name = "http" -version = "0.2.9" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" +checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" dependencies = [ "bytes", "fnv", @@ -974,9 +950,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.0.2" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8adf3ddd720272c6ea8bf59463c04e0f93d0bbf7c5439b691bca2987e0270897" +checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" dependencies = [ "equivalent", "hashbrown 0.14.2", @@ -1017,9 +993,9 @@ checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" [[package]] name = "js-sys" -version = "0.3.64" +version = "0.3.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" +checksum = "54c0c35952f67de54bb584e9fd912b3023117cbafc0a77d8f3dee1fb5f572fe8" dependencies = [ "wasm-bindgen", ] @@ -1032,9 +1008,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.149" +version = "0.2.150" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" +checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" [[package]] name = "linked-hash-map" @@ -1044,9 +1020,9 @@ checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" [[package]] name = "linux-raw-sys" -version = "0.4.10" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da2479e8c062e40bf0066ffa0bc823de0a9368974af99c9f6df941d2c231e03f" +checksum = "969488b55f8ac402214f3f5fd243ebb7206cf82de60d3172994707a4bcc2b829" [[package]] name = "lock_api" @@ -1150,9 +1126,9 @@ dependencies = [ [[package]] name = "mongodb" -version = "2.7.0" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e22d517e7e678e1c9a2983ec704b43f3b22f38b1b7a247ea3ddb36d21578bf4e" +checksum = "e7c926772050c3a3f87c837626bf6135c8ca688d91d31dd39a3da547fc2bc9fe" dependencies = [ "async-trait", "base64 0.13.1", @@ -1216,12 +1192,6 @@ dependencies = [ "tempfile", ] -[[package]] -name = "nodrop" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" - [[package]] name = "nom" version = "7.1.3" @@ -1318,9 +1288,9 @@ dependencies = [ [[package]] name = "openssl" -version = "0.10.57" +version = "0.10.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bac25ee399abb46215765b1cb35bc0212377e58a061560d8b29b024fd0430e7c" +checksum = "7a257ad03cd8fb16ad4172fedf8094451e1af1c4b70097636ef2eac9a5f0cc33" dependencies = [ "bitflags 2.4.1", "cfg-if", @@ -1339,7 +1309,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -1350,9 +1320,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.93" +version = "0.9.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db4d56a4c0478783083cfafcc42493dd4a981d41669da64b4572a2a089b51b1d" +checksum = "40a4130519a360279579c2053038317e40eff64d13fd3f004f9e1b72b8a6aaf9" dependencies = [ "cc", "libc", @@ -1395,7 +1365,7 @@ checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.4.1", + "redox_syscall", "smallvec", "windows-targets", ] @@ -1438,7 +1408,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -1543,15 +1513,6 @@ dependencies = [ "getrandom", ] -[[package]] -name = "redox_syscall" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" -dependencies = [ - "bitflags 1.3.2", -] - [[package]] name = "redox_syscall" version = "0.4.1" @@ -1718,9 +1679,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.20" +version = "0.38.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67ce50cb2e16c2903e30d1cbccfd8387a74b9d4c938b6a4c5ec6cc7556f7a8a0" +checksum = "dc99bc2d4f1fed22595588a013687477aedf3cdcfb26558c559edb67b4d9b22e" dependencies = [ "bitflags 2.4.1", "errno", @@ -1731,9 +1692,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.21.8" +version = "0.21.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "446e14c5cda4f3f30fe71863c34ec70f5ac79d6087097ad0bb433e1be5edf04c" +checksum = "629648aced5775d558af50b2b4c7b02983a04b312126d45eeead26e7caa498b9" dependencies = [ "log", "ring 0.17.5", @@ -1743,9 +1704,9 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" dependencies = [ "base64 0.21.5", ] @@ -1843,9 +1804,9 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "sentry" -version = "0.31.7" +version = "0.31.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0097a48cd1999d983909f07cb03b15241c5af29e5e679379efac1c06296abecc" +checksum = "6ce4b57f1b521f674df7a1d200be8ff5d74e3712020ee25b553146657b5377d5" dependencies = [ "httpdate", "native-tls", @@ -1862,9 +1823,9 @@ dependencies = [ [[package]] name = "sentry-backtrace" -version = "0.31.7" +version = "0.31.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18a7b80fa1dd6830a348d38a8d3a9761179047757b7dca29aef82db0118b9670" +checksum = "58cc8d4e04a73de8f718dc703943666d03f25d3e9e4d0fb271ca0b8c76dfa00e" dependencies = [ "backtrace", "once_cell", @@ -1874,9 +1835,9 @@ dependencies = [ [[package]] name = "sentry-contexts" -version = "0.31.7" +version = "0.31.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7615dc588930f1fd2e721774f25844ae93add2dbe2d3c2f995ce5049af898147" +checksum = "6436c1bad22cdeb02179ea8ef116ffc217797c028927def303bc593d9320c0d1" dependencies = [ "hostname", "libc", @@ -1888,9 +1849,9 @@ dependencies = [ [[package]] name = "sentry-core" -version = "0.31.7" +version = "0.31.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f51264e4013ed9b16558cce43917b983fa38170de2ca480349ceb57d71d6053" +checksum = "901f761681f97db3db836ef9e094acdd8756c40215326c194201941947164ef1" dependencies = [ "once_cell", "rand", @@ -1901,9 +1862,9 @@ dependencies = [ [[package]] name = "sentry-debug-images" -version = "0.31.7" +version = "0.31.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fe6180fa564d40bb942c9f0084ffb5de691c7357ead6a2b7a3154fae9e401dd" +checksum = "afdb263e73d22f39946f6022ed455b7561b22ff5553aca9be3c6a047fa39c328" dependencies = [ "findshlibs", "once_cell", @@ -1912,9 +1873,9 @@ dependencies = [ [[package]] name = "sentry-panic" -version = "0.31.7" +version = "0.31.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "323160213bba549f9737317b152af116af35c0410f4468772ee9b606d3d6e0fa" +checksum = "74fbf1c163f8b6a9d05912e1b272afa27c652e8b47ea60cb9a57ad5e481eea99" dependencies = [ "sentry-backtrace", "sentry-core", @@ -1922,9 +1883,9 @@ dependencies = [ [[package]] name = "sentry-tracing" -version = "0.31.7" +version = "0.31.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38033822128e73f7b6ca74c1631cef8868890c6cb4008a291cf73530f87b4eac" +checksum = "82eabcab0a047040befd44599a1da73d3adb228ff53b5ed9795ae04535577704" dependencies = [ "sentry-backtrace", "sentry-core", @@ -1934,9 +1895,9 @@ dependencies = [ [[package]] name = "sentry-types" -version = "0.31.7" +version = "0.31.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e663b3eb62ddfc023c9cf5432daf5f1a4f6acb1df4d78dd80b740b32dd1a740" +checksum = "da956cca56e0101998c8688bc65ce1a96f00673a0e58e663664023d4c7911e82" dependencies = [ "debugid", "hex", @@ -1951,9 +1912,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.189" +version = "1.0.193" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e422a44e74ad4001bdc8eede9a4570ab52f71190e9c076d14369f38b9200537" +checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" dependencies = [ "serde_derive", ] @@ -1969,22 +1930,22 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.189" +version = "1.0.193" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e48d1f918009ce3145511378cf68d613e3b3d9137d67272562080d68a2b32d5" +checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] name = "serde_json" -version = "1.0.107" +version = "1.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65" +checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" dependencies = [ - "indexmap 2.0.2", + "indexmap 2.1.0", "itoa", "ryu", "serde", @@ -2056,7 +2017,7 @@ checksum = "91d129178576168c589c9ec973feedf7d3126c01ac2bf08795109aa35b69fb8f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -2110,9 +2071,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.11.1" +version = "1.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" +checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" [[package]] name = "socket2" @@ -2182,9 +2143,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.38" +version = "2.0.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b" +checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" dependencies = [ "proc-macro2", "quote", @@ -2232,13 +2193,13 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tempfile" -version = "3.8.0" +version = "3.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef" +checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" dependencies = [ "cfg-if", "fastrand", - "redox_syscall 0.3.5", + "redox_syscall", "rustix", "windows-sys", ] @@ -2260,7 +2221,7 @@ checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -2319,9 +2280,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.33.0" +version = "1.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f38200e3ef7995e5ef13baec2f432a6da0aa9ac495b2c0e8f3b7eec2c92d653" +checksum = "d0c014766411e834f7af5b8f4cf46257aab4036ca95e9d2c144a10f59ad6f5b9" dependencies = [ "backtrace", "bytes", @@ -2337,13 +2298,13 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" +checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -2450,7 +2411,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -2465,9 +2426,9 @@ dependencies = [ [[package]] name = "tracing-log" -version = "0.1.4" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f751112709b4e791d8ce53e32c4ed2d353565a795ce84da2285393f41557bdf2" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" dependencies = [ "log", "once_cell", @@ -2476,9 +2437,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30a651bc37f915e81f087d86e62a18eec5f79550c7faff886f7090b4ea757c77" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" dependencies = [ "matchers", "nu-ansi-term", @@ -2614,9 +2575,9 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "ureq" -version = "2.8.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5ccd538d4a604753ebc2f17cd9946e89b77bf87f6a8e2309667c6f2e87855e3" +checksum = "7830e33f6e25723d41a63f77e434159dad02919f18f55a512b5f16f3b1d77138" dependencies = [ "base64 0.21.5", "log", @@ -2639,9 +2600,9 @@ dependencies = [ [[package]] name = "uuid" -version = "1.5.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ad59a7560b41a70d191093a945f0b87bc1deeda46fb237479708a1d6b6cdfc" +checksum = "5e395fcf16a7a3d8127ec99782007af141946b4795001f876d54fb0d55978560" dependencies = [ "getrandom", "serde", @@ -2682,9 +2643,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.87" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" +checksum = "7daec296f25a1bae309c0cd5c29c4b260e510e6d813c286b19eaadf409d40fce" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -2692,24 +2653,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.87" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" +checksum = "e397f4664c0e4e428e8313a469aaa58310d302159845980fd23b0f22a847f217" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.37" +version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" +checksum = "9afec9963e3d0994cac82455b2b3502b81a7f40f9a0d32181f7528d9f4b43e02" dependencies = [ "cfg-if", "js-sys", @@ -2719,9 +2680,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.87" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" +checksum = "5961017b3b08ad5f3fe39f1e79877f8ee7c23c5e5fd5eb80de95abc41f1f16b2" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2729,28 +2690,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.87" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" +checksum = "c5353b8dab669f5e10f5bd76df26a9360c748f054f862ff5f3f8aae0c7fb3907" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.87" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" +checksum = "0d046c5d029ba91a1ed14da14dca44b68bf2f124cfbaf741c54151fdb3e0750b" [[package]] name = "web-sys" -version = "0.3.64" +version = "0.3.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" +checksum = "5db499c5f66323272151db0e666cd34f78617522fb0c1604d31a27c50c206a85" dependencies = [ "js-sys", "wasm-bindgen", @@ -2886,26 +2847,26 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.7.15" +version = "0.7.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81ba595b9f2772fbee2312de30eeb80ec773b4cb2f1e8098db024afadda6c06f" +checksum = "e97e415490559a91254a2979b4829267a57d2fcd741a98eee8b722fb57289aa0" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.15" +version = "0.7.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "772666c41fb6dceaf520b564b962d738a8e1a83b41bd48945f50837aed78bb1d" +checksum = "dd7e48ccf166952882ca8bd778a43502c64f33bf94c12ebe2a7f08e5a0f6689f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] name = "zeroize" -version = "1.6.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" diff --git a/clearing-house-app/Cargo.toml b/clearing-house-app/Cargo.toml index dc5b9252..6319cd4b 100644 --- a/clearing-house-app/Cargo.toml +++ b/clearing-house-app/Cargo.toml @@ -12,9 +12,9 @@ edition = "2021" # JWT biscuit = "0.6.0" # Database -mongodb = { version = ">= 2.7.0" , features = ["openssl-tls"]} +mongodb = { version = ">= 2.7.0", features = ["openssl-tls"] } # Serialization -serde = { version = ">1.0.184", features = ["derive"] } +serde = { version = "> 1.0.184", features = ["derive"] } serde_json = "1" # Error handling anyhow = "1" @@ -26,7 +26,6 @@ aes = "0.8.3" aes-gcm-siv = "0.11.1" hkdf = "0.12.3" sha2 = "0.10.7" -blake2-rfc = "0.2.18" ring = "0.16.20" # Fixed size arrays generic-array = "0.14.7" @@ -54,7 +53,7 @@ axum = { version = "0.6.20", features = ["json", "http2"] } # Helper to allow defining traits for async functions async-trait = "0.1.73" # Helper for working with futures -futures = "0.3.28" +futures = "0.3.29" thiserror = "1.0.48" sentry = { version = "0.31.7", optional = true } @@ -62,7 +61,9 @@ sentry = { version = "0.31.7", optional = true } # Controlling execution of unit test cases, which could interfere with each other serial_test = "2.0.0" # Tempfile creation for testing -tempfile = "3.8.0" +tempfile = "3.8" +tower = { version = "0.4", features = ["util"] } +hyper = { version = "0.14.27", features = ["full"] } [features] default = [] diff --git a/clearing-house-app/src/db/doc_store.rs b/clearing-house-app/src/db/doc_store.rs index 449872b6..a7c1b2b3 100644 --- a/clearing-house-app/src/db/doc_store.rs +++ b/clearing-house-app/src/db/doc_store.rs @@ -11,7 +11,7 @@ use anyhow::anyhow; use futures::StreamExt; use mongodb::bson::doc; use mongodb::options::{ - AggregateOptions, CreateCollectionOptions, IndexOptions, UpdateOptions, WriteConcern, + AggregateOptions, CreateCollectionOptions, UpdateOptions, WriteConcern, }; use mongodb::{bson, Client, IndexModel}; @@ -86,7 +86,7 @@ impl DataStore { }; // This purpose of this index is to ensure that the transaction counter is unique - let mut index_options = IndexOptions::default(); + /*let mut index_options = IndexOptions::default(); index_options.unique = Some(true); let mut index_model = IndexModel::default(); index_model.keys = doc! {format!("{}.{}",MONGO_DOC_ARRAY, MONGO_TC): 1}; @@ -107,7 +107,7 @@ impl DataStore { debug!("... failed."); return Err(anyhow!("Failed to create index")); } - } + }*/ // This creates a compound index over pid and the timestamp to enable paging using buckets let mut compound_index_model = IndexModel::default(); @@ -163,7 +163,7 @@ impl DataStore { MONGO_DOC_ARRAY: mongodb::bson::to_bson(&bucket_update)?, }, "$inc": {"counter": 1}, - "$setOnInsert": { "_id": format!("{}_{}", doc.pid.clone(), doc.ts), MONGO_DT_ID: doc.dt_id.clone(), MONGO_FROM_TS: doc.ts}, + "$setOnInsert": { "_id": format!("{}_{}_{}", doc.pid.clone(), doc.ts, crate::util::new_uuid()), MONGO_DT_ID: doc.dt_id.clone(), MONGO_FROM_TS: doc.ts}, "$set": {MONGO_TO_TS: doc.ts}, }, update_options).await { Ok(_r) => { @@ -326,14 +326,14 @@ impl DataStore { doc! {"$skip": skip_buckets}, // worst case: overlap between two buckets. doc! {"$limit": 2}, - doc! {"$unwind": format ! ("${}", MONGO_DOC_ARRAY)}, + doc! {"$unwind": format! ("${}", MONGO_DOC_ARRAY)}, doc! {"$replaceRoot": { "newRoot": "$documents"}}, doc! {"$match":{ MONGO_TS: {"$gte": date_from.timestamp(), "$lte": date_to.timestamp()} }}, doc! {"$sort": {MONGO_TS: sort_order}}, doc! {"$skip": start_entry as i32}, - doc! { "$limit": size as i32}, + doc! {"$limit": size as i32}, ]; let coll = self @@ -483,8 +483,6 @@ mod bucket { pub struct DocumentBucketUpdate { pub id: String, pub ts: i64, - pub tc: i64, - pub hash: String, pub keys_ct: String, pub cts: Vec, } @@ -494,8 +492,6 @@ mod bucket { DocumentBucketUpdate { id: doc.id.clone(), ts: doc.ts, - tc: doc.tc, - hash: doc.hash.clone(), keys_ct: doc.keys_ct.clone(), cts: doc.cts.to_vec(), } @@ -512,8 +508,6 @@ mod bucket { dt_id, pid, ts: bucket_update.ts, - tc: bucket_update.tc, - hash: bucket_update.hash.clone(), keys_ct: bucket_update.keys_ct.clone(), cts: bucket_update.cts.to_vec(), } diff --git a/clearing-house-app/src/lib.rs b/clearing-house-app/src/lib.rs new file mode 100644 index 00000000..7f8cfc73 --- /dev/null +++ b/clearing-house-app/src/lib.rs @@ -0,0 +1,85 @@ +#[macro_use] +extern crate tracing; + +use crate::db::doc_store::DataStore; +use crate::db::key_store::KeyStore; +use crate::db::process_store::ProcessStore; +use crate::model::constants::ENV_LOGGING_SERVICE_ID; +use crate::util::ServiceConfig; +use std::sync::Arc; + +mod config; +mod crypto; +mod db; +pub mod model; +mod ports; +mod services; +pub mod util; + +/// Contains the application state +#[derive(Clone)] +pub struct AppState { + #[cfg_attr(not(doc_type), allow(dead_code))] + pub keyring_service: Arc, + pub logging_service: Arc, + pub service_config: Arc, + pub signing_key_path: String, +} + +impl AppState { + /// Initialize the application state from config + async fn init(conf: &config::CHConfig) -> anyhow::Result { + trace!("Initializing Process store"); + let process_store = + ProcessStore::init_process_store(&conf.process_database_url, conf.clear_db) + .await + .expect("Failure to initialize process store! Exiting..."); + trace!("Initializing Keyring store"); + let keyring_store = KeyStore::init_keystore(&conf.keyring_database_url, conf.clear_db) + .await + .expect("Failure to initialize keyring store! Exiting..."); + trace!("Initializing Document store"); + let doc_store = DataStore::init_datastore(&conf.document_database_url, conf.clear_db) + .await + .expect("Failure to initialize document store! Exiting..."); + + trace!("Initializing services"); + let keyring_service = Arc::new(services::keyring_service::KeyringService::new( + keyring_store, + )); + let doc_service = Arc::new(services::document_service::DocumentService::new( + doc_store, + keyring_service.clone(), + )); + let logging_service = Arc::new(services::logging_service::LoggingService::new( + process_store, + doc_service.clone(), + )); + + let service_config = Arc::new(util::init_service_config( + ENV_LOGGING_SERVICE_ID.to_string(), + )?); + let signing_key = util::init_signing_key(conf.signing_key.as_deref())?; + + Ok(Self { + signing_key_path: signing_key, + service_config, + keyring_service, + logging_service, + }) + } +} + +pub async fn app() -> anyhow::Result { + // Read configuration + let conf = config::read_config(None); + config::configure_logging(&conf); + + tracing::info!("Config read successfully! Initializing application ..."); + + // Initialize application state + let app_state = AppState::init(&conf).await?; + + // Setup router + Ok(ports::router().with_state(app_state)) +} \ No newline at end of file diff --git a/clearing-house-app/src/main.rs b/clearing-house-app/src/main.rs index e59ecdb7..56bf783d 100644 --- a/clearing-house-app/src/main.rs +++ b/clearing-house-app/src/main.rs @@ -1,104 +1,25 @@ #![forbid(unsafe_code)] #![warn(clippy::unwrap_used)] -#[macro_use] -extern crate tracing; - -use crate::db::doc_store::DataStore; -use crate::db::key_store::KeyStore; -use crate::db::process_store::ProcessStore; -use crate::model::constants::ENV_LOGGING_SERVICE_ID; -use crate::util::ServiceConfig; use std::net::SocketAddr; -use std::sync::Arc; - -mod config; -mod crypto; -mod db; -mod model; -mod ports; -mod services; -mod util; - -/// Contains the application state -#[derive(Clone)] -pub(crate) struct AppState { - #[cfg_attr(not(doc_type), allow(dead_code))] - pub keyring_service: Arc, - pub logging_service: Arc, - pub service_config: Arc, - pub signing_key_path: String, -} - -impl AppState { - /// Initialize the application state from config - async fn init(conf: &config::CHConfig) -> anyhow::Result { - trace!("Initializing Process store"); - let process_store = - ProcessStore::init_process_store(&conf.process_database_url, conf.clear_db) - .await - .expect("Failure to initialize process store! Exiting..."); - trace!("Initializing Keyring store"); - let keyring_store = KeyStore::init_keystore(&conf.keyring_database_url, conf.clear_db) - .await - .expect("Failure to initialize keyring store! Exiting..."); - trace!("Initializing Document store"); - let doc_store = DataStore::init_datastore(&conf.document_database_url, conf.clear_db) - .await - .expect("Failure to initialize document store! Exiting..."); - - trace!("Initializing services"); - let keyring_service = Arc::new(services::keyring_service::KeyringService::new( - keyring_store, - )); - let doc_service = Arc::new(services::document_service::DocumentService::new( - doc_store, - keyring_service.clone(), - )); - let logging_service = Arc::new(services::logging_service::LoggingService::new( - process_store, - doc_service.clone(), - )); - - let service_config = Arc::new(util::init_service_config( - ENV_LOGGING_SERVICE_ID.to_string(), - )?); - let signing_key = util::init_signing_key(conf.signing_key.as_deref())?; - - Ok(Self { - signing_key_path: signing_key, - service_config, - keyring_service, - logging_service, - }) - } -} /// Main function: Reading config, initializing application state, starting server #[tokio::main] async fn main() -> Result<(), anyhow::Error> { #[cfg(feature = "sentry")] let _guard = sentry::init(("https://347cc3aa30aa0c07d437da8c780838d3@o4506146399322112.ingest.sentry.io/4506155710480384", sentry::ClientOptions { - release: sentry::release_name!(), - ..Default::default() + release: sentry::release_name!(), + ..Default::default() })); - // Read configuration - let conf = config::read_config(None); - config::configure_logging(&conf); - - info!("Config read successfully! Initializing application ..."); - - // Initialize application state - let app_state = AppState::init(&conf).await?; // Setup router - let app = ports::router().with_state(app_state); + let app = clearing_house_app::app().await?; // Bind port and start server let addr = SocketAddr::from(([0, 0, 0, 0], 8000)); - info!("Starting server: Listening on {}", addr); + tracing::info!("Starting server: Listening on {}", addr); Ok(axum::Server::bind(&addr) .serve(app.into_make_service()) - .with_graceful_shutdown(util::shutdown_signal()) + .with_graceful_shutdown(clearing_house_app::util::shutdown_signal()) .await?) } diff --git a/clearing-house-app/src/model/claims.rs b/clearing-house-app/src/model/claims.rs index f51fa867..d6b96cb9 100644 --- a/clearing-house-app/src/model/claims.rs +++ b/clearing-house-app/src/model/claims.rs @@ -4,7 +4,6 @@ use anyhow::Context; use axum::extract::FromRef; use axum::response::IntoResponse; use num_bigint::BigUint; -use ring::signature::KeyPair; use std::env; #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] @@ -75,8 +74,9 @@ pub fn get_jwks(key_path: &str) -> Option> .unwrap_or_else(|_| panic!("Failed to load keyfile from path {key_path}")); if let biscuit::jws::Secret::RsaKeyPair(a) = keypair { + use ring::signature::KeyPair; let pk_modulus = BigUint::from_bytes_be( - a.as_ref() + a .public_key() .modulus() .big_endian_without_leading_zero(), @@ -112,6 +112,7 @@ pub fn get_jwks(key_path: &str) -> Option> } pub fn get_fingerprint(key_path: &str) -> Option { + use ring::signature::KeyPair; let keypair = biscuit::jws::Secret::rsa_keypair_from_file(key_path) .unwrap_or_else(|_| panic!("File exists at '{key_path}' and is a valid RSA keypair")); if let biscuit::jws::Secret::RsaKeyPair(a) = keypair { @@ -135,6 +136,50 @@ pub fn get_fingerprint(key_path: &str) -> Option { } } +pub fn create_token< + T: std::fmt::Display + Clone + serde::Serialize + for<'de> serde::Deserialize<'de>, +>( + issuer: &str, + audience: &str, + private_claims: &T, +) -> String { + let signing_secret = match env::var(ENV_SHARED_SECRET) { + Ok(secret) => biscuit::jws::Secret::Bytes(secret.to_string().into_bytes()), + Err(_) => { + panic!( + "Shared Secret not configured. Please configure environment variable {}", + ENV_SHARED_SECRET + ); + } + }; + let expiration_date = chrono::Utc::now() + chrono::Duration::minutes(5); + + let claims = biscuit::ClaimsSet:: { + registered: biscuit::RegisteredClaims { + issuer: Some(issuer.to_string()), + issued_at: Some(biscuit::Timestamp::from(chrono::Utc::now())), + audience: Some(biscuit::SingleOrMultiple::Single(audience.to_string())), + expiry: Some(biscuit::Timestamp::from(expiration_date)), + ..Default::default() + }, + private: private_claims.clone(), + }; + + // Construct the JWT + let jwt = biscuit::jws::Compact::new_decoded( + From::from(biscuit::jws::RegisteredHeader { + algorithm: biscuit::jwa::SignatureAlgorithm::HS256, + ..Default::default() + }), + claims, + ); + + jwt.into_encoded(&signing_secret) + .unwrap() + .unwrap_encoded() + .to_string() +} + pub fn decode_token serde::Deserialize<'de>>( token: &str, audience: &str, diff --git a/clearing-house-app/src/model/document.rs b/clearing-house-app/src/model/document.rs index 383231bb..77358eda 100644 --- a/clearing-house-app/src/model/document.rs +++ b/clearing-house-app/src/model/document.rs @@ -3,8 +3,6 @@ use crate::model::crypto::{KeyEntry, KeyMap}; use crate::util::new_uuid; use aes_gcm_siv::aead::Aead; use aes_gcm_siv::{Aes256GcmSiv, KeyInit}; -use base64::Engine; -use blake2_rfc::blake2b::Blake2b; use chrono::Local; use generic_array::GenericArray; use std::collections::HashMap; @@ -79,7 +77,6 @@ pub struct Document { pub dt_id: String, pub pid: String, pub ts: i64, - pub tc: i64, pub parts: Vec, } @@ -132,16 +129,11 @@ impl Document { self.pid.clone(), self.dt_id.clone(), self.ts, - self.tc, key_ct, cts, )) } - pub fn get_formatted_tc(&self) -> String { - format_tc(self.tc) - } - pub fn get_parts_map(&self) -> HashMap { let mut p_map = HashMap::with_capacity(self.parts.len()); for part in self.parts.iter() { @@ -150,13 +142,12 @@ impl Document { p_map } - pub fn new(pid: String, dt_id: String, tc: i64, parts: Vec) -> Document { + pub fn new(pid: String, dt_id: String, parts: Vec) -> Document { Document { id: Document::create_uuid(), dt_id, pid, ts: Local::now().timestamp(), - tc, parts, } } @@ -166,7 +157,6 @@ impl Document { pid: String, dt_id: String, ts: i64, - tc: i64, parts: Vec, ) -> Document { Document { @@ -174,7 +164,6 @@ impl Document { dt_id, pid, ts, - tc, parts, } } @@ -186,8 +175,6 @@ pub struct EncryptedDocument { pub pid: String, pub dt_id: String, pub ts: i64, - pub tc: i64, - pub hash: String, pub keys_ct: String, pub cts: Vec, } @@ -229,42 +216,15 @@ impl EncryptedDocument { self.pid.clone(), self.dt_id.clone(), self.ts, - self.tc, pts, )) } - pub fn get_formatted_tc(&self) -> String { - format_tc(self.tc) - } - - pub fn hash(&self) -> String { - let mut hasher = Blake2b::new(64); - - hasher.update(self.id.as_bytes()); - hasher.update(self.pid.as_bytes()); - hasher.update(self.dt_id.as_bytes()); - hasher.update(self.get_formatted_tc().as_bytes()); - hasher.update(self.ts.to_string().as_bytes()); - hasher.update(self.hash.as_bytes()); - hasher.update(self.keys_ct.as_bytes()); - let mut cts = self.cts.clone(); - cts.sort(); - for ct in cts.iter() { - hasher.update(ct.as_bytes()); - } - - let res = base64::engine::general_purpose::STANDARD.encode(hasher.finalize()); - debug!("hashed cts: '{}'", &res); - res - } - pub fn new( id: String, pid: String, dt_id: String, ts: i64, - tc: i64, keys_ct: String, cts: Vec, ) -> EncryptedDocument { @@ -273,8 +233,6 @@ impl EncryptedDocument { pid, dt_id, ts, - tc, - hash: String::from("0"), keys_ct, cts, } @@ -295,29 +253,3 @@ pub fn restore_pt_no_dt(pt: &str) -> anyhow::Result<(String, String)> { fn format_pt_for_storage(field_name: &str, pt: &str) -> String { format!("{}{}{}", field_name, SPLIT_CT, pt) } - -fn format_tc(tc: i64) -> String { - format!("{:08}", tc) -} - -#[cfg(test)] -mod test { - /// Purpose of this test case: The `base64::encode` function has been deprecated in favor of - /// `base64::engine::Engine::encode`. This test case ensures that the new function works as - /// expected. - #[test] - fn hash() { - let doc = super::EncryptedDocument::new( - String::from("id"), - String::from("pid"), - String::from("dt_id"), - 42, - 12, - String::from("keys_ct"), - vec![String::from("ct1"), String::from("ct2")], - ); - - let hash = doc.hash(); - assert_eq!("X/BsEutzaPbi555duyusiD9z5aUCwE7oNIMteMtdYLEAqJ7FJ0Ln13J3t1Qw8MMJhLCb9rRE8bRbqHtV4mYqRA==", hash); - } -} diff --git a/clearing-house-app/src/model/ids/message.rs b/clearing-house-app/src/model/ids/message.rs index ee068246..10e5ed4f 100644 --- a/clearing-house-app/src/model/ids/message.rs +++ b/clearing-house-app/src/model/ids/message.rs @@ -123,7 +123,7 @@ impl Default for IdsMessage { pid: None, model_version: "".to_string(), correlation_message: None, - issued: InfoModelDateTime::new(), + issued: InfoModelDateTime::default(), issuer_connector: InfoModelId::new("".to_string()), sender_agent: "https://w3id.org/idsa/core/ClearingHouse".to_string(), recipient_connector: None, @@ -334,7 +334,6 @@ impl TryFrom for Document { Ok(Document::new( m.pid.ok_or(serde_json::Error::custom("PID missing"))?, DEFAULT_DOC_TYPE.to_string(), - -1, doc_parts, )) } diff --git a/clearing-house-app/src/model/ids/mod.rs b/clearing-house-app/src/model/ids/mod.rs index 0882585d..5f48bdb9 100644 --- a/clearing-house-app/src/model/ids/mod.rs +++ b/clearing-house-app/src/model/ids/mod.rs @@ -33,6 +33,7 @@ impl InfoModelComplexId { InfoModelComplexId { id: Some(id) } } } + impl From for InfoModelComplexId { fn from(id: String) -> InfoModelComplexId { InfoModelComplexId::new(id) @@ -61,6 +62,7 @@ impl std::fmt::Display for InfoModelId { Ok(()) } } + impl From for InfoModelId { fn from(id: String) -> InfoModelId { InfoModelId::SimpleId(id) @@ -74,8 +76,8 @@ pub enum InfoModelDateTime { Time(chrono::DateTime), } -impl InfoModelDateTime { - pub fn new() -> InfoModelDateTime { +impl Default for InfoModelDateTime { + fn default() -> InfoModelDateTime { InfoModelDateTime::Time(chrono::Local::now()) } } @@ -94,9 +96,9 @@ impl std::fmt::Display for InfoModelDateTime { pub struct InfoModelTimeStamp { //IDS name #[serde( - rename = "@type", - alias = "type", - skip_serializing_if = "Option::is_none" + rename = "@type", + alias = "type", + skip_serializing_if = "Option::is_none" )] pub format: Option, //IDS name @@ -112,6 +114,7 @@ impl Default for InfoModelTimeStamp { } } } + impl std::fmt::Display for InfoModelTimeStamp { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match serde_json::to_string(&self) { @@ -133,7 +136,7 @@ The message classes relevant for the Connector to Connector communication are li available in the Information Model can be found here. Based on [v4.2.0](https://github.com/International-Data-Spaces-Association/InformationModel/blob/v4.2.0/taxonomies/Message.ttl) -*/ + */ #[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq)] pub enum MessageType { #[serde(rename = "ids:Message")] diff --git a/clearing-house-app/src/model/mod.rs b/clearing-house-app/src/model/mod.rs index 653e01e3..f2aaa61a 100644 --- a/clearing-house-app/src/model/mod.rs +++ b/clearing-house-app/src/model/mod.rs @@ -1,4 +1,4 @@ -pub(crate) mod claims; +pub mod claims; pub mod constants; pub(crate) mod crypto; pub(crate) mod doc_type; diff --git a/clearing-house-app/src/model/process.rs b/clearing-house-app/src/model/process.rs index 9ea3c5be..cda0edfb 100644 --- a/clearing-house-app/src/model/process.rs +++ b/clearing-house-app/src/model/process.rs @@ -31,12 +31,10 @@ pub struct Receipt { #[derive(Debug, PartialEq, Clone, serde::Serialize, serde::Deserialize)] pub struct DataTransaction { - pub transaction_id: String, pub timestamp: i64, pub process_id: String, pub document_id: String, pub payload: String, - pub chain_hash: String, pub client_id: String, pub clearing_house_version: String, } @@ -78,12 +76,10 @@ impl From for DataTransaction { Err(e) => { println!("Error occurred: {:#?}", e); DataTransaction { - transaction_id: "error".to_string(), timestamp: 0, process_id: "error".to_string(), document_id: "error".to_string(), payload: "error".to_string(), - chain_hash: "error".to_string(), client_id: "error".to_string(), clearing_house_version: "error".to_string(), } diff --git a/clearing-house-app/src/services/document_service.rs b/clearing-house-app/src/services/document_service.rs index 73c62074..926e170b 100644 --- a/clearing-house-app/src/services/document_service.rs +++ b/clearing-house-app/src/services/document_service.rs @@ -23,8 +23,6 @@ pub enum DocumentServiceError { source: anyhow::Error, description: String, }, - #[error("Error while creating the chain hash!")] - ChainHashError, #[error("Error while retrieving keys from keyring!")] KeyringServiceError(#[from] crate::services::keyring_service::KeyringServiceError), #[error("Invalid dates in query!")] @@ -53,9 +51,6 @@ impl axum::response::IntoResponse for DocumentServiceError { format!("{}: {}", description, source), ) .into_response(), - Self::ChainHashError => { - (StatusCode::INTERNAL_SERVER_ERROR, self.to_string()).into_response() - } Self::KeyringServiceError(e) => e.into_response(), Self::InvalidDates => (StatusCode::BAD_REQUEST, self.to_string()).into_response(), Self::NotFound => (StatusCode::NOT_FOUND, self.to_string()).into_response(), @@ -130,7 +125,7 @@ impl DocumentService { }?; debug!("start encryption"); - let mut enc_doc = match doc.encrypt(keys) { + let enc_doc = match doc.encrypt(keys) { Ok(ct) => { debug!("got ct"); Ok(ct) @@ -141,31 +136,9 @@ impl DocumentService { } }?; - // chain the document to previous documents - debug!("add the chain hash..."); - // get the document with the previous tc - match self.db.get_document_with_previous_tc(doc.tc).await { - Ok(Some(previous_doc)) => { - enc_doc.hash = previous_doc.hash(); - } - Ok(None) => { - if doc.tc == 0 { - info!("No entries found for pid {}. Beginning new chain!", doc.pid); - } else { - // If this happens, db didn't find a tc entry that should exist. - return Err(DocumentServiceError::ChainHashError); - } - } - Err(e) => { - error!("Error while creating the chain hash: {:?}", e); - return Err(DocumentServiceError::ChainHashError); - } - } - // prepare the success result message - let receipt = - DocumentReceipt::new(enc_doc.ts, &enc_doc.pid, &enc_doc.id, &enc_doc.hash); + DocumentReceipt::new(enc_doc.ts, &enc_doc.pid, &enc_doc.id); trace!("storing document ...."); // store document diff --git a/clearing-house-app/src/services/logging_service.rs b/clearing-house-app/src/services/logging_service.rs index d1a33281..213699e8 100644 --- a/clearing-house-app/src/services/logging_service.rs +++ b/clearing-house-app/src/services/logging_service.rs @@ -74,7 +74,6 @@ impl axum::response::IntoResponse for LoggingServiceError { pub struct LoggingService { db: ProcessStore, doc_api: Arc, - write_lock: Arc>, } impl LoggingService { @@ -82,7 +81,6 @@ impl LoggingService { LoggingService { db, doc_api, - write_lock: Arc::new(tokio::sync::Mutex::new(())), } } @@ -133,64 +131,31 @@ impl LoggingService { // transform message to document debug!("transforming message to document..."); - let mut doc = Document::try_from(m).map_err(LoggingServiceError::ParsingError)?; - - // lock write access - let _x = self.write_lock.lock().await; - match self.db.get_transaction_counter().await { - Ok(Some(tid)) => { - debug!("Storing document..."); - doc.tc = tid; - // TODO: ChClaims usage check - match self - .doc_api - .create_enc_document(ChClaims::new(user), doc.clone()) - .await - { - Ok(doc_receipt) => { - debug!("Increase transaction counter"); - match self.db.increment_transaction_counter().await { - Ok(Some(_tid)) => { - debug!("Creating receipt..."); - let transaction = DataTransaction { - transaction_id: doc.get_formatted_tc(), - timestamp: doc_receipt.timestamp, - process_id: doc_receipt.pid, - document_id: doc_receipt.doc_id, - payload, - chain_hash: doc_receipt.chain_hash, - client_id: user.to_owned(), - clearing_house_version: env!("CARGO_PKG_VERSION").to_string(), - }; - debug!("...done. Signing receipt..."); - Ok(transaction.sign(key_path)) - } - Ok(None) => { - unreachable!("increment_transaction_counter never returns None!") - } - Err(e) => { - error!("Error while incrementing transaction id!"); - Err(LoggingServiceError::DatabaseError { - source: e, - description: "Error while incrementing transaction id!" - .to_string(), - }) // InternalError - } - } - } - Err(e) => { - error!("Error while creating document: {:?}", e); - Err(LoggingServiceError::DocumentServiceError(e)) - } - } + let doc = Document::try_from(m).map_err(LoggingServiceError::ParsingError)?; + + debug!("Storing document..."); + // TODO: ChClaims usage check + match self + .doc_api + .create_enc_document(ChClaims::new(user), doc.clone()) + .await + { + Ok(doc_receipt) => { + debug!("Creating receipt..."); + let transaction = DataTransaction { + timestamp: doc_receipt.timestamp, + process_id: doc_receipt.pid, + document_id: doc_receipt.doc_id, + payload, + client_id: user.to_owned(), + clearing_house_version: env!("CARGO_PKG_VERSION").to_string(), + }; + debug!("...done. Signing receipt..."); + Ok(transaction.sign(key_path)) } - Ok(None) => unreachable!("get_transaction_counter never returns None!"), Err(e) => { - error!("Error while getting transaction id!"); - Err(LoggingServiceError::DatabaseError { - source: e, - description: "Error while getting transaction id".to_string(), - }) // InternalError + error!("Error while creating document: {:?}", e); + Err(LoggingServiceError::DocumentServiceError(e)) } } } diff --git a/clearing-house-app/src/services/mod.rs b/clearing-house-app/src/services/mod.rs index a5f1e207..98888eec 100644 --- a/clearing-house-app/src/services/mod.rs +++ b/clearing-house-app/src/services/mod.rs @@ -15,16 +15,14 @@ pub struct DocumentReceipt { pub timestamp: i64, pub pid: String, pub doc_id: String, - pub chain_hash: String, } impl DocumentReceipt { - pub fn new(timestamp: i64, pid: &str, doc_id: &str, chain_hash: &str) -> DocumentReceipt { + pub fn new(timestamp: i64, pid: &str, doc_id: &str) -> DocumentReceipt { DocumentReceipt { timestamp, pid: pid.to_string(), doc_id: doc_id.to_string(), - chain_hash: chain_hash.to_string(), } } } diff --git a/clearing-house-app/src/util.rs b/clearing-house-app/src/util.rs index bcbab1c8..3c39ce3c 100644 --- a/clearing-house-app/src/util.rs +++ b/clearing-house-app/src/util.rs @@ -1,7 +1,7 @@ use anyhow::Context; #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] -pub(crate) struct ServiceConfig { +pub struct ServiceConfig { pub service_id: String, } @@ -33,7 +33,7 @@ pub(super) fn init_signing_key(signing_key_path: Option<&str>) -> anyhow::Result } /// Signal handler to catch a Ctrl+C and initiate a graceful shutdown -pub(super) async fn shutdown_signal() { +pub async fn shutdown_signal() { let ctrl_c = async { tokio::signal::ctrl_c() .await diff --git a/clearing-house-app/tests/README.md b/clearing-house-app/tests/README.md new file mode 100644 index 00000000..52e2628b --- /dev/null +++ b/clearing-house-app/tests/README.md @@ -0,0 +1,5 @@ +# Integration Tests + +Prerequisites: + +- MongoDB running on `localhost:27017` \ No newline at end of file diff --git a/clearing-house-app/tests/log.rs b/clearing-house-app/tests/log.rs new file mode 100644 index 00000000..610785c0 --- /dev/null +++ b/clearing-house-app/tests/log.rs @@ -0,0 +1,87 @@ +#![cfg(test)] + +use axum::http::{Request, StatusCode}; +use tower::ServiceExt; +use clearing_house_app::model::ids::message::IdsMessage; +use clearing_house_app::model::ids::{InfoModelDateTime, InfoModelId, MessageType}; +use clearing_house_app::model::ids::request::ClearingHouseMessage; +use clearing_house_app::util::new_uuid; +use clearing_house_app::model::{claims::create_token, constants::SERVICE_HEADER}; +use clearing_house_app::model::claims::ChClaims; + +#[tokio::test] +#[ignore] +async fn log_message() { + std::env::set_var("SERVICE_ID_LOG", "test"); + std::env::set_var("SHARED_SECRET", "test"); + std::env::set_var("CH_APP_LOG_LEVEL", "TRACE"); + std::env::set_var("CH_CLEAR_DB", "false"); + + let app = clearing_house_app::app().await.unwrap(); + + let pid = new_uuid(); + + let msg = ClearingHouseMessage { + header: IdsMessage { + context: Some(std::collections::HashMap::from([ + ("ids".to_string(), "https://w3id.org/idsa/core/".to_string()), + ( + "idsc".to_string(), + "https://w3id.org/idsa/code/".to_string(), + ), + ])), + type_message: MessageType::Message, + id: Some(new_uuid()), + pid: None, + model_version: "".to_string(), + correlation_message: None, + issued: InfoModelDateTime::default(), + issuer_connector: InfoModelId::new("".to_string()), + sender_agent: "https://w3id.org/idsa/core/ClearingHouse".to_string(), + recipient_connector: None, + recipient_agent: None, + transfer_contract: None, + content_version: None, + security_token: None, + authorization_token: None, + payload: None, + payload_type: None, + }, + payload: Some("test".to_string()), + payload_type: None, + }; + + let claims = ChClaims::new("test"); + + // Log + let response = app.clone() + .oneshot(Request::builder() + .uri(format!("/messages/log/{}", pid)) + .method("POST") + .header("Content-Type", "application/json") + .header(SERVICE_HEADER, create_token("test", "test", &claims)) + .body(serde_json::to_string(&msg).unwrap().into()).unwrap()) + .await + .unwrap(); + + assert_eq!(response.status(), StatusCode::CREATED); + + let body = hyper::body::to_bytes(response.into_body()).await.unwrap(); + assert!(!body.is_empty()); + println!("Receipt: {:?}", body); +/* + // Query + let query_resp = app + .oneshot(Request::builder() + .uri(format!("/messages/query/{}", pid)) + .method("POST") + .header("Content-Type", "application/json") + .header(SERVICE_HEADER, create_token("test", "test", &claims)) + .body(serde_json::to_string(&msg).unwrap().into()).unwrap()) + .await + .unwrap(); + + let body = hyper::body::to_bytes(query_resp.into_body()).await.unwrap(); + println!("Query: {:?}", body); + */ +} \ No newline at end of file diff --git a/clearing-house-app/tests/public_key.rs b/clearing-house-app/tests/public_key.rs new file mode 100644 index 00000000..f76626d4 --- /dev/null +++ b/clearing-house-app/tests/public_key.rs @@ -0,0 +1,21 @@ +use axum::body::Body; +use axum::http::{Request, StatusCode}; +use tower::ServiceExt; + +#[tokio::test] +#[ignore] +async fn retrieve_public_key() { + std::env::set_var("SERVICE_ID_LOG", "test"); + + let app = clearing_house_app::app().await.unwrap(); + + let response = app + .oneshot(Request::builder().uri("/.well-known/jwks.json").body(Body::empty()).unwrap()) + .await + .unwrap(); + + assert_eq!(response.status(), StatusCode::OK); + + let body = hyper::body::to_bytes(response.into_body()).await.unwrap(); + assert!(!body.is_empty()); +} \ No newline at end of file From bcc6a5604162d6d4166f00e57587e9bab049c565 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maximilian=20Sch=C3=B6nenberg?= Date: Wed, 22 Nov 2023 11:32:48 +0100 Subject: [PATCH 2/5] fix(ch-app): Fix integration test case log --- clearing-house-app/tests/log.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/clearing-house-app/tests/log.rs b/clearing-house-app/tests/log.rs index 610785c0..64a50bb9 100644 --- a/clearing-house-app/tests/log.rs +++ b/clearing-house-app/tests/log.rs @@ -15,7 +15,7 @@ async fn log_message() { std::env::set_var("SERVICE_ID_LOG", "test"); std::env::set_var("SHARED_SECRET", "test"); std::env::set_var("CH_APP_LOG_LEVEL", "TRACE"); - std::env::set_var("CH_CLEAR_DB", "false"); + std::env::set_var("CH_APP_CLEAR_DB", "false"); let app = clearing_house_app::app().await.unwrap(); @@ -69,7 +69,7 @@ async fn log_message() { let body = hyper::body::to_bytes(response.into_body()).await.unwrap(); assert!(!body.is_empty()); println!("Receipt: {:?}", body); -/* + // Query let query_resp = app .oneshot(Request::builder() @@ -83,5 +83,5 @@ async fn log_message() { let body = hyper::body::to_bytes(query_resp.into_body()).await.unwrap(); println!("Query: {:?}", body); - */ + } \ No newline at end of file From cef068b2e41916a05101dab5e3255114a49a95c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maximilian=20Sch=C3=B6nenberg?= Date: Thu, 23 Nov 2023 10:04:34 +0100 Subject: [PATCH 3/5] feat(ch-app): Add and debug integration test --- clearing-house-app/Cargo.toml | 2 + clearing-house-app/src/db/doc_store.rs | 4 +- clearing-house-app/src/lib.rs | 2 +- clearing-house-app/src/model/claims.rs | 17 ++-- clearing-house-app/src/model/ids/mod.rs | 10 +-- clearing-house-app/src/model/mod.rs | 2 +- .../src/services/document_service.rs | 3 +- .../src/services/logging_service.rs | 5 +- clearing-house-app/tests/log.rs | 89 ++++++++++++++----- clearing-house-app/tests/public_key.rs | 9 +- 10 files changed, 95 insertions(+), 48 deletions(-) diff --git a/clearing-house-app/Cargo.toml b/clearing-house-app/Cargo.toml index 6319cd4b..58f3fd75 100644 --- a/clearing-house-app/Cargo.toml +++ b/clearing-house-app/Cargo.toml @@ -54,7 +54,9 @@ axum = { version = "0.6.20", features = ["json", "http2"] } async-trait = "0.1.73" # Helper for working with futures futures = "0.3.29" +# Helper for creating custom error types thiserror = "1.0.48" +# Optional: Sentry integration sentry = { version = "0.31.7", optional = true } [dev-dependencies] diff --git a/clearing-house-app/src/db/doc_store.rs b/clearing-house-app/src/db/doc_store.rs index a7c1b2b3..455c8a50 100644 --- a/clearing-house-app/src/db/doc_store.rs +++ b/clearing-house-app/src/db/doc_store.rs @@ -10,9 +10,7 @@ use crate::model::SortingOrder; use anyhow::anyhow; use futures::StreamExt; use mongodb::bson::doc; -use mongodb::options::{ - AggregateOptions, CreateCollectionOptions, UpdateOptions, WriteConcern, -}; +use mongodb::options::{AggregateOptions, CreateCollectionOptions, UpdateOptions, WriteConcern}; use mongodb::{bson, Client, IndexModel}; #[derive(Clone, Debug)] diff --git a/clearing-house-app/src/lib.rs b/clearing-house-app/src/lib.rs index 7f8cfc73..3e48c3d1 100644 --- a/clearing-house-app/src/lib.rs +++ b/clearing-house-app/src/lib.rs @@ -82,4 +82,4 @@ pub async fn app() -> anyhow::Result { // Setup router Ok(ports::router().with_state(app_state)) -} \ No newline at end of file +} diff --git a/clearing-house-app/src/model/claims.rs b/clearing-house-app/src/model/claims.rs index d6b96cb9..30958fbd 100644 --- a/clearing-house-app/src/model/claims.rs +++ b/clearing-house-app/src/model/claims.rs @@ -75,12 +75,8 @@ pub fn get_jwks(key_path: &str) -> Option> if let biscuit::jws::Secret::RsaKeyPair(a) = keypair { use ring::signature::KeyPair; - let pk_modulus = BigUint::from_bytes_be( - a - .public_key() - .modulus() - .big_endian_without_leading_zero(), - ); + let pk_modulus = + BigUint::from_bytes_be(a.public_key().modulus().big_endian_without_leading_zero()); let pk_e = BigUint::from_bytes_be( a.as_ref() .public_key() @@ -225,3 +221,12 @@ pub fn decode_token serde::Deserialize<'d .with_context(|| "Failed validating JWT")?; Ok(decoded_jwt.payload()?.private.clone()) } + +#[cfg(test)] +mod test { + #[test] + fn get_fingerprint() { + let fingerprint = super::get_fingerprint("keys/private_key.der").unwrap(); + assert_eq!(fingerprint, "Qra//29Frxbj5hh5Azef+G36SeiOm9q7s8+w8uGLD28"); + } +} diff --git a/clearing-house-app/src/model/ids/mod.rs b/clearing-house-app/src/model/ids/mod.rs index 5f48bdb9..f72ed4c5 100644 --- a/clearing-house-app/src/model/ids/mod.rs +++ b/clearing-house-app/src/model/ids/mod.rs @@ -5,9 +5,9 @@ pub mod request; #[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq)] pub struct InfoModelComplexId { - //IDS name + /// IDS name #[serde(rename = "@id", alias = "id", skip_serializing_if = "Option::is_none")] - // Correlated message, e.g. a response to a previous request + /// Correlated message, e.g. a response to a previous request pub id: Option, } @@ -96,9 +96,9 @@ impl std::fmt::Display for InfoModelDateTime { pub struct InfoModelTimeStamp { //IDS name #[serde( - rename = "@type", - alias = "type", - skip_serializing_if = "Option::is_none" + rename = "@type", + alias = "type", + skip_serializing_if = "Option::is_none" )] pub format: Option, //IDS name diff --git a/clearing-house-app/src/model/mod.rs b/clearing-house-app/src/model/mod.rs index f2aaa61a..a2040981 100644 --- a/clearing-house-app/src/model/mod.rs +++ b/clearing-house-app/src/model/mod.rs @@ -4,7 +4,7 @@ pub(crate) mod crypto; pub(crate) mod doc_type; pub(crate) mod document; pub mod ids; -pub(crate) mod process; +pub mod process; #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] pub enum SortingOrder { diff --git a/clearing-house-app/src/services/document_service.rs b/clearing-house-app/src/services/document_service.rs index 926e170b..b9f254ce 100644 --- a/clearing-house-app/src/services/document_service.rs +++ b/clearing-house-app/src/services/document_service.rs @@ -137,8 +137,7 @@ impl DocumentService { }?; // prepare the success result message - let receipt = - DocumentReceipt::new(enc_doc.ts, &enc_doc.pid, &enc_doc.id); + let receipt = DocumentReceipt::new(enc_doc.ts, &enc_doc.pid, &enc_doc.id); trace!("storing document ...."); // store document diff --git a/clearing-house-app/src/services/logging_service.rs b/clearing-house-app/src/services/logging_service.rs index 213699e8..658dc1cc 100644 --- a/clearing-house-app/src/services/logging_service.rs +++ b/clearing-house-app/src/services/logging_service.rs @@ -78,10 +78,7 @@ pub struct LoggingService { impl LoggingService { pub fn new(db: ProcessStore, doc_api: Arc) -> LoggingService { - LoggingService { - db, - doc_api, - } + LoggingService { db, doc_api } } pub async fn log( diff --git a/clearing-house-app/tests/log.rs b/clearing-house-app/tests/log.rs index 64a50bb9..dc57a8df 100644 --- a/clearing-house-app/tests/log.rs +++ b/clearing-house-app/tests/log.rs @@ -1,13 +1,16 @@ #![cfg(test)] use axum::http::{Request, StatusCode}; -use tower::ServiceExt; +use biscuit::jwa::SignatureAlgorithm::PS512; +use biscuit::jws::Secret; +use clearing_house_app::model::claims::{ChClaims, get_fingerprint}; use clearing_house_app::model::ids::message::IdsMessage; -use clearing_house_app::model::ids::{InfoModelDateTime, InfoModelId, MessageType}; use clearing_house_app::model::ids::request::ClearingHouseMessage; -use clearing_house_app::util::new_uuid; +use clearing_house_app::model::ids::{IdsQueryResult, InfoModelDateTime, InfoModelId, MessageType}; use clearing_house_app::model::{claims::create_token, constants::SERVICE_HEADER}; -use clearing_house_app::model::claims::ChClaims; +use clearing_house_app::util::new_uuid; +use tower::ServiceExt; +use clearing_house_app::model::process::Receipt; #[tokio::test] #[ignore] @@ -20,6 +23,7 @@ async fn log_message() { let app = clearing_house_app::app().await.unwrap(); let pid = new_uuid(); + let id = new_uuid(); let msg = ClearingHouseMessage { header: IdsMessage { @@ -31,7 +35,7 @@ async fn log_message() { ), ])), type_message: MessageType::Message, - id: Some(new_uuid()), + id: Some(id.clone()), pid: None, model_version: "".to_string(), correlation_message: None, @@ -53,35 +57,72 @@ async fn log_message() { let claims = ChClaims::new("test"); - // Log - let response = app.clone() - .oneshot(Request::builder() - .uri(format!("/messages/log/{}", pid)) - .method("POST") - .header("Content-Type", "application/json") - .header(SERVICE_HEADER, create_token("test", "test", &claims)) - .body(serde_json::to_string(&msg).unwrap().into()).unwrap()) + // Send log message + let response = app + .clone() + .oneshot( + Request::builder() + .uri(format!("/messages/log/{}", pid)) + .method("POST") + .header("Content-Type", "application/json") + .header(SERVICE_HEADER, create_token("test", "test", &claims)) + .body(serde_json::to_string(&msg).unwrap().into()) + .unwrap(), + ) .await .unwrap(); + // Check status code assert_eq!(response.status(), StatusCode::CREATED); - + // get body let body = hyper::body::to_bytes(response.into_body()).await.unwrap(); assert!(!body.is_empty()); - println!("Receipt: {:?}", body); - // Query + // Decode receipt + let receipt = serde_json::from_slice::(&body).unwrap(); + println!("Receipt: {:?}", receipt); + let decoded_receipt = receipt.data + .decode(&Secret::rsa_keypair_from_file("keys/private_key.der") + .expect("Loading key successfully"), PS512) + .expect("Decoding JWS successful"); + let decoded_receipt_header = decoded_receipt + .header() + .expect("Header is now already decoded"); + + assert_eq!(decoded_receipt_header.registered.key_id, get_fingerprint("keys/private_key.der")); + + let decoded_receipt_payload = decoded_receipt + .payload() + .expect("Payload is now already decoded"); + println!("Decoded Receipt: {:?}", decoded_receipt); + + assert_eq!(decoded_receipt_payload.process_id, pid); + assert_eq!(decoded_receipt_payload.payload, "test".to_string()); + + // --------------------------------------------------------------------------------------------- + + // Query ID let query_resp = app - .oneshot(Request::builder() - .uri(format!("/messages/query/{}", pid)) - .method("POST") - .header("Content-Type", "application/json") - .header(SERVICE_HEADER, create_token("test", "test", &claims)) - .body(serde_json::to_string(&msg).unwrap().into()).unwrap()) + .oneshot( + Request::builder() + .uri(format!("/messages/query/{}", pid)) + .method("POST") + .header("Content-Type", "application/json") + .header(SERVICE_HEADER, create_token("test", "test", &claims)) + .body(serde_json::to_string(&msg).unwrap().into()) + .unwrap(), + ) .await .unwrap(); + assert_eq!(query_resp.status(), StatusCode::OK); let body = hyper::body::to_bytes(query_resp.into_body()).await.unwrap(); - println!("Query: {:?}", body); + assert!(!body.is_empty()); -} \ No newline at end of file + let ids_message = serde_json::from_slice::(&body).unwrap(); + println!("IDS Query Result: {:?}", ids_message); + let query_docs = ids_message.documents; + assert_eq!(query_docs.len(), 1); + let doc = query_docs.first().expect("Document is there, just checked").to_owned(); + assert_eq!(doc.payload.expect("Payload is there"), "test".to_string()); +} diff --git a/clearing-house-app/tests/public_key.rs b/clearing-house-app/tests/public_key.rs index f76626d4..a4c19dcb 100644 --- a/clearing-house-app/tests/public_key.rs +++ b/clearing-house-app/tests/public_key.rs @@ -10,7 +10,12 @@ async fn retrieve_public_key() { let app = clearing_house_app::app().await.unwrap(); let response = app - .oneshot(Request::builder().uri("/.well-known/jwks.json").body(Body::empty()).unwrap()) + .oneshot( + Request::builder() + .uri("/.well-known/jwks.json") + .body(Body::empty()) + .unwrap(), + ) .await .unwrap(); @@ -18,4 +23,4 @@ async fn retrieve_public_key() { let body = hyper::body::to_bytes(response.into_body()).await.unwrap(); assert!(!body.is_empty()); -} \ No newline at end of file +} From 11a7314f2bfc9236561770623a98239bf71b088e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maximilian=20Sch=C3=B6nenberg?= Date: Thu, 23 Nov 2023 10:40:36 +0100 Subject: [PATCH 4/5] feat(ch-app): Use JWKS from endpoint to validate receipt --- clearing-house-app/tests/log.rs | 47 ++++++++++++++++---------- clearing-house-app/tests/public_key.rs | 3 ++ 2 files changed, 33 insertions(+), 17 deletions(-) diff --git a/clearing-house-app/tests/log.rs b/clearing-house-app/tests/log.rs index dc57a8df..652971b5 100644 --- a/clearing-house-app/tests/log.rs +++ b/clearing-house-app/tests/log.rs @@ -2,11 +2,12 @@ use axum::http::{Request, StatusCode}; use biscuit::jwa::SignatureAlgorithm::PS512; -use biscuit::jws::Secret; +use biscuit::jwk::JWKSet; +use hyper::Body; use clearing_house_app::model::claims::{ChClaims, get_fingerprint}; use clearing_house_app::model::ids::message::IdsMessage; use clearing_house_app::model::ids::request::ClearingHouseMessage; -use clearing_house_app::model::ids::{IdsQueryResult, InfoModelDateTime, InfoModelId, MessageType}; +use clearing_house_app::model::ids::{IdsQueryResult, InfoModelId, MessageType}; use clearing_house_app::model::{claims::create_token, constants::SERVICE_HEADER}; use clearing_house_app::util::new_uuid; use tower::ServiceExt; @@ -22,6 +23,26 @@ async fn log_message() { let app = clearing_house_app::app().await.unwrap(); + // Prerequisite JWKS for checking the signature + let response = app + .clone() + .oneshot( + Request::builder() + .uri("/.well-known/jwks.json") + .body(Body::empty()) + .unwrap(), + ) + .await + .unwrap(); + + assert_eq!(response.status(), StatusCode::OK); + + let body = hyper::body::to_bytes(response.into_body()).await.unwrap(); + assert!(!body.is_empty()); + let jwks = serde_json::from_slice::>(&body).expect("Decoded the JWKSet"); + + // --------------------------------------------------------------------------------------------- + // Create a message let pid = new_uuid(); let id = new_uuid(); @@ -36,20 +57,10 @@ async fn log_message() { ])), type_message: MessageType::Message, id: Some(id.clone()), - pid: None, - model_version: "".to_string(), - correlation_message: None, - issued: InfoModelDateTime::default(), - issuer_connector: InfoModelId::new("".to_string()), + model_version: "test".to_string(), + issuer_connector: InfoModelId::new("test-connector".to_string()), sender_agent: "https://w3id.org/idsa/core/ClearingHouse".to_string(), - recipient_connector: None, - recipient_agent: None, - transfer_contract: None, - content_version: None, - security_token: None, - authorization_token: None, - payload: None, - payload_type: None, + ..Default::default() }, payload: Some("test".to_string()), payload_type: None, @@ -82,8 +93,7 @@ async fn log_message() { let receipt = serde_json::from_slice::(&body).unwrap(); println!("Receipt: {:?}", receipt); let decoded_receipt = receipt.data - .decode(&Secret::rsa_keypair_from_file("keys/private_key.der") - .expect("Loading key successfully"), PS512) + .decode_with_jwks(&jwks, Some(PS512)) .expect("Decoding JWS successful"); let decoded_receipt_header = decoded_receipt .header() @@ -122,7 +132,10 @@ async fn log_message() { let ids_message = serde_json::from_slice::(&body).unwrap(); println!("IDS Query Result: {:?}", ids_message); let query_docs = ids_message.documents; + + // Check the only document in the result assert_eq!(query_docs.len(), 1); let doc = query_docs.first().expect("Document is there, just checked").to_owned(); assert_eq!(doc.payload.expect("Payload is there"), "test".to_string()); + assert_eq!(doc.model_version, "test".to_string()); } diff --git a/clearing-house-app/tests/public_key.rs b/clearing-house-app/tests/public_key.rs index a4c19dcb..3aba0514 100644 --- a/clearing-house-app/tests/public_key.rs +++ b/clearing-house-app/tests/public_key.rs @@ -1,5 +1,6 @@ use axum::body::Body; use axum::http::{Request, StatusCode}; +use biscuit::jwk::JWKSet; use tower::ServiceExt; #[tokio::test] @@ -23,4 +24,6 @@ async fn retrieve_public_key() { let body = hyper::body::to_bytes(response.into_body()).await.unwrap(); assert!(!body.is_empty()); + let jwks = serde_json::from_slice::>(&body).expect("Decoded the JWKSet"); + println!("JWKS: {:?}", jwks); } From 2779f6c5fc2f550e9e35af9c60b2ca7426d52036 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maximilian=20Sch=C3=B6nenberg?= Date: Thu, 23 Nov 2023 10:41:30 +0100 Subject: [PATCH 5/5] feat(ch-app): Removed certs folder --- clearing-house-app/certs/daps-dev.der | Bin 796 -> 0 bytes clearing-house-app/certs/daps.der | Bin 796 -> 0 bytes 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 clearing-house-app/certs/daps-dev.der delete mode 100644 clearing-house-app/certs/daps.der diff --git a/clearing-house-app/certs/daps-dev.der b/clearing-house-app/certs/daps-dev.der deleted file mode 100644 index bf5eca335b9710b0ba41a0ba3caf58f5f1c918e6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 796 zcmXqLVwNyyVw$&rnTe5!iILHOi;Y98&EuRc3p0~}iy^lGCmVAp3!5;Li>o2O0WXNd z#lu!oR9aP4V#otj4HV$!VNOXcGZZrr0r8l5cnvL$^bE}`^bGZkj7<&X#CeU34J?c- z4NOffjm)EfTr(io0?IY;BFPpR11X3t!YH;_85$b^K@+1A(2<-#AGCevWn^SzWngY% z7g|VCw^Cc3w7m~eoykqzx?|jk6Am; zyvKU})-vaKN5=A{JwFw;l}dh?_2;;AgI9Aa&r*&PGg}%`l3nbkD$DJi)vm-{p(G%+ zES-Jkgfcl!gF8nVV_7;}7O!(&yKRT*<+>G<9=6-N$y_M%J3T47cKQbygGo)Q>9q$J zu6)h({kX}Y%W~aCf-{@E@;9z->3f)N`&yw&>_gy;|JmCm!na9ApNO5At8hW`zFUaw z&yK@6?JcW%w(d&%r}?$V{ZGBU;j8l@cRy|YymTk`$;V=c9dz88x%@lIG#}Y?2e#N) zmHMxnts*=ne)$h~_QLgleFCdInV1|fpxHm9AGR|Jo?heTWgl%kDLu$P90bG z3K=MYbSQ&VNEnDUi1??~?&WxQ%V0&Pq<%t6WX#!9C(=IX?y~e%*!rV3cXs2ShdJ{ diff --git a/clearing-house-app/certs/daps.der b/clearing-house-app/certs/daps.der deleted file mode 100644 index bf5eca335b9710b0ba41a0ba3caf58f5f1c918e6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 796 zcmXqLVwNyyVw$&rnTe5!iILHOi;Y98&EuRc3p0~}iy^lGCmVAp3!5;Li>o2O0WXNd z#lu!oR9aP4V#otj4HV$!VNOXcGZZrr0r8l5cnvL$^bE}`^bGZkj7<&X#CeU34J?c- z4NOffjm)EfTr(io0?IY;BFPpR11X3t!YH;_85$b^K@+1A(2<-#AGCevWn^SzWngY% z7g|VCw^Cc3w7m~eoykqzx?|jk6Am; zyvKU})-vaKN5=A{JwFw;l}dh?_2;;AgI9Aa&r*&PGg}%`l3nbkD$DJi)vm-{p(G%+ zES-Jkgfcl!gF8nVV_7;}7O!(&yKRT*<+>G<9=6-N$y_M%J3T47cKQbygGo)Q>9q$J zu6)h({kX}Y%W~aCf-{@E@;9z->3f)N`&yw&>_gy;|JmCm!na9ApNO5At8hW`zFUaw z&yK@6?JcW%w(d&%r}?$V{ZGBU;j8l@cRy|YymTk`$;V=c9dz88x%@lIG#}Y?2e#N) zmHMxnts*=ne)$h~_QLgleFCdInV1|fpxHm9AGR|Jo?heTWgl%kDLu$P90bG z3K=MYbSQ&VNEnDUi1??~?&WxQ%V0&Pq<%t6WX#!9C(=IX?y~e%*!rV3cXs2ShdJ{