jwt_hack/utils/
mod.rs

1use colored::Colorize;
2use std::fmt::Display;
3
4pub mod compression;
5
6/// Displays a success message with a green plus icon prefix
7pub fn log_success<T: Display>(message: T) {
8    println!("{} {}", "[+]".bright_green(), message);
9}
10
11/// Displays an information message with a blue asterisk icon prefix
12pub fn log_info<T: Display>(message: T) {
13    println!("{} {}", "[*]".bright_blue(), message);
14}
15
16/// Displays a warning message with a yellow exclamation mark prefix
17pub fn log_warning<T: Display>(message: T) {
18    println!("{} {}", "[!]".yellow(), message);
19}
20
21/// Displays an error message with a red minus icon prefix
22pub fn log_error<T: Display>(message: T) {
23    println!("{} {}", "[-]".bright_red(), message);
24}
25
26/// Displays a debug message with a cyan question mark prefix for development purposes
27#[allow(dead_code)]
28pub fn log_debug<T: Display>(message: T) {
29    println!("{} {}", "[?]".cyan(), message);
30}
31
32/// Returns a value formatted with color based on success status (green for success, red for failure)
33#[allow(dead_code)]
34pub fn format_value<T: Display>(value: T, is_success: bool) -> colored::ColoredString {
35    if is_success {
36        format!("{value}").bright_green()
37    } else {
38        format!("{value}").bright_red()
39    }
40}
41
42/// Colorizes JWT token components for better visual distinction (header=blue, payload=magenta, signature=yellow)
43pub fn format_jwt_token(token: &str) -> String {
44    let parts: Vec<&str> = token.split('.').collect();
45
46    if parts.len() < 2 {
47        return token.to_string();
48    }
49
50    if parts.len() == 2 {
51        // Header and payload only
52        return format!("{}.{}", parts[0].bright_blue(), parts[1].bright_magenta());
53    }
54
55    // Full JWT with signature
56    format!(
57        "{}.{}.{}",
58        parts[0].bright_blue(),
59        parts[1].bright_magenta(),
60        parts[2].bright_yellow()
61    )
62}
63
64/// Creates an animated spinner to indicate ongoing operations with the specified message
65pub fn start_progress(message: &str) -> indicatif::ProgressBar {
66    let pb = indicatif::ProgressBar::new_spinner();
67    pb.set_style(
68        indicatif::ProgressStyle::default_spinner()
69            .template("{spinner:.blue} {msg}")
70            .unwrap()
71            .tick_strings(&["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"]),
72    );
73    pb.set_message(message.to_string());
74    pb.enable_steady_tick(std::time::Duration::from_millis(100));
75    pb
76}
77
78/// Converts a duration into human-readable format (hours, minutes, seconds)
79#[allow(dead_code)]
80pub fn format_duration(duration: std::time::Duration) -> String {
81    let seconds = duration.as_secs();
82
83    if seconds < 60 {
84        return format!("{seconds}s");
85    }
86
87    let minutes = seconds / 60;
88    let remain_seconds = seconds % 60;
89
90    if minutes < 60 {
91        return format!("{minutes}m {remain_seconds}s");
92    }
93
94    let hours = minutes / 60;
95    let remain_minutes = minutes % 60;
96
97    format!("{hours}h {remain_minutes}m {remain_seconds}s")
98}
99
100/// Formats a base64 encoded string for display with preview (shows first/last chars with length)
101pub fn format_base64_preview(base64_str: &str) -> String {
102    const PREVIEW_LEN: usize = 8;
103
104    if base64_str.len() <= PREVIEW_LEN * 2 {
105        return base64_str.to_string();
106    }
107
108    let start = &base64_str[..PREVIEW_LEN];
109    let end = &base64_str[base64_str.len() - PREVIEW_LEN..];
110    let length = base64_str.len();
111
112    format!("{}...{} ({} chars)", start, end, length)
113}
114
115#[cfg(test)]
116mod tests {
117    use super::*;
118    use colored::Colorize;
119    use std::time::Duration;
120
121    #[test]
122    fn test_format_jwt_token_full() {
123        let token = "header.payload.signature";
124        let expected = format!(
125            "{}.{}.{}",
126            "header".bright_blue(),
127            "payload".bright_magenta(),
128            "signature".bright_yellow()
129        );
130        assert_eq!(format_jwt_token(token), expected);
131    }
132
133    #[test]
134    fn test_format_jwt_token_no_signature() {
135        let token = "header.payload";
136        let expected = format!("{}.{}", "header".bright_blue(), "payload".bright_magenta());
137        assert_eq!(format_jwt_token(token), expected);
138    }
139
140    #[test]
141    fn test_format_jwt_token_invalid_format() {
142        let token = "invalidtoken";
143        assert_eq!(format_jwt_token(token), "invalidtoken");
144    }
145
146    #[test]
147    fn test_format_jwt_token_empty_string() {
148        let token = "";
149        assert_eq!(format_jwt_token(token), "");
150    }
151
152    #[test]
153    fn test_format_duration_util_seconds() {
154        assert_eq!(format_duration(Duration::from_secs(5)), "5s");
155    }
156
157    #[test]
158    fn test_format_duration_util_minutes_seconds() {
159        assert_eq!(format_duration(Duration::from_secs(125)), "2m 5s");
160    }
161
162    #[test]
163    fn test_format_duration_util_hours_minutes_seconds() {
164        assert_eq!(format_duration(Duration::from_secs(3723)), "1h 2m 3s");
165    }
166
167    #[test]
168    fn test_format_duration_util_exact_minute() {
169        assert_eq!(format_duration(Duration::from_secs(60)), "1m 0s");
170    }
171
172    #[test]
173    fn test_format_duration_util_exact_hour() {
174        assert_eq!(format_duration(Duration::from_secs(3600)), "1h 0m 0s");
175    }
176
177    #[test]
178    fn test_format_duration_util_zero() {
179        assert_eq!(format_duration(Duration::ZERO), "0s");
180    }
181
182    #[test]
183    fn test_format_value_success() {
184        let expected = "success_text".bright_green();
185        assert_eq!(format_value("success_text", true), expected);
186    }
187
188    #[test]
189    fn test_format_value_failure() {
190        let expected = "failure_text".bright_red();
191        assert_eq!(format_value("failure_text", false), expected);
192    }
193
194    #[test]
195    fn test_format_value_integer() {
196        let expected = "123".bright_green(); // is_success = true
197        assert_eq!(format_value(123, true), expected);
198
199        let expected_fail = "456".bright_red(); // is_success = false
200        assert_eq!(format_value(456, false), expected_fail);
201    }
202}