libeufin

Integration and sandbox testing for FinTech APIs and data formats
Log | Files | Refs | Submodules | README | LICENSE

commit 067448ce7cccc440f9a71552bbf217c0ba0bfdbd
parent 057f40d6179c3cfdba1089de77fd6af85f2afdd5
Author: Antoine A <>
Date:   Wed,  2 Sep 2026 14:02:05 +0200

common: port recent kotlin fixes and port more tests

Diffstat:
MCargo.lock | 378++++++++++++++++++++++++++++++++++++++-----------------------------------------
Dbuild.gradle | 82-------------------------------------------------------------------------------
Mdatabase-versioning/libeufin-bank-procedures.sql | 17++++++++---------
Mlibeufin-bank/src/api.rs | 3++-
Mlibeufin-bank/src/api/prepared.rs | 103++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------
Mlibeufin-bank/src/api/token.rs | 106+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------
Mlibeufin-bank/src/api/tx.rs | 28+++++++++++++++++++++++-----
Mlibeufin-bank/src/api/wire.rs | 4++--
Mlibeufin-bank/src/api/withdrawal.rs | 33+++++++++++++++++++++++++++------
Mlibeufin-bank/src/auth.rs | 30++++++++++++++++++++++++++++++
Mlibeufin-bank/src/db.rs | 116++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
Mlibeufin-bank/src/db/account.rs | 5+++++
Mlibeufin-bank/src/db/tan.rs | 11++++++++---
Mlibeufin-bank/src/db/token.rs | 55+++++++++++++++++++++++++++++++++++++++++++++++++++++++
14 files changed, 605 insertions(+), 366 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock @@ -3,16 +3,10 @@ version = 4 [[package]] -name = "adler2" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" - -[[package]] name = "aho-corasick" -version = "1.1.4" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +checksum = "c982642fa9e8606056828ee9a8505737230110bb1099153c79efe865c59d12ba" dependencies = [ "memchr", ] @@ -25,9 +19,9 @@ checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] name = "android_system_properties" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +checksum = "ae221649c9976a6f6c56ae1facf410f3ddb33cc661c4b7b61020a912d4237fbc" dependencies = [ "libc", ] @@ -176,9 +170,9 @@ checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" [[package]] name = "aws-lc-rs" -version = "1.17.3" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00bdb5da18dac48ca2cc7cd4a98e533e8635a58e2361d13a1a4ee3888e0d72f1" +checksum = "ce2b2dcc879c3bae0d371e77c99f2238400ef24ec001394befa67b6e543add9e" dependencies = [ "aws-lc-sys", "untrusted 0.7.1", @@ -187,9 +181,9 @@ dependencies = [ [[package]] name = "aws-lc-sys" -version = "0.43.0" +version = "0.44.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43103168cc76fe62678a375e722fc9cb3a0146159ac5828bc4f0dfd755c2224c" +checksum = "f09fae7be8bb3174e05c6afdb34199e6dc0c7c04ba9fa237b1967adfbde27483" dependencies = [ "cc", "cmake", @@ -274,9 +268,9 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "base64" -version = "0.23.0" +version = "0.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b25655df2c3cdd83c5e5b293b88acd880332b2ddadd7c30ac43144fdc0033da9" +checksum = "ac07cdecf99051d9a5238b80f35af32cdeba5b336e55d957b318b50137e18da5" [[package]] name = "base64ct" @@ -290,7 +284,7 @@ version = "0.19.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a0cd0bd35a28836d528d2b58ad499bc3c5641d59379421b1be9eeb0c2f2b912a" dependencies = [ - "base64 0.23.0", + "base64 0.23.1", "blowfish", "getrandom 0.4.3", "subtle", @@ -342,9 +336,9 @@ dependencies = [ [[package]] name = "bstr" -version = "1.13.0" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f7dc094d718f2e1c1559ad110e27eeaae14a5465d3d56dd6dbd793079fbd530" +checksum = "6bb31b46c14244e20ee9984b11bf5c992b91fb6939fea616e3512c8baecdbe5f" dependencies = [ "memchr", "serde_core", @@ -396,9 +390,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.4.0" +version = "1.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5add81bb678e6cb321aff7fa0dc7689ad82b112dbc032cea19f91d6b8e3582b9" +checksum = "0ad534f4357a5264cce5019c989cf66a4f0dc4e0d1b1d15f8aacec0ff7360273" dependencies = [ "find-msvc-tools", "jobserver", @@ -420,12 +414,12 @@ checksum = "f079e83a288787bcd14a6aea84cee5c87a67c5a3e660c30f557a3d24761b3527" [[package]] name = "chacha20" -version = "0.10.1" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d524456ba66e72eb8b115ff89e01e497f8e6d11d78b70b1aa13c0fbd97540a81" +checksum = "65c35e4b699c7e15ccbe7ee35c005e4fc0a278d22238a2857e6ce2dadeda1b06" dependencies = [ "cfg-if", - "cpufeatures 0.3.0", + "cpufeatures 0.3.1", "rand_core 0.10.1", ] @@ -453,9 +447,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.6.4" +version = "4.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d91e0c145792ef73a6ad36d27c75ac09f1832222a3c209689d90f534685ee5b7" +checksum = "473c7e07f409a8d772161724aa8db6a765a2532a70f9667eeb7b49d3d02fbdca" dependencies = [ "clap_builder", "clap_derive", @@ -463,9 +457,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.6.2" +version = "4.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f09628afdcc538b57f3c6341e9c8e9970f18e4a481690a64974d7023bd33548b" +checksum = "7b48fea5a88e9ae728a2dcbedbfc0e730f7d60da42e1cb049a83c9fb8b789889" dependencies = [ "anstream", "anstyle", @@ -482,7 +476,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 3.0.3", + "syn 3.0.4", ] [[package]] @@ -517,9 +511,9 @@ checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" [[package]] name = "combine" -version = "4.6.7" +version = "4.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +checksum = "cfc320937d09e6de266b31b9afb480f197d7a861be86be7cb2ea7e5d1bfffc5e" dependencies = [ "bytes", "memchr", @@ -626,9 +620,9 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" +checksum = "5ca28b0ae3115b884660db4118d803791fd6756b6e88f39c0f3f7859060d7566" dependencies = [ "libc", ] @@ -650,9 +644,9 @@ checksum = "217698eaf96b4a3f0bc4f3662aaa55bdf913cd54d7204591faa790070c6d0853" [[package]] name = "crc32fast" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +checksum = "8498c871161e1742aaa9d52551b2d6ebdd4c3d45a3be423e3728f33b955be550" dependencies = [ "cfg-if", ] @@ -769,9 +763,9 @@ dependencies = [ [[package]] name = "data-encoding" -version = "2.11.0" +version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4ae5f15dda3c708c0ade84bfee31ccab44a3da4f88015ed22f63732abe300c8" +checksum = "4583a4551df46e2792f82ceeac45e850d2e2d5debba0b91f102385cda5b11f06" [[package]] name = "debug_unsafe" @@ -901,7 +895,7 @@ checksum = "c6232dd377dcc64799954cbd3a9bb882e9cdc1308ccd87b1c098f1fb2eaf82a8" dependencies = [ "proc-macro2", "quote", - "syn 3.0.3", + "syn 3.0.4", ] [[package]] @@ -927,9 +921,9 @@ checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" [[package]] name = "either" -version = "1.17.0" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5e8f6c15a24b9a3ee5efec809ccd006d3b30e8b3bb63c39af737c7f87daa1d" +checksum = "252afb9ae5eaa683babdc6a068b3f5726eb19e05070c731f9b2a23a7c3e8ed34" dependencies = [ "serde", ] @@ -988,9 +982,9 @@ dependencies = [ [[package]] name = "fast-float2" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8eb564c5c7423d25c886fb561d1e4ee69f72354d16918afa32c08811f6b6a55" +checksum = "c6e8948ce679d00a02a94739ea185595dca7118ed04feb991127e443bd3d761f" [[package]] name = "fastrand" @@ -1011,17 +1005,16 @@ dependencies = [ [[package]] name = "find-msvc-tools" -version = "0.1.9" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" +checksum = "d45db016d36b838f563236e9193d0ee6ce38f3f68b6c94e914b4929c96bbb890" [[package]] name = "flate2" -version = "1.1.9" +version = "1.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" +checksum = "6e634e2e0ebac1ee034020da1ca582e17ffe4e0f5e985823721e168928136dcb" dependencies = [ - "miniz_oxide", "zlib-rs", ] @@ -1065,9 +1058,9 @@ checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" [[package]] name = "futures" -version = "0.3.33" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a88cf1f829d945f548cf8fec32c61b1f202b6d93b45848602fc02af4b12ad218" +checksum = "9a31d2a3fbaaeb2af2368bbdd904aa8e812d3c04a1ee10d3171f52d556e5d0a3" dependencies = [ "futures-channel", "futures-core", @@ -1080,9 +1073,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.33" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "262590f4fe6afeb0bc83be1daa64e52657fe185690a958af7f3ad0e92085c5ae" +checksum = "b1f9e3d69d39e4862ffed03ed071a76f9a13ba1d9109d355b0f0aa6b15e393c4" dependencies = [ "futures-core", "futures-sink", @@ -1090,15 +1083,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.33" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cd50c473c80f6d7c3670a752354b8e569b1a7cbfdc0419ec88e5edad85e0dc7" +checksum = "92d699e522242e69e3003b94ecc1f960f3a5e015aa7c5d7486e65ad01dd94f5e" [[package]] name = "futures-executor" -version = "0.3.33" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6754879cc9f2c66f88c6e5c35344bb0bdb0708b0352b1201815667c7eabc7458" +checksum = "031b47cf1a3c6cc8bc2fc76cd437f521619387907d469316e7c0bc278f1f5432" dependencies = [ "futures-core", "futures-task", @@ -1118,38 +1111,38 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.33" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4577ecaa3c4f96589d473f679a71b596316f6641bc350038b962a5daf0085d7a" +checksum = "53c0fa8157de1303bfffdaa1cc2a673bfffb60102f76b0ef4441659124373fed" [[package]] name = "futures-macro" -version = "0.3.33" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d6d3cde68c518367be28956066ddfef33813991b77a55005a69dae04bf3b10b" +checksum = "9fb9654ba8355388abeb8dcb4fc62f511300867002afc858860463bdd9fe0c44" dependencies = [ "proc-macro2", "quote", - "syn 2.0.119", + "syn 3.0.4", ] [[package]] name = "futures-sink" -version = "0.3.33" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e34418ac499d6305c2fb5ad0ed2f6ac998c5f8ca209b4510f7f94242c647e307" +checksum = "1944426bf7d03f1d14f708785e4b33efd750b36d48a157b836b3efc15ede8e1d" [[package]] name = "futures-task" -version = "0.3.33" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b231ed28831efb4a61a08580c4bc233ec56bc009f4cd8f52da2c3cb97df0c109" +checksum = "cd417de3d1d015fc3bfd2b1ea46dfc7bab72ef86f1cc7cc9c78e728b34a6d1fd" [[package]] name = "futures-util" -version = "0.3.33" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a77a90a256fce34da66415271e30f94ee91c57b04b8a2c042d9cf3220179deaa" +checksum = "0d50a92467f8ba5dd6e3ee5d4bd04d73ab2e4e1c44474a0674821dfce14b79bc" dependencies = [ "futures-channel", "futures-core", @@ -1219,9 +1212,9 @@ checksum = "e4eba85ea1d0a966a983acd07deee566e67395d2d96b6fb39e62b5a833f1eb0b" [[package]] name = "globset" -version = "0.4.19" +version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e47d37d2ae4464254884b60ab7071be2b876a9c35b696bd018ddcc76847309cd" +checksum = "07c34a9410465b45bd9787443bc7370f37735bad04b0f0cd57ff1a3186c98988" dependencies = [ "aho-corasick", "bstr", @@ -1232,9 +1225,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.15" +version = "0.4.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6cb093c84e8bd9b188d4c4a8cb6579fc016968d14c99882163cd3ff402a4f155" +checksum = "ef8e5e5a340588f4452631496976cf8636d4a7ecf600239fdc27615d2530bc16" dependencies = [ "atomic-waker", "bytes", @@ -1342,9 +1335,9 @@ dependencies = [ [[package]] name = "http-body-util" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9f41fd6a08e4d4ec69df65976da761afd5ad5e58a9d4acb46bd1c953a9e3ff2" +checksum = "23169fe34a5fbcdd3f3862e78fb9b6fccd5f02a6dc6f732547005d45631ce71c" dependencies = [ "bytes", "futures-core", @@ -1356,7 +1349,7 @@ dependencies = [ [[package]] name = "http-client" version = "1.5.0" -source = "git+git://git.taler.net/taler-rust.git/#f8078cd31e1046e7ffd587b8ac6bf27793590f99" +source = "git+git://git.taler.net/taler-rust.git/#48c40c365ac671cbbe1ac2fb359e1a5cf7e165a3" dependencies = [ "compact_str", "futures-util", @@ -1407,9 +1400,9 @@ dependencies = [ [[package]] name = "hyper" -version = "1.11.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d22053281f852e11534f5198498373cbb59295120a20771d90f7ed1897490a72" +checksum = "27b501faa50e7a26c3d3560ca625132f4078a17771f4810baf70475ae48cbe43" dependencies = [ "atomic-waker", "bytes", @@ -1494,9 +1487,9 @@ dependencies = [ [[package]] name = "icu_collections" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c" +checksum = "fa68d21081c4a05d5a901a1c62add574c77048b6a1c67be3b50ce0b60d4ca513" dependencies = [ "displaydoc", "potential_utf", @@ -1508,9 +1501,9 @@ dependencies = [ [[package]] name = "icu_locale_core" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" +checksum = "d56e28588da92eee5c3201a6eff33fabdd49b62269c8938d4ff050ce4d900deb" dependencies = [ "displaydoc", "litemap", @@ -1521,9 +1514,9 @@ dependencies = [ [[package]] name = "icu_normalizer" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4" +checksum = "12f9cf5f235641ed274641dd81c3f28d870e276763d0797aeeab72317b1c646f" dependencies = [ "icu_collections", "icu_normalizer_data", @@ -1535,16 +1528,17 @@ dependencies = [ [[package]] name = "icu_normalizer_data" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38" +checksum = "1563da1ed3e0b3bf3d74c9b85917ac9c56464d2f57242270c09c9e752f8021a0" [[package]] name = "icu_properties" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de" +checksum = "7e7ca276ad3145661a65914e6daf131ca5120cd3dcee8f8f3214b8875184a148" dependencies = [ + "displaydoc", "icu_collections", "icu_locale_core", "icu_properties_data", @@ -1555,15 +1549,15 @@ dependencies = [ [[package]] name = "icu_properties_data" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14" +checksum = "e590f038c1464a96894fd6d10127e90a8be4509f56ff7ecef851b15cee0b7caa" [[package]] name = "icu_provider" -version = "2.2.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" +checksum = "d27bbb9d3abbefac45d55f647c9de1d44aafcd1186eb91879afef17c396c3e73" dependencies = [ "displaydoc", "icu_locale_core", @@ -1603,9 +1597,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.14.0" +version = "2.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" +checksum = "07aa2048142242915a31d35844fb311e0e53fcca590c3a0a40dcf1b841fa09eb" dependencies = [ "equivalent", "hashbrown 0.17.1", @@ -1622,9 +1616,9 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.12.0" +version = "2.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2" +checksum = "6a756c3fac73139e83f14c2d742155dd2b78d3ee56597b419a0579b7bdd6dd78" [[package]] name = "is_terminal_polyfill" @@ -1744,9 +1738,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.103" +version = "0.3.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53b44bfcdb3f8d5837a46dae1ca9660a837176eee74a28b229bc626816589102" +checksum = "0e0c1080212aad755ea003d18543e8768dd432c48819efd73a7bf1e39b7a5a3a" dependencies = [ "cfg-if", "futures-util", @@ -1808,7 +1802,7 @@ dependencies = [ "taler-macros", "taler-test-utils", "tokio", - "tower-http 0.7.0", + "tower-http 0.7.1", "tracing", "url", "uuid", @@ -1874,7 +1868,7 @@ dependencies = [ "taler-test-utils", "thiserror", "tokio", - "tower-http 0.7.0", + "tower-http 0.7.1", "tracing", "zip", ] @@ -1923,14 +1917,14 @@ dependencies = [ [[package]] name = "libredox" -version = "0.1.18" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c943259e342f1e06ff2da7a83eabdfe7f92ce10262688dbf1895ff0b3e6e4652" +checksum = "d7955dfc218a8afb29dfeffd540e3a6e96baeb94fe7138228dd7cc6937fbbf96" dependencies = [ "bitflags 2.13.1", "libc", "plain", - "redox_syscall 0.9.1", + "redox_syscall 0.9.3", ] [[package]] @@ -1962,9 +1956,9 @@ dependencies = [ [[package]] name = "litemap" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" +checksum = "47d9d19d1d6efa0109d2f65ff4c85cddd50bd572e5a00127ab10987290bcefae" [[package]] name = "litrs" @@ -1983,9 +1977,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.33" +version = "0.4.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad" +checksum = "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6" [[package]] name = "lru-slab" @@ -2047,16 +2041,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] -name = "miniz_oxide" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" -dependencies = [ - "adler2", - "simd-adler32", -] - -[[package]] name = "mio" version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2137,7 +2121,7 @@ dependencies = [ "num-integer", "num-iter", "num-traits", - "rand 0.8.7", + "rand 0.8.8", "smallvec", "zeroize", ] @@ -2150,9 +2134,9 @@ checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441" [[package]] name = "num-integer" -version = "0.1.46" +version = "0.1.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +checksum = "7ce2d95d4b3734dc35aa2f45e1aa22cd416814592a4f9d9205e11affd5b8e10b" dependencies = [ "num-traits", ] @@ -2206,9 +2190,9 @@ checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" [[package]] name = "owo-colors" -version = "4.3.0" +version = "4.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d211803b9b6b570f68772237e415a029d5a50c65d382910b879fb19d3271f94d" +checksum = "13c45bb4a6ae1280ec0803b1ef9d3455eb50f01efbbe1447ab020f1d54fba9d8" [[package]] name = "parking" @@ -2253,11 +2237,11 @@ dependencies = [ [[package]] name = "pem" -version = "3.0.6" +version = "4.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d30c53c26bc5b31a98cd02d20f25a7c8567146caf63ed593a9d87b2775291be" +checksum = "d354a98a3d1251555de99e8fdd8afda05573c31b82f59063a7b0a29b5527f120" dependencies = [ - "base64 0.22.1", + "base64 0.23.1", "serde_core", ] @@ -2305,9 +2289,9 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.33" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e" +checksum = "f6b464fbc74e149a392436b17d523f769e057cb6877f6a5c4618bc6f11800548" [[package]] name = "plain" @@ -2317,9 +2301,9 @@ checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" [[package]] name = "portable-atomic" -version = "1.14.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d20d5497ef88037a52ff98267d066e7f11fcc5e99bbfbd58a42336193aacec3" +checksum = "05c8b63e8d9609db387f0324918f81d68fe27748f084ef092fb35954d0539a85" [[package]] name = "portable-atomic-util" @@ -2332,9 +2316,9 @@ dependencies = [ [[package]] name = "potential_utf" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" +checksum = "d83eb9bc6d8e5cf568e7a1101d60ee05e81ed50ea106026f3d18deeb046d7661" dependencies = [ "zerovec", ] @@ -2405,9 +2389,9 @@ dependencies = [ [[package]] name = "quinn-proto" -version = "0.11.16" +version = "0.11.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f4bfc015262b9df63c8845072ce59068853ff5872180c2ce2f13038b970e560" +checksum = "04759210543be93709136e28212294a659ef5001836ff4eab4d663e4529bba83" dependencies = [ "aws-lc-rs", "bytes", @@ -2463,9 +2447,9 @@ checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" [[package]] name = "rand" -version = "0.8.7" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22f6172bdec972074665ed81ed53b71da00bfc44b65a753cfde883ec4c702a1a" +checksum = "e058c7de0b26af77780c769414d6257830bb240f3c38477dbc2c16e5f54d6d4c" dependencies = [ "libc", "rand_chacha 0.3.1", @@ -2548,9 +2532,9 @@ dependencies = [ [[package]] name = "rcgen" -version = "0.14.8" +version = "0.14.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57f6d249aad744e274e682777a50283a225a32705394ee6d5fcc01efa25e4055" +checksum = "8774e05a7d0de114588e6a28fe7e71694b82614ed569d86d8b389dfbc98b8ad8" dependencies = [ "aws-lc-rs", "pem", @@ -2571,9 +2555,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.9.1" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07507be7b4a5f9f26eeb41eeaebb1f5a7ff29dfb29739facc21d35bf8b11c21e" +checksum = "d678d17679829e73d371e96880897e98fee2ded7acc0a50bdf8af2affa4b2fe5" dependencies = [ "bitflags 2.13.1", ] @@ -2612,9 +2596,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.16" +version = "0.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fcfdb36bda0c880c5931cdc7a2bcdc8ba4556847b9d912bca70bc94708711ad" +checksum = "ad8553b9b26413251cbf30e620595c7a41b3887f03da04579c0e6b0d6a06b4b2" dependencies = [ "aho-corasick", "memchr", @@ -2829,9 +2813,9 @@ checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" [[package]] name = "rustls-webpki" -version = "0.103.13" +version = "0.103.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e" +checksum = "f3c3cf1d8b1e7d4927e2d154c3fcb02979afb9939629c62cd9048d4f07b60ac2" dependencies = [ "aws-lc-rs", "ring", @@ -2931,7 +2915,7 @@ checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" dependencies = [ "proc-macro2", "quote", - "syn 3.0.3", + "syn 3.0.4", ] [[package]] @@ -2972,9 +2956,9 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.21.0" +version = "3.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76a5c54c7310e7b8b9577c286d7e399ddd876c3e12b3ed917a8aabc4b96e9e8c" +checksum = "ee78f1fbe43ac4a0e47aadb3dbd357b69eb0d3793e948624cd03dd2750ab1c0a" dependencies = [ "serde_core", "serde_with_macros", @@ -2982,9 +2966,9 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.21.0" +version = "3.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84d57bc0c8b9a17920c178daa6bb924850d54a9c97ab45194bb8c17ad66bb660" +checksum = "8705578779c2b6bd90d84d66eb2e206b708b1a4d7b9f17641b293545bf1c7e46" dependencies = [ "darling", "proc-macro2", @@ -3259,7 +3243,7 @@ dependencies = [ "memchr", "once_cell", "percent-encoding", - "rand 0.8.7", + "rand 0.8.8", "rsa", "serde", "sha1", @@ -3298,7 +3282,7 @@ dependencies = [ "md-5", "memchr", "once_cell", - "rand 0.8.7", + "rand 0.8.8", "serde", "serde_json", "sha2", @@ -3414,9 +3398,9 @@ dependencies = [ [[package]] name = "syn" -version = "3.0.3" +version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3" +checksum = "e6275cddf4610d1775e6d1fe9469b2e77d0f39fd98fb7450901b821e0c53649f" dependencies = [ "proc-macro2", "quote", @@ -3467,7 +3451,7 @@ dependencies = [ [[package]] name = "taler-api" version = "1.5.0" -source = "git+git://git.taler.net/taler-rust.git/#f8078cd31e1046e7ffd587b8ac6bf27793590f99" +source = "git+git://git.taler.net/taler-rust.git/#48c40c365ac671cbbe1ac2fb359e1a5cf7e165a3" dependencies = [ "aws-lc-rs", "axum", @@ -3486,7 +3470,7 @@ dependencies = [ "taler-common", "thiserror", "tokio", - "tower-http 0.7.0", + "tower-http 0.7.1", "tracing", "url", "zlib-rs", @@ -3495,12 +3479,12 @@ dependencies = [ [[package]] name = "taler-build" version = "1.5.0" -source = "git+git://git.taler.net/taler-rust.git/#f8078cd31e1046e7ffd587b8ac6bf27793590f99" +source = "git+git://git.taler.net/taler-rust.git/#48c40c365ac671cbbe1ac2fb359e1a5cf7e165a3" [[package]] name = "taler-common" version = "1.5.0" -source = "git+git://git.taler.net/taler-rust.git/#f8078cd31e1046e7ffd587b8ac6bf27793590f99" +source = "git+git://git.taler.net/taler-rust.git/#48c40c365ac671cbbe1ac2fb359e1a5cf7e165a3" dependencies = [ "anyhow", "aws-lc-rs", @@ -3530,17 +3514,17 @@ dependencies = [ [[package]] name = "taler-macros" version = "1.5.0" -source = "git+git://git.taler.net/taler-rust.git/#f8078cd31e1046e7ffd587b8ac6bf27793590f99" +source = "git+git://git.taler.net/taler-rust.git/#48c40c365ac671cbbe1ac2fb359e1a5cf7e165a3" dependencies = [ "proc-macro2", "quote", - "syn 3.0.3", + "syn 3.0.4", ] [[package]] name = "taler-test-utils" version = "1.5.0" -source = "git+git://git.taler.net/taler-rust.git/#f8078cd31e1046e7ffd587b8ac6bf27793590f99" +source = "git+git://git.taler.net/taler-rust.git/#48c40c365ac671cbbe1ac2fb359e1a5cf7e165a3" dependencies = [ "aws-lc-rs", "axum", @@ -3608,22 +3592,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.19" +version = "2.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09a43598840e33d5b0331f38c5e30d13bb11c11210a4b58f0d9b18a5a5eefcd9" +checksum = "ec86235f5fcc2a73650310756d2ac5b138a5780bbbdfae3eeccec992c435ba4f" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "2.0.19" +version = "2.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43cbfe0cf76104d42a574802844187e84a305e531ed54455f11fbde0f10541cd" +checksum = "bc04cd3e1236dd4a98afca4569f2deb3f120e5422a4023be2cb683f8486292af" dependencies = [ "proc-macro2", "quote", - "syn 3.0.3", + "syn 3.0.4", ] [[package]] @@ -3637,9 +3621,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.54" +version = "0.3.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e1d5e639ff6bab73cb6885cc7e7b1de96c3f32c68ec55f3952614bec1092244" +checksum = "cdb87b95ec50ddfa440816d227a17b2ccbdda963a316a727fda0fc4334f7d134" dependencies = [ "deranged", "num-conv", @@ -3667,9 +3651,9 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" +checksum = "b1e27c91459209c2986af3dcf603a5a74a4368754ce37414f59acc971167f643" dependencies = [ "displaydoc", "zerovec", @@ -3714,7 +3698,7 @@ checksum = "78773a2a397f451582ce068015985c33193cf6dea8b74d2a639fe457b2f07b0e" dependencies = [ "proc-macro2", "quote", - "syn 3.0.3", + "syn 3.0.4", ] [[package]] @@ -3801,9 +3785,9 @@ dependencies = [ [[package]] name = "tower-http" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b11f75e912b0c2be01b63d8cf8057b8c3f97cf34abb3d431a3a4c8675498e233" +checksum = "08a05a66a4fdd61cbbe0a1d755ffe0ca6aba159dd4820936a0ff8a8278245b9c" dependencies = [ "bitflags 2.13.1", "bytes", @@ -4041,9 +4025,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.24.0" +version = "1.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf3923a6f5c4c6382e0b653c4117f48d631ea17f38ed86e2a828e6f7412f5239" +checksum = "b5772d71c9be8a8a6ac2117d949c5b224c1b72241bb611d9a3012edcf8af7812" dependencies = [ "getrandom 0.4.3", "js-sys", @@ -4121,9 +4105,9 @@ checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" [[package]] name = "wasm-bindgen" -version = "0.2.126" +version = "0.2.127" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b067c0c11094aef6b7a801c1e34a26affafdf3d051dba08456b868789aaf9a4" +checksum = "1b70935747edd64d89de3efa29d73789b806c15798f8e7dca4d8ac356b50ce70" dependencies = [ "cfg-if", "once_cell", @@ -4134,9 +4118,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.76" +version = "0.4.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c62df1340f32221cb9c54d6a27b030e3dba64361d4a95bed55f9aacb44da291d" +checksum = "6b7777d5cc23d0e91404e53ce2d5e8ec7acae3026b16233dba62cd3246457950" dependencies = [ "js-sys", "wasm-bindgen", @@ -4144,9 +4128,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.126" +version = "0.2.127" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "167ce5e579f6bcf889c4f7175a8a5a585de84e8ff93976ce393efa5f2837aab1" +checksum = "77775f8f3f7217702089053b94958f8f54061a3f663417df76e19cbdcca29bc1" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -4154,9 +4138,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.126" +version = "0.2.127" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3997c7839262f4ef12cf90b818d6340c18e80f263f1a94bf157d0ec4420380e" +checksum = "e11d33f857dc2fb11b8bc75aee111aa9cbeb12cd9f25efd3d4c2a3dd4e235284" dependencies = [ "bumpalo", "proc-macro2", @@ -4167,18 +4151,18 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.126" +version = "0.2.127" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc1b4cb0cc549fcf58d7dfc081778139b3d283a081644e833e84682ad71cea24" +checksum = "7ef64dbcc55df09c7e5a46182d181c2cfa3e925f3da937ea764728b4bbb9dcbf" dependencies = [ "unicode-ident", ] [[package]] name = "web-sys" -version = "0.3.103" +version = "0.3.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8622dcb61c0bcc9fffa6938bed81210af2da9a7e4a1a834b2e37a59b6dfb6141" +checksum = "c435338968042f4f59a557f690a253676d47ce13ceb55d70100e7facf6620a30" dependencies = [ "js-sys", "wasm-bindgen", @@ -4497,9 +4481,9 @@ checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" [[package]] name = "writeable" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" +checksum = "3ad82d2a33cdc9674dc7465672f271e096168fcdbe0f799d9e6db8c5892679dc" [[package]] name = "x509-parser" @@ -4560,18 +4544,18 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.55" +version = "0.8.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5a105cd7b140f6eeec8acff2ea38135d3cab283ada58540f629fe51e46696eb" +checksum = "556764e583adb45a9f8d413c2a147fa7e8d821e48e12b14fd560b607998b75eb" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.55" +version = "0.8.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fe976fb70c78cd64cccfe3a6fc142244e8a77b70959b30faf9d0ac37ee228eb" +checksum = "f2ab42fc20575779bd240faa45f94a74256f755c0fa9e89f0ede20d91d0cdfc1" dependencies = [ "proc-macro2", "quote", @@ -4607,9 +4591,9 @@ checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e" [[package]] name = "zerotrie" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" +checksum = "4ea269c3bd32f0a32c321907a2ae912ba6f4649bb0fc764a15627e99a7095a3f" dependencies = [ "displaydoc", "yoke", @@ -4618,9 +4602,9 @@ dependencies = [ [[package]] name = "zerovec" -version = "0.11.6" +version = "0.11.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" +checksum = "bb0464e17806c1d976d5cba29399c7f08e516e279e2ba493f63123b5fca67dd8" dependencies = [ "yoke", "zerofrom", @@ -4629,13 +4613,13 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.11.3" +version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" +checksum = "34df6fc39dbd26ddc9c10e6a2984476e13acce22e64e4487636ef494369225da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.119", + "syn 3.0.4", ] [[package]] @@ -4654,9 +4638,9 @@ dependencies = [ [[package]] name = "zlib-rs" -version = "0.6.6" +version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b142a20ec14a91d5bc708c1dc21b080c550113d8aa77afa29635673a65dd02c5" +checksum = "34b31d188d9d685a4f9c7b46d6e36631b07058d2cfe190267adce54dc230bf12" [[package]] name = "zmij" diff --git a/build.gradle b/build.gradle @@ -1,82 +0,0 @@ -// This file is in the public domain. - -plugins { - id("org.jetbrains.kotlin.jvm") version "2.4.0" - id("org.jetbrains.dokka") version "2.2.0" - id("idea") - id("java-library") -} - -group = "tech.libeufin" -apply from: 'build-system/version.gradle' - -if (!JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_17)){ - throw new GradleException( - "This build must be run with java 17 " + - "or later (your version is java ${JavaVersion.current()})") -} - -allprojects { - ext { - set("kotlin_version", "2.4.0") - set("ktor_version", "3.5.0") - set("clikt_version", "5.1.0") - set("coroutines_version", "1.11.0") - set("postgres_version", "42.7.11") - set("junixsocket_version", "2.10.1") - set("shadow_version", "9.4.3") - set("prometheus_version", "1.6.1") - } - - repositories { - mavenCentral() - } -} - -subprojects { - apply plugin: 'org.jetbrains.dokka' - - tasks.withType(Test) { - // Invalidate tests cache when editing SQL logic - inputs.dir("$rootDir/database-versioning").withPathSensitivity(PathSensitivity.RELATIVE) - // Or when editing ISO20022 test samples - inputs.dir("$rootDir/libeufin-nexus/sample").withPathSensitivity(PathSensitivity.RELATIVE) - inputs.dir("$rootDir/testbench/sample").withPathSensitivity(PathSensitivity.RELATIVE) - - def failedTests = [] - - afterTest { desc, result -> - if (result.resultType == TestResult.ResultType.FAILURE) { - failedTests << "${desc.className}.${desc.name}" - } - } - - afterSuite { desc, result -> - if (desc.parent == null && !failedTests.isEmpty()) { - logger.lifecycle("") - logger.lifecycle("==== FAILED TESTS ====") - failedTests.each { logger.lifecycle(it) } - logger.lifecycle("======================") - } - } - - testLogging { - events "failed" - exceptionFormat = 'full' - } - } -} - -task libeufinVersion { - doLast { - println project.version - } -} - -dependencies { - dokka(project(":libeufin-common:")) - dokka(project(":libeufin-bank:")) - dokka(project(":libeufin-nexus:")) - dokka(project(":libeufin-ebics:")) - dokka(project(":libeufin-ebisync:")) -} diff --git a/database-versioning/libeufin-bank-procedures.sql b/database-versioning/libeufin-bank-procedures.sql @@ -1508,12 +1508,11 @@ SELECT amount_local.val, amount_local.frac, out_missing_amount, out_amount_differs - FROM taler_withdrawal_operations AS op - WHERE op.withdrawal_uuid=in_withdrawal_uuid - -- Prepared-transfer withdrawals are intentionally unbound until the - -- first confirmation; ordinary withdrawals are bound at creation. - AND (op.wallet_bank_account IS NULL - OR op.wallet_bank_account=wallet_bank_account_local); + FROM taler_withdrawal_operations + WHERE withdrawal_uuid=in_withdrawal_uuid + -- Prepared-transfer withdrawals are intentionally unbound until the + -- first confirmation; ordinary withdrawals are bound at creation. + AND (wallet_bank_account IS NULL OR wallet_bank_account=wallet_bank_account_local); out_no_op=NOT FOUND; IF out_no_op OR already_confirmed OR out_aborted OR out_not_selected OR out_missing_amount OR out_amount_differs OR out_tan_required THEN RETURN; @@ -1545,8 +1544,8 @@ END IF; -- Confirm operation and update amount UPDATE taler_withdrawal_operations SET amount=amount_local, - wallet_bank_account=COALESCE(wallet_bank_account, wallet_bank_account_local), - confirmation_done=true + confirmation_done=true, + wallet_bank_account=COALESCE(wallet_bank_account, wallet_bank_account_local) WHERE withdrawal_uuid=in_withdrawal_uuid; -- Notify status change @@ -1703,7 +1702,7 @@ SELECT bank_account_id -- Check for idempotence and conflict SELECT (amount_debit != in_amount_debit OR amount_credit != in_amount_credit - OR subject != in_subject + OR subject != in_subject OR bank_account != account_id) , cashout_id INTO out_request_uid_reuse, out_cashout_id diff --git a/libeufin-bank/src/api.rs b/libeufin-bank/src/api.rs @@ -279,7 +279,7 @@ pub mod test { use crate::{ CONFIG_SOURCE, api::{ - BankState, MonitorResponse, + BankState, account::{ AccountData, Balance, CreditDebitInfo, create_admin_account, rand_iban_payto, }, @@ -941,6 +941,7 @@ pub mod test { #[tokio::test] async fn corebank() { + use crate::api::MonitorResponse; let ctx = bank_setup().await; ctx.auth_routine(Method::GET, "/monitor", Auth::Admin).await; diff --git a/libeufin-bank/src/api/prepared.rs b/libeufin-bank/src/api/prepared.rs @@ -130,13 +130,17 @@ mod test { use taler_common::{ api::{ EddsaPublicKey, EddsaSignature, - prepared::{PublicKeyAlg, RegistrationRequest, TransferType}, + prepared::{ + PublicKeyAlg, RegistrationRequest, RegistrationResponse, TransferSubject, + TransferType, + }, }, db::IncomingType, error_code::ErrorCode, types::amount::{Amount, Currency}, }; use taler_test_utils::{ + json, routine::{Status, registration_routine}, server::TestServer as _, }; @@ -147,26 +151,26 @@ mod test { async fn registration() { let ctx = bank_setup().await; - let key_pair1 = Ed25519KeyPair::generate().unwrap(); - let auth_pub1 = EddsaPublicKey::try_from(key_pair1.public_key().as_ref()).unwrap(); + let key_pair = Ed25519KeyPair::generate().unwrap(); + let auth_pub = EddsaPublicKey::try_from(key_pair.public_key().as_ref()).unwrap(); let req = RegistrationRequest { credit_account: ctx.exchange_payto.as_uri(), r#type: TransferType::reserve, recurrent: false, - credit_amount: Amount::new(&Currency::KUDOS, 120, 0), + credit_amount: Amount::new(&Currency::KUDOS, 1, 0), alg: PublicKeyAlg::EdDSA, - account_pub: auth_pub1, - authorization_pub: auth_pub1, + account_pub: auth_pub, + authorization_pub: auth_pub, authorization_sig: EddsaSignature::ZEROED, } - .signed(&key_pair1); + .signed(&key_pair); ctx.post("/taler-prepared-transfer/registration") .json( RegistrationRequest { credit_account: ctx.customer_payto.as_uri(), ..req.clone() } - .signed(&key_pair1), + .signed(&key_pair), ) .await .assert_error(ErrorCode::BANK_ACCOUNT_IS_NOT_EXCHANGE); @@ -176,7 +180,7 @@ mod test { credit_account: ctx.unknown_payto.as_uri(), ..req.clone() } - .signed(&key_pair1), + .signed(&key_pair), ) .await .assert_error(ErrorCode::BANK_UNKNOWN_CREDITOR); @@ -229,37 +233,56 @@ mod test { ) .await; - /* - * - * // Non recurrent no URI - client.post("/taler-prepared-transfer/registration") { - json(valid_req) { - "type" to "reserve" - } - }.assertOkJson<SubjectResult> { - val uuid = (it.subjects[0] as? TransferSubject.Uri)!!.uri.substringAfterLast('/') - client.postA("/accounts/customer/withdrawals/$uuid/confirm").assertNoContent() // reserve - tx("customer", "KUDOS:1", "exchange", "Taler MAP:$pub") // bounce - tx("customer", "KUDOS:1", "exchange", "Taler MAP:$pub") // bounce - assertBalance("customer", "-KUDOS:1") - assertBalance("exchange", "+KUDOS:1") - } - * // Withdrawal is aborted on completion - client.post("/taler-prepared-transfer/registration") { - json(valid_req) { - "type" to "kyc" - } - }.assertOkJson<SubjectResult> { - val uuid = (it.subjects[0] as? TransferSubject.Uri)!!.uri.substringAfterLast('/') - println("UUID $uuid") - tx("customer", "KUDOS:1", "exchange", "Taler MAP:$pub") // kyc - tx("customer", "KUDOS:1", "exchange", "Taler MAP:$pub") // bounce - client.postA("/accounts/customer/withdrawals/$uuid/confirm") - .assertConflict(TalerErrorCode.BANK_CONFIRM_ABORT_CONFLICT) // aborted - assertBalance("customer", "-KUDOS:2") - assertBalance("exchange", "+KUDOS:2") - } + ctx.assert_balance("customer", "-504").await; + ctx.assert_balance("exchange", "504").await; + let subject = &format!("Taler MAP:{auth_pub}"); + + // Non recurrent accept on then bounce + let res = ctx + .post("/taler-prepared-transfer/registration") + .json(&req) + .await + .assert_ok_json::<RegistrationResponse>(); + let uuid = match &res.subjects[0] { + TransferSubject::Uri { uri, .. } => uri.as_str().rsplit('/').next().unwrap(), + _ => unreachable!(), + }; + ctx.posta(format!("/accounts/customer/withdrawals/{uuid}/confirm")) + .json(json!({})) + .await + .assert_no_content(); // reserve + ctx.posta(format!("/accounts/merchant/withdrawals/{uuid}/confirm")) + .json(json!({})) + .await + .assert_error(ErrorCode::BANK_TRANSACTION_NOT_FOUND); + ctx.tx_s("customer", "1", "exchange", subject).await; // bounce + ctx.tx_s("customer", "1", "exchange", subject).await; // bounce + ctx.assert_balance("customer", "-505").await; + ctx.assert_balance("exchange", "505").await; - */ + // Withdrawal is aborted on completion + let res = ctx + .post("/taler-prepared-transfer/registration") + .json( + RegistrationRequest { + r#type: TransferType::kyc, + ..req.clone() + } + .signed(&key_pair), + ) + .await + .assert_ok_json::<RegistrationResponse>(); + let uuid = match &res.subjects[0] { + TransferSubject::Uri { uri, .. } => uri.as_str().rsplit('/').next().unwrap(), + _ => unreachable!(), + }; + ctx.tx_s("customer", "1", "exchange", subject).await; // kyc + ctx.tx_s("customer", "1", "exchange", subject).await; // bounce + ctx.posta(format!("/accounts/customer/withdrawals/{uuid}/confirm")) + .json(json!({})) + .await + .assert_error(ErrorCode::BANK_CONFIRM_ABORT_CONFLICT); // Aborted + ctx.assert_balance("customer", "-506").await; + ctx.assert_balance("exchange", "506").await; } } diff --git a/libeufin-bank/src/api/token.rs b/libeufin-bank/src/api/token.rs @@ -45,7 +45,7 @@ use crate::{ auth::{TOKEN_PREFIX, TokenScope, UserAuth, UserRAuth, UserRWAuth}, db::{ self, - token::{TokenCreationResult, access, create}, + token::{TokenCreationResult, access, create, refresh}, }, mfa::{MfaReq, TokenOp}, }; @@ -84,6 +84,7 @@ pub struct TokenSuccessResponse { } pub const TOKEN_DEFAULT_DURATION: Duration = Duration::from_hours(24); +pub const TOKEN_REFRESH_OVERLAP: Duration = Duration::from_mins(5); pub fn token_api() -> Router<Arc<BankState>> { Router::new() @@ -122,19 +123,36 @@ pub fn token_api() -> Router<Arc<BankState>> { )?) } }; - match create( - &state.db, - &auth.username, - new.as_ref(), - &creation, - &expiration, - &req.scope, - req.refreshable, - req.description.as_deref(), - auth.is_admin() || mfa.is_2fa(), - ) - .await? - { + + let res = if let Some(existing) = &auth.token { + refresh( + &state.db, + &auth.username, + existing, + new.as_ref(), + &creation, + &expiration, + &(creation + TOKEN_REFRESH_OVERLAP), + &req.scope, + req.refreshable, + req.description.as_deref(), + ) + .await? + } else { + create( + &state.db, + &auth.username, + new.as_ref(), + &creation, + &expiration, + &req.scope, + req.refreshable, + req.description.as_deref(), + auth.is_admin() || mfa.is_2fa(), + ) + .await? + }; + match res { TokenCreationResult::Success(token_id) => Ok(Json(TokenSuccessResponse { access_token: format!("{TOKEN_PREFIX}{new}"), expiration, @@ -195,10 +213,11 @@ pub fn token_api() -> Router<Arc<BankState>> { #[cfg(test)] pub mod test { - use std::str::FromStr; + use std::{str::FromStr, time::Duration}; use axum::http::{Method, header::AUTHORIZATION}; use jiff::Timestamp; + use taler_api::db::TypeHelper; use taler_common::{ api::ErrorDetail, error_code::ErrorCode, @@ -410,6 +429,63 @@ pub mod test { .await .assert_error(ErrorCode::GENERIC_TOKEN_UNKNOWN); + // Refresh overlap is fixed and non sliding + let TokenSuccessResponse { + access_token: source, + expiration: _, + token_id: source_id, + } = ctx + .postpw("/accounts/merchant/token") + .json(json!({ + "scope": "readonly", + "refreshable" : true, + "duration" : { "d_us" : 86_400_000_000u64 }, + "description" : "refresh source" + })) + .await + .assert_ok_json::<TokenSuccessResponse>(); + let before_refresh = Timestamp::now(); + for i in 0..2 { + ctx.post("/accounts/merchant/token") + .header(AUTHORIZATION, format!("Bearer {source}")) + .json(json!({ + "scope": "readonly", + "description": format!("replacement-{i}") + })) + .await + .assert_ok(); + } + let first_deadline: Timestamp = + sqlx::query("SELECT expiration_time FROM bearer_tokens WHERE bearer_token_id=$1") + .bind(source_id as i64) + .try_map(|it| it.try_get_timestamp(0)) + .fetch_one(&ctx.state.db) + .await + .unwrap(); + assert!(first_deadline > before_refresh + Duration::from_mins(5)); + assert!(first_deadline < Timestamp::now() + Duration::from_mins(5)); + // A retry after a lost response may create another replacement, but + // must not extend the original token's overlap deadline + ctx.post("/accounts/merchant/token") + .header(AUTHORIZATION, format!("Bearer {source}")) + .json(json!({ + "scope": "readonly", + "description": "replacement-lost-response-retry" + })) + .await + .assert_ok(); + + assert!( + sqlx::query_scalar::<_, bool>( + "SELECT expiration_time=$2 FROM bearer_tokens WHERE bearer_token_id=$1" + ) + .bind(source_id as i64) + .bind(first_deadline.as_microsecond()) + .fetch_one(&ctx.state.db) + .await + .unwrap() + ); + // 2FA { // Setup a known phone 2FA diff --git a/libeufin-bank/src/api/tx.rs b/libeufin-bank/src/api/tx.rs @@ -41,7 +41,7 @@ use taler_common::{ use crate::{ api::BankState, - auth::UserRAuth, + auth::{UserOptRAuth, UserRAuth}, db::tx::{TxResult, create, get_by_id, pool_history}, mfa::{BankTxOp, MfaReq}, payto::{BankPayto, FullBankPayto, LibeufinId}, @@ -149,19 +149,20 @@ pub fn tx_api() -> Router<Arc<BankState>> { }, ) .get( - async |mut auth: UserRAuth, + async |mut auth: UserOptRAuth, Query(params): Query<HistoryParams>, State(state): State<Arc<BankState>>| { let params = params.check()?; + let info = auth + .bank_info_auth_or_public(&state.db, &state.cfg.ctx) + .await?; let transactions = pool_history( &state.db, &state.cfg.ctx, &state.cfg.regional_currency, &state.tx_channel, &params, - auth.bank_info(&state.db, &state.cfg.ctx) - .await? - .bank_account_id, + info.bank_account_id, ) .await?; if transactions.is_empty() { @@ -412,6 +413,23 @@ pub mod test { ctx.assert_balance("merchant", "3").await; ctx.assert_balance("exchange", "-3").await; + // Public history is public + ctx.patch_admin("/accounts/merchant") + .json(json!({ "is_public": true})) + .await + .assert_no_content(); + ctx.get("/accounts/merchant/transactions").await.assert_ok(); + ctx.get("/accounts/customer/transactions") + .await + .assert_error(ErrorCode::BANK_UNKNOWN_ACCOUNT); + ctx.patch_admin("/accounts/merchant") + .json(json!({ "is_public": false})) + .await + .assert_no_content(); + ctx.get("/accounts/merchant/transactions") + .await + .assert_error(ErrorCode::BANK_UNKNOWN_ACCOUNT); + // Check 2fa ctx.fill_tan_info("merchant").await; ctx.assert_balance("merchant", "3").await; diff --git a/libeufin-bank/src/api/wire.rs b/libeufin-bank/src/api/wire.rs @@ -670,7 +670,7 @@ pub mod test { let path = format!("/accounts/exchange/taler-wire-gateway/admin/add-{path}"); ctx.auth_routine(Method::POST, &path, Auth::Admin).await; let req = json!({ - "amount": format!("KUDOS:44"), + "amount": "KUDOS:44", "debit_account": ctx.customer_payto, key: EddsaPublicKey::rand(), }); @@ -688,7 +688,7 @@ pub mod test { if *ty != IncomingType::map { ctx.post_admin(&path) .json(json!(req + { - "amount": format!("KUDOS:44"), + "amount": "KUDOS:44", })) .await .assert_error(ErrorCode::BANK_UNALLOWED_DEBIT); diff --git a/libeufin-bank/src/api/withdrawal.rs b/libeufin-bank/src/api/withdrawal.rs @@ -565,7 +565,7 @@ mod test { async { tokio::time::sleep(Duration::from_millis(100)).await; ctx.posta(format!( - "/accounts/customer/withdrawals/{confirmed}/confirm" + "/accounts/merchant/withdrawals/{confirmed}/confirm" )) .json(json!({})) .await @@ -986,6 +986,23 @@ mod test { .await .assert_error(ErrorCode::BANK_AMOUNT_DIFFERS); + // A selected operation is bound to the account that created it. + let uuid = ctx + .posta("/accounts/merchant/withdrawals") + .json(json!({ "amount": "KUDOS:1" })) + .await + .assert_ok_json::<BankAccountCreateWithdrawalResponse>() + .withdrawal_id; + ctx.withdraw_select(uuid).await; + ctx.posta(format!("/accounts/customer/withdrawals/{uuid}/confirm")) + .json(json!({})) + .await + .assert_error(ErrorCode::BANK_TRANSACTION_NOT_FOUND); + ctx.posta(format!("/accounts/merchant/withdrawals/{uuid}/abort")) + .json(json!({})) + .await + .assert_no_content(); + // Confirm with amount let uuid = ctx .posta("/accounts/merchant/withdrawals") @@ -1101,7 +1118,7 @@ mod test { // 2FA without body ctx.fill_tan_info("merchant").await; - ctx.assert_balance("merchant", "-6.2").await; + ctx.assert_balance("merchant", "-6.48").await; let uuid = ctx .posta("/accounts/merchant/withdrawals") .json(json!({ "amount": "KUDOS:1" })) @@ -1112,12 +1129,14 @@ mod test { ctx.posta(format!("/accounts/merchant/withdrawals/{uuid}/confirm")) .json(json!({})) .await - .assert_challenge_check(&ctx, async |_| ctx.assert_balance("merchant", "-6.2").await) + .assert_challenge_check(&ctx, async |_| { + ctx.assert_balance("merchant", "-6.48").await + }) .await .assert_no_content(); // 2FA with body - ctx.assert_balance("merchant", "-7.3").await; + ctx.assert_balance("merchant", "-7.58").await; let uuid = ctx .posta("/accounts/merchant/withdrawals") .json(json!({})) @@ -1128,9 +1147,11 @@ mod test { ctx.posta(format!("/accounts/merchant/withdrawals/{uuid}/confirm")) .json(json!({ "amount": "KUDOS:1" })) .await - .assert_challenge_check(&ctx, async |_| ctx.assert_balance("merchant", "-7.3").await) + .assert_challenge_check(&ctx, async |_| { + ctx.assert_balance("merchant", "-7.58").await + }) .await .assert_no_content(); - ctx.assert_balance("merchant", "-8.4").await; + ctx.assert_balance("merchant", "-8.68").await; } } diff --git a/libeufin-bank/src/auth.rs b/libeufin-bank/src/auth.rs @@ -264,6 +264,7 @@ impl<S: UserAuthScope> FromRequestParts<Arc<BankState>> for UserAuth<S> { pub struct UserOptAuth<S> { pub username: CompactString, auth_info: Option<BankInfo>, + user_info: Option<BankInfo>, scope: PhantomData<S>, } @@ -271,6 +272,33 @@ impl<S> UserOptAuth<S> { pub fn is_authenticated(&self) -> bool { self.auth_info.is_some() } + + /** Retrieve the bank account info for the selected username if authenticated or if public */ + pub async fn bank_info_auth_or_public( + &mut self, + db: &PgPool, + ctx: &PaytoCtx, + ) -> ApiResult<&BankInfo> { + if self.user_info.is_none() { + if let Some(info) = &self.auth_info + && info.username == self.username + { + return Ok(info); + } + let info = super::db::account::bank_info(db, ctx, &self.username).await?; + + let Some(info) = info else { + todo!("Unknown account") + }; + self.user_info = Some(info); + } + let info = self.user_info.as_ref().unwrap(); + if !info.is_public && !self.is_authenticated() { + Err(failure_code(ErrorCode::BANK_UNKNOWN_ACCOUNT)) + } else { + Ok(info) + } + } } impl<S: UserAuthScope> FromRequestParts<Arc<BankState>> for UserOptAuth<S> { @@ -285,6 +313,7 @@ impl<S: UserAuthScope> FromRequestParts<Arc<BankState>> for UserOptAuth<S> { Ok(Self { username: auth.username, auth_info: Some(auth.auth_info), + user_info: None, scope: PhantomData, }) } else { @@ -292,6 +321,7 @@ impl<S: UserAuthScope> FromRequestParts<Arc<BankState>> for UserOptAuth<S> { Ok(Self { username: username.into(), auth_info: None, + user_info: None, scope: PhantomData, }) } diff --git a/libeufin-bank/src/db.rs b/libeufin-bank/src/db.rs @@ -230,16 +230,28 @@ pub async fn monitor( #[cfg(test)] mod test { + use std::time::Duration; + + use jiff::Timestamp; use taler_common::{ error_code::ErrorCode::BANK_UNALLOWED_DEBIT, - types::amount::{Currency, Decimal, MAX_VALUE, decimal}, + types::{ + amount::{Currency, Decimal, MAX_VALUE, decimal}, + base32::Base32, + }, }; use taler_test_utils::json; - - use crate::api::{ - Timeframe, - conversion::RoundingMode::{self, nearest, up, zero}, - test::bank_setup, + use uuid::Uuid; + + use crate::{ + TanChannel, + api::{ + Timeframe, + conversion::RoundingMode::{self, nearest, up, zero}, + test::bank_setup, + }, + db::tan::{self, SendResult, SolveResult, mark_sent, send, solve}, + mfa::Operation, }; #[tokio::test] @@ -758,4 +770,96 @@ mod test { monitor_cashin(3, "KUDOS:55.94", "EUR:70").await; monitor_cashout(3, "KUDOS:22.9", "EUR:28.85").await; } + + #[tokio::test] + async fn tan_challenge() { + const VALIDITY_PERIOD: Duration = Duration::from_hours(1); + const RETRANSMISSION_PERIOD: Duration = Duration::from_mins(1); + const RETRY_COUNTER: u16 = 3; + + let ctx = bank_setup().await; + + let create = async |code: &str, now: &Timestamp| -> Uuid { + tan::new( + &ctx.state.db, + "customer", + Operation::withdrawal, + &Base32::rand(), + &Base32::rand(), + code, + now, + RETRY_COUNTER, + VALIDITY_PERIOD, + TanChannel::sms, + "+88", + ) + .await + .unwrap() + }; + let mark_sent = async |id: &Uuid, now: &Timestamp| { + mark_sent(&ctx.state.db, id, &(*now + RETRANSMISSION_PERIOD)) + .await + .unwrap() + }; + let send = async |id: &Uuid, now: &Timestamp| -> SendResult { + send(&ctx.state.db, id, now, 10).await.unwrap() + }; + let solve = async |id: &Uuid, code: &str, now: &Timestamp| -> SolveResult { + solve(&ctx.state.db, id, code, now).await.unwrap() + }; + + let now = Timestamp::now(); + let expired = now + VALIDITY_PERIOD; + let retransmit = now + RETRANSMISSION_PERIOD; + + const GOOD: &str = "good-code"; + const BAD: &str = "bad-code"; + + // Check basic + let id = create(GOOD, &now).await; + // Bad code + assert_eq!(solve(&id, BAD, &now).await, SolveResult::BadCode); + // Good code + assert!(matches!( + solve(&id, GOOD, &now).await, + SolveResult::Success { .. } + )); + // Never resend a confirmed challenge + assert_eq!(send(&id, &now).await, SendResult::Solved); + // Confirmed challenge always ok + assert!(matches!( + solve(&id, GOOD, &now).await, + SolveResult::Success { .. } + )); + + // Check retry + let id = create(GOOD, &now).await; + mark_sent(&id, &now).await; + // Bad code + for _ in 0..RETRY_COUNTER - 1 { + assert_eq!(solve(&id, BAD, &now).await, SolveResult::BadCode); + } + assert_eq!(solve(&id, BAD, &now).await, SolveResult::NoRetry); + // Good code fail + assert_eq!(solve(&id, GOOD, &now).await, SolveResult::NoRetry); + // Exhausted challenge IDs are terminal and cannot be resent + assert_eq!(send(&id, &now).await, SendResult::Expired); + + // Check retransmission + let id = create(GOOD, &now).await; + // Failed to send retransmit + assert!(matches!(send(&id, &now).await, SendResult::Send { .. })); + // Code successfully sent and still valid + mark_sent(&id, &now).await; + assert!(matches!(send(&id, &now).await, SendResult::Success { .. })); + // Code is still valid but should be resent + assert!(matches!( + send(&id, &retransmit).await, + SendResult::Send { .. } + )); + // Good code fail because expired + assert_eq!(solve(&id, GOOD, &expired).await, SolveResult::Expired); + // Expired challenge IDs are terminal and cannot be resent + assert_eq!(send(&id, &expired).await, SendResult::Expired); + } } diff --git a/libeufin-bank/src/db/account.rs b/libeufin-bank/src/db/account.rs @@ -580,6 +580,7 @@ pub async fn check_password( bank_account_id, internal_payto, is_taler_exchange, + is_public, name, tan_channels, email, @@ -596,6 +597,7 @@ pub async fn check_password( payto: sql_bank_payto(&r, ctx, "internal_payto", "name")?, bank_account_id: r.try_get_u64("bank_account_id")?, is_exchange: r.try_get("is_taler_exchange")?, + is_public: r.try_get("is_public")?, phone: r.try_get("phone")?, email: r.try_get("email")?, channels: r.try_get("tan_channels")?, @@ -645,6 +647,7 @@ pub struct BankInfo { pub payto: FullBankPayto, pub bank_account_id: u64, pub is_exchange: bool, + pub is_public: bool, pub phone: Option<CompactString>, pub email: Option<CompactString>, pub channels: Vec<TanChannel>, @@ -684,6 +687,7 @@ pub async fn bank_info( internal_payto, name, is_taler_exchange, + is_public, tan_channels, email, phone @@ -699,6 +703,7 @@ pub async fn bank_info( payto: sql_bank_payto(&r, ctx, "internal_payto", "name")?, bank_account_id: r.try_get_u64("bank_account_id")?, is_exchange: r.try_get("is_taler_exchange")?, + is_public: r.try_get("is_public")?, phone: r.try_get("phone")?, email: r.try_get("email")?, channels: r.try_get("tan_channels")?, diff --git a/libeufin-bank/src/db/tan.rs b/libeufin-bank/src/db/tan.rs @@ -92,6 +92,7 @@ pub async fn new( } /** Result of TAN challenge transmission */ +#[derive(Debug, Clone, PartialEq, Eq)] pub enum SendResult { Send { info: CompactString, @@ -125,6 +126,7 @@ pub async fn send( ,code ,tan_channel ,tan_info + ,retry_counter -- If this is the first time we submit this challenge check there is not too many active challenges ,(retransmission_date = 0 AND ( SELECT count(*) >= $1 @@ -143,14 +145,16 @@ pub async fn send( .try_map(|r: PgRow| Ok( if r.try_get("solved")? { SendResult::Solved + } else if r.try_get::<i32, _>("retry_counter")? <= 0 { + SendResult::Expired } else if r.try_get("too_many")? { SendResult::TooMany } else { - let retransmission = r.try_get_timestamp ("retransmission_date")?; + let retransmission = r.try_get_timestamp("retransmission_date")?; let expiration = r.try_get_timestamp("expiration_date")?; - if expiration < *now { + if expiration <= *now { SendResult::Expired - } else if retransmission < *now { + } else if retransmission <= *now { SendResult::Send { info: r.try_get("tan_info")?, channel: r.try_get("tan_channel")?, @@ -181,6 +185,7 @@ pub async fn mark_sent(db: &PgPool, uuid: &Uuid, retransmission: &Timestamp) -> } /** Result of TAN challenge solution */ +#[derive(Debug, Clone, PartialEq, Eq)] pub enum SolveResult { Success { op: Operation, diff --git a/libeufin-bank/src/db/token.rs b/libeufin-bank/src/db/token.rs @@ -83,6 +83,59 @@ pub async fn create( ) } +/** Create new token for [username] */ +pub async fn refresh( + db: &PgPool, + username: &str, + source: &[u8], + content: &[u8], + creation: &Timestamp, + expiration: &TalerTimestamp, + source_expiration_cap: &Timestamp, + scope: &TokenScope, + is_refreshable: bool, + description: Option<&str>, +) -> sqlx::Result<TokenCreationResult> { + serialized!( + sqlx::query( + " + WITH source_token AS ( + UPDATE bearer_tokens + SET expiration_time=LEAST(expiration_time, $1) + WHERE content=$2 + AND bank_customer=( + SELECT customer_id FROM customers + WHERE username=$3 AND deleted_at IS NULL + ) + RETURNING bank_customer + ) + INSERT INTO bearer_tokens ( + content, creation_time, expiration_time, scope, bank_customer, + is_refreshable, description, last_access + ) + SELECT $4, $5, $6, $7, bank_customer, $8, $9, $5 + FROM source_token + RETURNING bearer_token_id + " + ) + .bind_timestamp(source_expiration_cap) + .bind(source) + .bind(username) + .bind(content) + .bind_timestamp(creation) + .bind(expiration) + .bind(scope) + .bind(is_refreshable) + .bind(description) + .try_map(|r: PgRow| { + Ok(TokenCreationResult::Success( + r.try_get_u64("bearer_token_id")?, + )) + }) + .fetch_one(db) + ) +} + /** Get info for [token] */ pub async fn access( db: &PgPool, @@ -139,6 +192,7 @@ pub async fn access_info( is_refreshable, username, is_taler_exchange, + is_public, bank_account_id, internal_payto, name, @@ -162,6 +216,7 @@ pub async fn access_info( payto: sql_bank_payto(&r, ctx, "internal_payto", "name")?, bank_account_id: r.try_get_u64("bank_account_id")?, is_exchange: r.try_get("is_taler_exchange")?, + is_public: r.try_get("is_public")?, phone: r.try_get("phone")?, email: r.try_get("email")?, channels: r.try_get("tan_channels")?,