1use fancy_regex::Regex;
6use std::fmt::Display;
7use std::sync::OnceLock;
8
9fn get_expressions() -> &'static Vec<Regex> {
10 static EXPRESSIONS: OnceLock<Vec<Regex>> = OnceLock::new();
11 EXPRESSIONS.get_or_init(|| {
12 vec![
13 Regex::new(
15 r##"gl(pat|oas|dt|rt|rtr|cbt|ptt|ft|imt|agent|wt|soat|ffct)-[0-9a-zA-Z\-_]*"##,
16 )
17 .unwrap(),
18 Regex::new(r##"g(hp|ithub_pat|ho|hu|hs|hr)_[0-9a-zA-Z\-_]*"##).unwrap(),
21 ]
22 })
23}
24
25pub fn redact(input: &impl Display) -> String {
28 let mut copy = input.to_string();
29 for expr in get_expressions() {
30 copy = expr.replace_all(©, "LORRY_REDACTED").to_string();
31 }
32
33 static GENERAL_EXPRESSION: OnceLock<Regex> = OnceLock::new();
34 let general_expression = GENERAL_EXPRESSION.get_or_init(|| {
35 Regex::new(
36 r##"(?<protocol>https?://)(?<username>.+?):(?<password>.+?)@(?<address>[\w\-\./]+)"##,
37 )
38 .unwrap()
39 });
40
41 if let Ok(Some(caps)) = general_expression.captures(©) {
42 let group = caps.get(3).unwrap(); copy = format!(
44 "{}{}{}",
45 ©[..group.start()],
46 "LORRY_REDACTED",
47 ©[group.end()..]
48 )
49 }
50
51 copy
52}
53
54#[cfg(test)]
55mod tests {
56 use super::*;
57
58 struct TestCase<'a> {
59 pub input: &'a str,
60 pub expected: &'a str,
61 }
62
63 impl TestCase<'_> {
64 pub fn check(&self) {
65 let result = redact(&self.input.to_string());
66 assert!(result == self.expected);
67 }
68 }
69
70 #[test]
71 fn test_redact() {
72 TestCase {
73 input: "glpat-Y38-kU_3pviux6H1D9ec",
74 expected: "LORRY_REDACTED",
75 }
76 .check();
77 TestCase {
78 input: "glpat-AdmAbJdT-FMYPa_2bQyy",
79 expected: "LORRY_REDACTED",
80 }
81 .check();
82 TestCase {
83 input: "glpat-MjW2FqijnvVBs7yPEoDG",
84 expected: "LORRY_REDACTED",
85 }
86 .check();
87 TestCase {
88 input: "Using git binary to push remote: http://oauth2:glpat-25HjHgcpRJsY_JQweJYa@localhost:9999/lorry-mirrors/test/lorry.git",
89 expected: "Using git binary to push remote: http://oauth2:LORRY_REDACTED@localhost:9999/lorry-mirrors/test/lorry.git",
90 }.check();
91 TestCase {
92 input: "Using git binary to push remote: http://oauth2:this_is_a_random_prefix-25HjHgcpRJsY_JQweJYa@localhost:9999/lorry-mirrors/test/lorry.git",
93 expected: "Using git binary to push remote: http://oauth2:LORRY_REDACTED@localhost:9999/lorry-mirrors/test/lorry.git",
94 }.check();
95 }
96}