road-runner-common 0.21.0

Shared Rust utilities for exchange ecosystem backend services.
Documentation
//! Masking for values that appear in notification payloads.
//!
//! A message body travels further than the system that produced it — into an inbox, an
//! SMS, an operations channel — so anything identifying is reduced to the minimum that
//! still lets the reader recognize what the message is about.

/// Keep the country prefix and the last four digits of an IBAN, mask the rest, and group
/// in fours the way an IBAN is normally printed. A Turkish IBAN is 26 characters, which
/// is not a multiple of four, so the revealed tail straddles the last two groups:
/// `TR330006100519786457841326` → `TR** **** **** **** **** **13 26`.
///
/// Whitespace in the input is ignored, so the same account renders identically whether it
/// was stored grouped or compact.
pub fn mask_iban(iban: &str) -> String {
    let compact: String = iban.chars().filter(|c| !c.is_whitespace()).collect();
    // Too short to mask meaningfully — reveal nothing rather than most of it.
    if compact.len() <= 6 {
        return "*".repeat(compact.len());
    }

    let masked: String = compact
        .char_indices()
        .map(|(index, character)| {
            if index < 2 || index >= compact.len() - 4 {
                character
            } else {
                '*'
            }
        })
        .collect();

    masked
        .as_bytes()
        .chunks(4)
        .map(|chunk| String::from_utf8_lossy(chunk).into_owned())
        .collect::<Vec<_>>()
        .join(" ")
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn masking_keeps_only_the_country_and_the_last_four() {
        let expected = "TR** **** **** **** **** **13 26";
        assert_eq!(mask_iban("TR330006100519786457841326"), expected);
        assert_eq!(mask_iban("TR33 0006 1005 1978 6457 8413 26"), expected);
        // Nothing worth revealing in a value this short.
        assert_eq!(mask_iban("TR3300"), "******");
        assert_eq!(mask_iban(""), "");
    }
}