dev_kit/command/
base64.rs1use crate::command::StringInput;
2use base64::Engine;
3use itertools::Itertools;
4use std::fs;
5use std::path::PathBuf;
6use std::str::FromStr;
7
8#[derive(clap::Subcommand)]
9pub enum Base64Command {
10 #[clap(about = "base64 decode, alias 'd'", alias = "d")]
11 Decode {
12 #[arg(help = "base64 text to decode", default_value = "")]
13 input: StringInput,
14 #[arg(short, long, help = "url safe", default_value = "false")]
15 url_safe: bool,
16 #[arg(short, long, help = "no padding", default_value = "false")]
17 no_pad: bool,
18 #[arg(short, long, help = "raw output", default_value = "false")]
19 raw_output: bool,
20 #[arg(short, long, help = "file to write output")]
21 file: Option<PathBuf>,
22 },
23 #[clap(about = "base64 encode, alias 'e'", alias = "e")]
24 Encode {
25 #[arg(help = "base64 text to decode", default_value = "")]
26 input: StringInput,
27 #[arg(short, long, help = "url safe", default_value = "false")]
28 url_safe: bool,
29 #[arg(short, long, help = "no padding", default_value = "false")]
30 no_pad: bool,
31 #[arg(short, long, help = "file to write output")]
32 file: Option<PathBuf>,
33 },
34}
35
36pub fn decode(input: &str, url_safe: bool, no_pad: bool) -> crate::Result<Vec<u8>> {
37 let text = if let Some(input) = PathBuf::from_str(input).ok().and_then(|p| fs::read_to_string(p).ok()) {
38 input
39 } else {
40 input.to_string()
41 };
42 if url_safe {
43 if no_pad {
44 base64::prelude::BASE64_URL_SAFE.decode(text.as_bytes())
45 } else {
46 base64::prelude::BASE64_URL_SAFE_NO_PAD.decode(text.as_bytes())
47 }
48 } else {
49 if no_pad {
50 base64::prelude::BASE64_STANDARD_NO_PAD.decode(text.as_bytes())
51 } else {
52 base64::prelude::BASE64_STANDARD.decode(text.as_bytes())
53 }
54 }.map_err(|e| anyhow::anyhow!("base64 encode failed: {}", e))
55}
56
57pub fn encode(input: &str, url_safe: bool, no_pad: bool) -> crate::Result<String> {
58 let data = if let Some(input) = PathBuf::from_str(input).ok().and_then(|p| fs::read(p).ok()) {
59 input
60 } else {
61 input.as_bytes().to_vec()
62 };
63 let string = if url_safe {
64 if no_pad {
65 base64::prelude::BASE64_URL_SAFE.encode(data)
66 } else {
67 base64::prelude::BASE64_URL_SAFE_NO_PAD.encode(data)
68 }
69 } else {
70 if no_pad {
71 base64::prelude::BASE64_STANDARD_NO_PAD.encode(data)
72 } else {
73 base64::prelude::BASE64_STANDARD.encode(data)
74 }
75 };
76 Ok(string)
77}
78
79pub enum Base64Val {
80 EncodeString(String),
81 DecodeBytes(Vec<u8>),
82}
83
84impl super::Command for Base64Command {
85 fn run(&self) -> crate::Result<()> {
86 match self {
87 Self::Decode { input, url_safe, no_pad, raw_output, file } => {
88 let data = decode(&input, *url_safe, *no_pad)?;
89 match (*raw_output, file) {
90 (false, None) => {
91 let text = String::from_utf8_lossy(&data);
92 println!("{}", text);
93 }
94 (true, None) => {
95 let text = data.chunks(8).flatten().map(|it| {
96 format!("{:02x} ", *it)
97 }).join("\n");
98 println!("{}", text);
99 }
100 (false, Some(file)) => {
101 let text = String::from_utf8_lossy(&data).to_string();
102 let _ = std::fs::write(file, text)?;
103 println!("write to {}", file.display())
104 }
105 (true, Some(file)) => {
106 let _ = std::fs::write(file, data)?;
107 println!("write to {}", file.display())
108 }
109 }
110 }
111 Self::Encode { input, url_safe, no_pad, file } => {
112 let text = encode(&input, *url_safe, *no_pad)?;
113 if let Some(file) = file {
114 let _ = std::fs::write(file, text)?;
115 println!("write to {}", file.display())
116 } else {
117 println!("{}", text);
118 }
119 }
120 }
121 Ok(())
122 }
123}
124
125