happy_cracking/crypto/
chain.rs1use anyhow::{Context, Result};
2use clap::Subcommand;
3
4use crate::crypto;
5
6const MAX_OPERATIONS: usize = 50;
7const MAX_OUTPUT_SIZE: usize = 50 * 1024 * 1024; #[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(¤t, op).with_context(|| format!("Failed at operation '{}'", op))
79 })
80}