libeufin

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

commit 188094f92c7afbdda811305cd9ec54be189b66ba
parent d986d1c90011d18b35f5d6d3538cd19f49de4cbd
Author: Antoine A <>
Date:   Thu, 16 Jul 2026 02:46:15 +0200

bank: fix bcrypt password hash

Diffstat:
Mlibeufin-bank/src/pw.rs | 20++++++++++++++++++--
Alibeufin-ebics/src/bin/iso20022-codegen.rs | 206+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 224 insertions(+), 2 deletions(-)

diff --git a/libeufin-bank/src/pw.rs b/libeufin-bank/src/pw.rs @@ -1,3 +1,19 @@ +/* + This file is part of TALER + Copyright (C) 2026 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ + use anyhow::anyhow; use aws_lc_rs::digest::SHA256; use rand::{TryRng as _, rngs::SysRng}; @@ -52,7 +68,7 @@ impl PwCrypto { PwCrypto::Bcrypt { cost } => { let mut salt = [0u8; 16]; SysRng.try_fill_bytes(&mut salt).unwrap(); - let pwh = bcrypt::bcrypt(*cost, salt, pw.as_bytes()); + let pwh = bcrypt::hash_with_salt_bytes(pw.as_bytes(), *cost, salt).unwrap(); format!("bcrypt${cost}${}${}", base64::fmt(salt), base64::fmt(pwh)) } PwCrypto::Sha256 => { @@ -87,7 +103,7 @@ impl PwCrypto { let salt = base64::decode(salt)? .try_into() .map_err(|_| anyhow!("bad password hash format"))?; - let pwh = bcrypt::bcrypt(cost, salt, pw.as_bytes()); + let pwh = bcrypt::hash_with_salt_bytes(pw, cost, salt)?; let pwh = base64::encode(pwh); ( pwh == hash, diff --git a/libeufin-ebics/src/bin/iso20022-codegen.rs b/libeufin-ebics/src/bin/iso20022-codegen.rs @@ -0,0 +1,206 @@ +/* +* This file is part of LibEuFin. +* Copyright (C) 2026 Taler Systems S.A. + +* LibEuFin is free software; you can redistribute it and/or modify +* it under the terms of the GNU Affero General Public License as +* published by the Free Software Foundation; either version 3, or +* (at your option) any later version. + +* LibEuFin is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General +* Public License for more details. + +* You should have received a copy of the GNU Affero General Public +* License along with LibEuFin; see the file COPYING. If not, see +* <http://www.gnu.org/licenses/> +*/ + +use std::{ + collections::BTreeMap, + fmt::Write as _, + io::{Cursor, Read as _}, +}; + +use calamine::{DataType, Reader as _, Xlsx}; +use reqwest::StatusCode; +use tokio::join; +use zip::ZipArchive; + +pub async fn iso20022codegen_external_code_set() { + let res = reqwest::get( + "https://www.iso20022.org/sites/default/files/media/file/ExternalCodeSets_XLSX.zip", + ) + .await + .unwrap(); + + assert_eq!(res.status(), StatusCode::OK); + let zipped = res.bytes().await.unwrap(); + let mut zip = ZipArchive::new(Cursor::new(&zipped)).unwrap(); + assert_eq!(zip.len(), 1); + + let mut bytes = Vec::new(); + zip.by_index(0).unwrap().read_to_end(&mut bytes).unwrap(); + let mut excel: Xlsx<_> = calamine::open_workbook_from_rs(Cursor::new(&bytes)).unwrap(); + + let mut code_sets: BTreeMap<_, Vec<_>> = BTreeMap::new(); + + let range = excel.worksheet_range("AllCodeSets").unwrap(); + for row in range.rows() { + let set = row[0].as_string().unwrap(); + let code = row[1].as_string().unwrap(); + let name = row[2].as_string().unwrap().replace('-', ""); + let definition = row[3] + .as_string() + .unwrap() + .split(['.', '\n']) + .next() + .unwrap() + .trim() + .replace("_x000D_", ""); + let vec = code_sets.entry(set).or_default(); + vec.push((code, name, definition)) + } + + let mut out = " +/* + * This file is part of LibEuFin. + * Copyright (C) 2026 Taler Systems S.A. + + * LibEuFin is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation; either version 3, or + * (at your option) any later version. + + * LibEuFin is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General + * Public License for more details. + + * You should have received a copy of the GNU Affero General Public + * License along with LibEuFin; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/> + */ + +// THIS FILE IS GENERATED, DO NOT EDIT + +use taler_macros::EnumMeta; + " + .to_string(); + + for (set, enum_name) in [ + ("ExternalStatusReason1Code", "StatusReason"), + ("ExternalPaymentGroupStatus1Code", "PaymentGroupStatus"), + ( + "ExternalPaymentTransactionStatus1Code", + "PaymentTransactionStatus", + ), + ("ExternalReturnReason1Code", "ReturnReason"), + ] { + let set = code_sets.get_mut(set).unwrap(); + set.sort_unstable_by_key(|(code, _, _)| code.clone()); + writeln!( + &mut out, + " + #[derive(Debug, Clone, Copy, PartialEq, Eq, EnumMeta)] + #[enum_meta(DomainCode, Description, Str)] + pub enum {enum_name} {{ + " + ) + .unwrap(); + for (code, name, description) in set.iter() { + writeln!(&mut out, "/// {description}").unwrap(); + writeln!(&mut out, "#[code = \"{code}\"]").unwrap(); + writeln!(&mut out, "{name},").unwrap(); + } + writeln!(&mut out, "}}").unwrap(); + } + std::fs::write("src/iso20022/status_code.rs", out).unwrap(); +} + +pub async fn iso20022codegen_bank_transaction_code() { + let res = reqwest::get( + "https://www.iso20022.org/sites/default/files/media/file/BTC_Codification_21March2024.xlsx", + ) + .await + .unwrap(); + + assert_eq!(res.status(), StatusCode::OK); + let bytes = res.bytes().await.unwrap(); + let mut excel: Xlsx<_> = calamine::open_workbook_from_rs(Cursor::new(&bytes)).unwrap(); + + let mut domain = BTreeMap::new(); + let mut family = BTreeMap::new(); + let mut subfamily = BTreeMap::new(); + + let range = excel.worksheet_range("BTC_Codification").unwrap(); + + for row in range.rows().skip(3) { + for (i, set) in [&mut domain, &mut family, &mut subfamily] + .into_iter() + .enumerate() + { + let name = row[i].as_string().unwrap(); + let code = row[i + 3].as_string().unwrap(); + let code = code.trim().to_string(); + set.insert(code, name); + } + } + + let mut out = " +/* + * This file is part of LibEuFin. + * Copyright (C) 2026 Taler Systems S.A. + + * LibEuFin is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation; either version 3, or + * (at your option) any later version. + + * LibEuFin is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General + * Public License for more details. + + * You should have received a copy of the GNU Affero General Public + * License along with LibEuFin; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/> + */ + +// THIS FILE IS GENERATED, DO NOT EDIT + +use taler_macros::EnumMeta; + " + .to_string(); + + for (set, enum_name) in [ + (domain, "BankTxDomainCode"), + (family, "BankTxFamilyCode"), + (subfamily, "BankTxSubFamilyCode"), + ] { + writeln!( + &mut out, + " + #[derive(Debug, Clone, Copy, PartialEq, Eq, EnumMeta)] + #[enum_meta(Description, Str)] + pub enum {enum_name} {{ + " + ) + .unwrap(); + for (code, description) in set.iter() { + writeln!(&mut out, "/// {description}").unwrap(); + writeln!(&mut out, "{code},").unwrap(); + } + writeln!(&mut out, "}}").unwrap(); + } + std::fs::write("src/iso20022/bank_tx_code.rs", out).unwrap(); +} + +#[tokio::main] +pub async fn main() { + join!( + iso20022codegen_external_code_set(), + iso20022codegen_bank_transaction_code() + ); +}