Skip to main content

happy_cracking/crypto/
chain.rs

1use anyhow::{Context, Result};
2use clap::Subcommand;
3
4use crate::crypto;
5
6const MAX_OPERATIONS: usize = 50;
7const MAX_OUTPUT_SIZE: usize = 50 * 1024 * 1024; // 50MB
8
9#[derive(Subcommand)]
10pub enum ChainAction {
11    #[command(about = "Apply a chain of operations")]
12    Run {
13        #[arg(help = "Input data")]
14        input: String,
15        #[arg(
16            short,
17            long,
18            help = "Comma-separated list of operations (e.g. base64-decode,rot13,hex-encode)"
19        )]
20        ops: String,
21    },
22}
23
24pub fn run(action: ChainAction) -> Result<()> {
25    match action {
26        ChainAction::Run { input, ops } => {
27            println!("{}", chain(&input, &ops)?);
28        }
29    }
30    Ok(())
31}
32
33fn apply_operation(input: &str, op: &str) -> Result<String> {
34    match op {
35        "base64-encode" => Ok(crypto::base64::encode(input)),
36        "base64-decode" => crypto::base64::decode(input),
37        "base32-encode" => Ok(crypto::base32::encode(input)),
38        "base32-decode" => crypto::base32::decode(input),
39        "hex-encode" => Ok(crypto::hex::encode(input)),
40        "hex-decode" => crypto::hex::decode(input),
41        "url-encode" => Ok(crypto::url::encode(input)),
42        "url-decode" => crypto::url::decode(input),
43        "binary-encode" => Ok(crypto::binary::encode(input)),
44        "binary-decode" => crypto::binary::decode(input),
45        "rot13" => Ok(crypto::rot::rot13(input)),
46        "rot47" => Ok(crypto::rot::rot47(input)),
47        "reverse" => Ok(input.chars().rev().collect()),
48        "upper" => Ok(input.to_uppercase()),
49        "lower" => Ok(input.to_lowercase()),
50        _ => anyhow::bail!("Unknown operation: {}", op),
51    }
52}
53
54pub fn chain(input: &str, ops: &str) -> Result<String> {
55    if ops.trim().is_empty() {
56        return Ok(input.to_string());
57    }
58
59    let op_count = ops.split(',').count();
60    if op_count > MAX_OPERATIONS {
61        anyhow::bail!(
62            "Too many operations: {} (limit: {})",
63            op_count,
64            MAX_OPERATIONS
65        );
66    }
67
68    ops.split(',')
69        .map(|op| op.trim())
70        .try_fold(input.to_string(), |current, op| {
71            if current.len() > MAX_OUTPUT_SIZE {
72                anyhow::bail!(
73                    "Output size limit exceeded: {} bytes (limit: {} bytes)",
74                    current.len(),
75                    MAX_OUTPUT_SIZE
76                );
77            }
78            apply_operation(&current, op).with_context(|| format!("Failed at operation '{}'", op))
79        })
80}