-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Feature: Add Base64 encode/decode support && refractor cli mod
- Loading branch information
Showing
13 changed files
with
261 additions
and
101 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
use clap::Parser; | ||
use std::{fmt::Display, str::FromStr}; | ||
|
||
use super::parse_input_file; | ||
#[derive(Debug, Parser)] | ||
pub struct Base64Opts { | ||
#[command(subcommand)] | ||
pub subcmd: Base64SubCommand, | ||
} | ||
|
||
#[derive(Debug, Parser)] | ||
pub enum Base64SubCommand { | ||
#[command(name = "encode", about = "base64 encode")] | ||
Encode(Base64EncodeOpts), | ||
#[command(name = "decode", about = "base64 decode")] | ||
Decode(Base64DecodeOpts), | ||
} | ||
|
||
#[derive(Debug, Parser)] | ||
pub struct Base64EncodeOpts { | ||
#[arg(short, long, value_parser=parse_input_file, required = true, help = "input file path, or '-' for stdin")] | ||
pub input: String, | ||
#[arg(long, default_value = "standard", value_parser=Base64Format::from_str, help = "base64 format: [standard, urlsafe, nopadding]")] | ||
pub format: Base64Format, | ||
} | ||
|
||
#[derive(Debug, Parser)] | ||
pub struct Base64DecodeOpts { | ||
#[arg(short, long, value_parser=parse_input_file, help = "input file path, or '-' for stdin")] | ||
pub input: String, | ||
#[arg(long, value_parser=Base64Format::from_str, default_value = "standard", help = "base64 format: [standard, urlsafe, nopadding]")] | ||
pub format: Base64Format, | ||
} | ||
|
||
#[derive(Debug, Clone, Copy)] | ||
pub enum Base64Format { | ||
Standard, | ||
UrlSafe, | ||
NoPadding, | ||
} | ||
|
||
impl FromStr for Base64Format { | ||
type Err = anyhow::Error; | ||
|
||
fn from_str(s: &str) -> Result<Self, Self::Err> { | ||
match s.to_lowercase().as_str() { | ||
"standard" => Ok(Base64Format::Standard), | ||
"urlsafe" => Ok(Base64Format::UrlSafe), | ||
"nopadding" => Ok(Base64Format::NoPadding), | ||
v => Err(anyhow::anyhow!("invalid base64 format: {}", v)), | ||
} | ||
} | ||
} | ||
|
||
impl From<Base64Format> for &'static str { | ||
fn from(f: Base64Format) -> Self { | ||
match f { | ||
Base64Format::Standard => "standard", | ||
Base64Format::UrlSafe => "urlsafe", | ||
Base64Format::NoPadding => "nopadding", | ||
} | ||
} | ||
} | ||
|
||
impl Display for Base64Format { | ||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||
write!(f, "{}", Into::<&str>::into(*self)) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
use super::parse_input_file; | ||
use clap::Parser; | ||
use std::{fmt::Display, str::FromStr}; | ||
|
||
#[derive(Debug, Parser)] | ||
pub struct CsvOpts { | ||
#[arg(long, default_value_t = true)] | ||
pub header: bool, | ||
#[arg(short, long, default_value_t = ',')] | ||
pub delimiter: char, | ||
#[arg(short, long, required = true, value_parser=parse_input_file)] | ||
pub input: String, | ||
#[arg(short, long)] // default_value_t = "output.json".into() | ||
pub output: Option<String>, | ||
#[arg(long, default_value = "json", value_parser=OutputFormat::from_str)] | ||
pub format: OutputFormat, | ||
} | ||
|
||
#[derive(Debug, Clone, Copy)] | ||
pub enum OutputFormat { | ||
Json, | ||
Yaml, | ||
} | ||
|
||
impl FromStr for OutputFormat { | ||
type Err = anyhow::Error; | ||
|
||
fn from_str(s: &str) -> Result<Self, Self::Err> { | ||
match s.to_lowercase().as_str() { | ||
"json" => Ok(OutputFormat::Json), | ||
"yaml" => Ok(OutputFormat::Yaml), | ||
v => Err(anyhow::anyhow!("invalid output format: {}", v)), | ||
} | ||
} | ||
} | ||
|
||
impl From<OutputFormat> for &'static str { | ||
fn from(f: OutputFormat) -> Self { | ||
match f { | ||
OutputFormat::Json => "json", | ||
OutputFormat::Yaml => "yaml", | ||
} | ||
} | ||
} | ||
|
||
impl Display for OutputFormat { | ||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||
write!(f, "{}", Into::<&str>::into(*self)) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
use clap::Parser; | ||
#[derive(Debug, Parser)] | ||
pub struct GenpassOpts { | ||
#[arg(long, default_value_t = false)] | ||
pub no_upper: bool, | ||
#[arg(long, default_value_t = false)] | ||
pub no_lower: bool, | ||
#[arg(long, default_value_t = false)] | ||
pub no_number: bool, | ||
#[arg(long, default_value_t = false)] | ||
pub no_symbol: bool, | ||
#[arg(short, long, default_value_t = 16)] | ||
pub length: u8, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
mod base64_opts; | ||
mod csv_opts; | ||
mod genpass_opts; | ||
|
||
use std::fs; | ||
|
||
pub use self::base64_opts::{Base64Format, Base64Opts, Base64SubCommand}; | ||
pub use self::csv_opts::{CsvOpts, OutputFormat}; | ||
pub use self::genpass_opts::GenpassOpts; | ||
use clap::Parser; | ||
|
||
#[derive(Debug, Parser)] | ||
#[command(name = "rcli", version, about, author, long_about=None)] | ||
pub struct Opts { | ||
#[command(subcommand)] | ||
pub subcmd: SubCommand, | ||
} | ||
|
||
#[derive(Debug, Parser)] | ||
pub enum SubCommand { | ||
// rcli csv --header xx -delimiter , -input /tmp/1.csv -output output.json | ||
#[command(name = "csv", about = "csv file processor")] | ||
Csv(CsvOpts), | ||
// rcli genpass --upper xx --lower --symbol --number --length | ||
#[command(name = "genpass", about = "generate password")] | ||
Genpass(GenpassOpts), | ||
// rcli base64 --encode/decode --output | ||
#[command(name = "base64", about = "base64 encode/decode")] | ||
Base64(Base64Opts), | ||
} | ||
|
||
// 模块级别的函数,共享input file的解析逻辑 | ||
fn parse_input_file(path: &str) -> Result<String, String> { | ||
if path == "-" || fs::metadata(path).is_ok() { | ||
Ok(path.to_string()) | ||
} else { | ||
Err(format!("file not found: {}", path)) | ||
} | ||
} | ||
|
||
// 单元测试 | ||
#[cfg(test)] | ||
mod tests { | ||
use super::*; | ||
|
||
#[test] | ||
fn test_parse_input_file() { | ||
assert_eq!(parse_input_file("-"), Ok("-".to_string())); | ||
assert_eq!(parse_input_file("*"), Err("file not found: *".to_string())); | ||
assert_eq!(parse_input_file("Cargo.toml"), Ok("Cargo.toml".to_string())); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
mod opts; | ||
mod cli; | ||
mod process; | ||
pub use opts::{CsvOpts, Opts, SubCommand}; | ||
pub use process::{process_csv, process_genpass}; | ||
pub use cli::{Base64SubCommand, Opts, SubCommand}; | ||
pub use process::{process_b64decode, process_b64encode, process_csv, process_genpass}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
use std::io::Read; | ||
|
||
use crate::cli::Base64Format; | ||
use base64::prelude::*; | ||
|
||
// input 可以是 '-', 表示从 stdin 读取,或者是文件路径, 输出到 stdout, 返回一个 reader | ||
fn get_reader(input: &str) -> anyhow::Result<Box<dyn Read>> { | ||
match input { | ||
"-" => Ok(Box::new(std::io::stdin())), | ||
path => Ok(Box::new(std::fs::File::open(path)?)), | ||
} | ||
} | ||
|
||
// base64 encoder, | ||
pub fn process_encode(input: &str, format: Base64Format) -> anyhow::Result<()> { | ||
let mut reader = get_reader(input)?; | ||
// 读取所有的数据 | ||
let mut data = Vec::new(); | ||
reader.read_to_end(&mut data)?; | ||
let encoded = match format { | ||
Base64Format::Standard => BASE64_STANDARD.encode(&data), | ||
Base64Format::UrlSafe => BASE64_URL_SAFE.encode(&data), | ||
Base64Format::NoPadding => BASE64_URL_SAFE_NO_PAD.encode(&data), | ||
}; | ||
println!("{}", encoded); | ||
Ok(()) | ||
} | ||
|
||
pub fn process_decode(input: &str, format: Base64Format) -> anyhow::Result<()> { | ||
let mut reader = get_reader(input)?; | ||
// 读取所有的数据 | ||
let mut data = String::new(); | ||
reader.read_to_string(&mut data)?; | ||
let data = data.trim_end(); | ||
let decode = match format { | ||
Base64Format::Standard => BASE64_STANDARD.decode(data)?, | ||
Base64Format::UrlSafe => BASE64_URL_SAFE.decode(data)?, | ||
Base64Format::NoPadding => BASE64_URL_SAFE_NO_PAD.decode(data)?, | ||
}; | ||
println!("{}", String::from_utf8(decode)?); | ||
Ok(()) | ||
} |
Oops, something went wrong.