mirror of
https://github.com/nushell/nushell.git
synced 2025-06-18 16:07:02 +02:00
Replace the old encode base64
and decode base64
with new-base64 commands (#14018)
<!-- if this PR closes one or more issues, you can automatically link the PR with them by using one of the [*linking keywords*](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword), e.g. - this PR should close #xxxx - fixes #xxxx you can also mention related issues, PRs or discussions! --> # Description <!-- Thank you for improving Nushell. Please, check our [contributing guide](../CONTRIBUTING.md) and talk to the core team before making major changes. Description of your pull request goes here. **Provide examples and/or screenshots** if your changes affect the user experience. --> Maybe we can deprecate `encode new-base64` and `decode new-base64` first, to make the code clean and simple I'd rather remove the old `encode base64` and `decode base64` and replace them with the `* new-base64` commands. Related PR: https://github.com/nushell/nushell/pull/13428 # User-Facing Changes <!-- List of all changes that impact the user experience here. This helps us keep track of breaking changes. --> - `encode new-base64` --> `encode base64` - `decode new-base64` --> `decode base64` # Tests + Formatting <!-- Don't forget to add tests that cover your changes. Make sure you've run and fixed any issues with these commands: - `cargo fmt --all -- --check` to check standard code formatting (`cargo fmt --all` applies these changes) - `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used` to check that you're using the standard code style - `cargo test --workspace` to check that all tests pass (on Windows make sure to [enable developer mode](https://learn.microsoft.com/en-us/windows/apps/get-started/developer-mode-features-and-debugging)) - `cargo run -- -c "use toolkit.nu; toolkit test stdlib"` to run the tests for the standard library > **Note** > from `nushell` you can also use the `toolkit` as follows > ```bash > use toolkit.nu # or use an `env_change` hook to activate it automatically > toolkit check pr > ``` --> # After Submitting <!-- If your PR had any user-facing changes, update [the documentation](https://github.com/nushell/nushell.github.io) after the PR is merged, if necessary. This will help us keep the docs up to date. --> It's a breaking change
This commit is contained in:
parent
4c8b09eb97
commit
2830ec008c
@ -188,8 +188,6 @@ pub fn add_shell_command_context(mut engine_state: EngineState) -> EngineState {
|
|||||||
EncodeBase32Hex,
|
EncodeBase32Hex,
|
||||||
DecodeBase64,
|
DecodeBase64,
|
||||||
EncodeBase64,
|
EncodeBase64,
|
||||||
DecodeBase64Old,
|
|
||||||
EncodeBase64Old,
|
|
||||||
DetectColumns,
|
DetectColumns,
|
||||||
Parse,
|
Parse,
|
||||||
Split,
|
Split,
|
||||||
|
@ -38,11 +38,11 @@ pub struct DecodeBase64;
|
|||||||
|
|
||||||
impl Command for DecodeBase64 {
|
impl Command for DecodeBase64 {
|
||||||
fn name(&self) -> &str {
|
fn name(&self) -> &str {
|
||||||
"decode new-base64"
|
"decode base64"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build("decode new-base64")
|
Signature::build("decode base64")
|
||||||
.input_output_types(vec![(Type::String, Type::Binary)])
|
.input_output_types(vec![(Type::String, Type::Binary)])
|
||||||
.allow_variants_without_examples(true)
|
.allow_variants_without_examples(true)
|
||||||
.switch("url", "Decode the URL-safe Base64 version.", None)
|
.switch("url", "Decode the URL-safe Base64 version.", None)
|
||||||
@ -62,17 +62,17 @@ impl Command for DecodeBase64 {
|
|||||||
vec![
|
vec![
|
||||||
Example {
|
Example {
|
||||||
description: "Decode a Base64 string",
|
description: "Decode a Base64 string",
|
||||||
example: r#""U29tZSBEYXRh" | decode new-base64 | decode"#,
|
example: r#""U29tZSBEYXRh" | decode base64 | decode"#,
|
||||||
result: None,
|
result: None,
|
||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "Decode arbitrary data",
|
description: "Decode arbitrary data",
|
||||||
example: r#""/w==" | decode new-base64"#,
|
example: r#""/w==" | decode base64"#,
|
||||||
result: Some(Value::test_binary(vec![0xFF])),
|
result: Some(Value::test_binary(vec![0xFF])),
|
||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "Decode a URL-safe Base64 string",
|
description: "Decode a URL-safe Base64 string",
|
||||||
example: r#""_w==" | decode new-base64 --url"#,
|
example: r#""_w==" | decode base64 --url"#,
|
||||||
result: Some(Value::test_binary(vec![0xFF])),
|
result: Some(Value::test_binary(vec![0xFF])),
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
@ -109,11 +109,11 @@ pub struct EncodeBase64;
|
|||||||
|
|
||||||
impl Command for EncodeBase64 {
|
impl Command for EncodeBase64 {
|
||||||
fn name(&self) -> &str {
|
fn name(&self) -> &str {
|
||||||
"encode new-base64"
|
"encode base64"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build("encode new-base64")
|
Signature::build("encode base64")
|
||||||
.input_output_types(vec![
|
.input_output_types(vec![
|
||||||
(Type::String, Type::String),
|
(Type::String, Type::String),
|
||||||
(Type::Binary, Type::String),
|
(Type::Binary, Type::String),
|
||||||
@ -135,17 +135,17 @@ impl Command for EncodeBase64 {
|
|||||||
vec![
|
vec![
|
||||||
Example {
|
Example {
|
||||||
description: "Encode a string with Base64",
|
description: "Encode a string with Base64",
|
||||||
example: r#""Alphabet from A to Z" | encode new-base64"#,
|
example: r#""Alphabet from A to Z" | encode base64"#,
|
||||||
result: Some(Value::test_string("QWxwaGFiZXQgZnJvbSBBIHRvIFo=")),
|
result: Some(Value::test_string("QWxwaGFiZXQgZnJvbSBBIHRvIFo=")),
|
||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "Encode arbitrary data",
|
description: "Encode arbitrary data",
|
||||||
example: r#"0x[BE EE FF] | encode new-base64"#,
|
example: r#"0x[BE EE FF] | encode base64"#,
|
||||||
result: Some(Value::test_string("vu7/")),
|
result: Some(Value::test_string("vu7/")),
|
||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "Use a URL-safe alphabet",
|
description: "Use a URL-safe alphabet",
|
||||||
example: r#"0x[BE EE FF] | encode new-base64 --url"#,
|
example: r#"0x[BE EE FF] | encode base64 --url"#,
|
||||||
result: Some(Value::test_string("vu7_")),
|
result: Some(Value::test_string("vu7_")),
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
@ -1,377 +0,0 @@
|
|||||||
use base64::{
|
|
||||||
alphabet,
|
|
||||||
engine::{
|
|
||||||
general_purpose::{NO_PAD, PAD},
|
|
||||||
GeneralPurpose,
|
|
||||||
},
|
|
||||||
Engine,
|
|
||||||
};
|
|
||||||
use nu_cmd_base::input_handler::{operate as general_operate, CmdArgument};
|
|
||||||
use nu_protocol::{
|
|
||||||
ast::CellPath,
|
|
||||||
engine::{Call, EngineState},
|
|
||||||
PipelineData, ShellError, Span, Spanned, Value,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const CHARACTER_SET_DESC: &str = "specify the character rules for encoding the input.\n\
|
|
||||||
\tValid values are 'standard', 'standard-no-padding', 'url-safe', 'url-safe-no-padding',\
|
|
||||||
'binhex', 'bcrypt', 'crypt', 'mutf7'";
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct Base64Config {
|
|
||||||
pub character_set: Spanned<String>,
|
|
||||||
pub action_type: ActionType,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
|
||||||
pub enum ActionType {
|
|
||||||
Encode,
|
|
||||||
Decode,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Arguments {
|
|
||||||
cell_paths: Option<Vec<CellPath>>,
|
|
||||||
binary: bool,
|
|
||||||
encoding_config: Base64Config,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CmdArgument for Arguments {
|
|
||||||
fn take_cell_paths(&mut self) -> Option<Vec<CellPath>> {
|
|
||||||
self.cell_paths.take()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) struct Base64CommandArguments {
|
|
||||||
pub(super) character_set: Option<Spanned<String>>,
|
|
||||||
pub(super) action_type: ActionType,
|
|
||||||
pub(super) binary: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn operate(
|
|
||||||
engine_state: &EngineState,
|
|
||||||
call: &Call,
|
|
||||||
input: PipelineData,
|
|
||||||
cell_paths: Vec<CellPath>,
|
|
||||||
args: Base64CommandArguments,
|
|
||||||
) -> Result<PipelineData, ShellError> {
|
|
||||||
let head = call.head;
|
|
||||||
let cell_paths = (!cell_paths.is_empty()).then_some(cell_paths);
|
|
||||||
|
|
||||||
// Default the character set to standard if the argument is not specified.
|
|
||||||
let character_set = match args.character_set {
|
|
||||||
Some(inner_tag) => inner_tag,
|
|
||||||
None => Spanned {
|
|
||||||
item: "standard".to_string(),
|
|
||||||
span: head, // actually this span is always useless, because default character_set is always valid.
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
let args = Arguments {
|
|
||||||
encoding_config: Base64Config {
|
|
||||||
character_set,
|
|
||||||
action_type: args.action_type,
|
|
||||||
},
|
|
||||||
binary: args.binary,
|
|
||||||
cell_paths,
|
|
||||||
};
|
|
||||||
|
|
||||||
general_operate(action, args, input, call.head, engine_state.signals())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn action(
|
|
||||||
input: &Value,
|
|
||||||
// only used for `decode` action
|
|
||||||
args: &Arguments,
|
|
||||||
command_span: Span,
|
|
||||||
) -> Value {
|
|
||||||
let base64_config = &args.encoding_config;
|
|
||||||
let output_binary = args.binary;
|
|
||||||
|
|
||||||
let config_character_set = &base64_config.character_set;
|
|
||||||
let base64_engine: GeneralPurpose = match config_character_set.item.as_str() {
|
|
||||||
"standard" => GeneralPurpose::new(&alphabet::STANDARD, PAD),
|
|
||||||
"standard-no-padding" => GeneralPurpose::new(&alphabet::STANDARD, NO_PAD),
|
|
||||||
"url-safe" => GeneralPurpose::new(&alphabet::URL_SAFE, PAD),
|
|
||||||
"url-safe-no-padding" => GeneralPurpose::new(&alphabet::URL_SAFE, NO_PAD),
|
|
||||||
"bcrypt" => GeneralPurpose::new(&alphabet::BCRYPT, NO_PAD),
|
|
||||||
"binhex" => GeneralPurpose::new(&alphabet::BIN_HEX, NO_PAD),
|
|
||||||
"crypt" => GeneralPurpose::new(&alphabet::CRYPT, NO_PAD),
|
|
||||||
"mutf7" => GeneralPurpose::new(&alphabet::IMAP_MUTF7, NO_PAD),
|
|
||||||
not_valid => return Value::error (
|
|
||||||
ShellError::GenericError {
|
|
||||||
error: "value is not an accepted character set".into(),
|
|
||||||
msg: format!(
|
|
||||||
"{not_valid} is not a valid character-set.\nPlease use `help encode base64` to see a list of valid character sets."
|
|
||||||
),
|
|
||||||
span: Some(config_character_set.span),
|
|
||||||
help: None,
|
|
||||||
inner: vec![],
|
|
||||||
}, config_character_set.span)
|
|
||||||
};
|
|
||||||
let value_span = input.span();
|
|
||||||
match input {
|
|
||||||
// Propagate existing errors.
|
|
||||||
Value::Error { .. } => input.clone(),
|
|
||||||
Value::Binary { val, .. } => match base64_config.action_type {
|
|
||||||
ActionType::Encode => {
|
|
||||||
let mut enc_vec = vec![0; val.len() * 4 / 3 + 4];
|
|
||||||
let bytes_written = match base64_engine.encode_slice(val, &mut enc_vec) {
|
|
||||||
Ok(bytes_written) => bytes_written,
|
|
||||||
Err(e) => {
|
|
||||||
return Value::error(
|
|
||||||
ShellError::GenericError {
|
|
||||||
error: "Error encoding data".into(),
|
|
||||||
msg: e.to_string(),
|
|
||||||
span: Some(value_span),
|
|
||||||
help: None,
|
|
||||||
inner: vec![],
|
|
||||||
},
|
|
||||||
value_span,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
enc_vec.truncate(bytes_written);
|
|
||||||
Value::string(std::str::from_utf8(&enc_vec).unwrap_or(""), command_span)
|
|
||||||
}
|
|
||||||
ActionType::Decode => Value::error(
|
|
||||||
ShellError::UnsupportedInput {
|
|
||||||
msg: "Binary data can only be encoded".to_string(),
|
|
||||||
input: "value originates from here".into(),
|
|
||||||
msg_span: command_span,
|
|
||||||
input_span: input.span(),
|
|
||||||
},
|
|
||||||
command_span,
|
|
||||||
),
|
|
||||||
},
|
|
||||||
Value::String { val, .. } => {
|
|
||||||
match base64_config.action_type {
|
|
||||||
ActionType::Encode => {
|
|
||||||
let mut enc_str = String::new();
|
|
||||||
base64_engine.encode_string(val, &mut enc_str);
|
|
||||||
Value::string(enc_str, command_span)
|
|
||||||
}
|
|
||||||
|
|
||||||
ActionType::Decode => {
|
|
||||||
// for decode, input val may contains invalid new line character, which is ok to omitted them by default.
|
|
||||||
let val = val.clone();
|
|
||||||
let val = val.replace("\r\n", "").replace('\n', "");
|
|
||||||
|
|
||||||
match base64_engine.decode(val) {
|
|
||||||
Ok(decoded_value) => {
|
|
||||||
if output_binary {
|
|
||||||
Value::binary(decoded_value, command_span)
|
|
||||||
} else {
|
|
||||||
match String::from_utf8(decoded_value) {
|
|
||||||
Ok(string_value) => Value::string(string_value, command_span),
|
|
||||||
Err(e) => Value::error(
|
|
||||||
ShellError::GenericError {
|
|
||||||
error: "base64 payload isn't a valid utf-8 sequence"
|
|
||||||
.into(),
|
|
||||||
msg: e.to_string(),
|
|
||||||
span: Some(value_span),
|
|
||||||
help: Some(
|
|
||||||
"consider using the `--binary` flag".to_owned(),
|
|
||||||
),
|
|
||||||
inner: vec![],
|
|
||||||
},
|
|
||||||
value_span,
|
|
||||||
),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(_) => Value::error(
|
|
||||||
ShellError::GenericError {
|
|
||||||
error: "value could not be base64 decoded".into(),
|
|
||||||
msg: format!(
|
|
||||||
"invalid base64 input for character set {}",
|
|
||||||
&config_character_set.item
|
|
||||||
),
|
|
||||||
span: Some(command_span),
|
|
||||||
help: None,
|
|
||||||
inner: vec![],
|
|
||||||
},
|
|
||||||
command_span,
|
|
||||||
),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
other => Value::error(
|
|
||||||
ShellError::TypeMismatch {
|
|
||||||
err_message: format!("string or binary, not {}", other.get_type()),
|
|
||||||
span: other.span(),
|
|
||||||
},
|
|
||||||
other.span(),
|
|
||||||
),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::{action, ActionType, Arguments, Base64Config};
|
|
||||||
use nu_protocol::{Span, Spanned, Value};
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn base64_encode_standard() {
|
|
||||||
let word = Value::test_string("Some Data Padding");
|
|
||||||
let expected = Value::test_string("U29tZSBEYXRhIFBhZGRpbmc=");
|
|
||||||
|
|
||||||
let actual = action(
|
|
||||||
&word,
|
|
||||||
&Arguments {
|
|
||||||
encoding_config: Base64Config {
|
|
||||||
character_set: Spanned {
|
|
||||||
item: "standard".to_string(),
|
|
||||||
span: Span::test_data(),
|
|
||||||
},
|
|
||||||
action_type: ActionType::Encode,
|
|
||||||
},
|
|
||||||
binary: true,
|
|
||||||
cell_paths: None,
|
|
||||||
},
|
|
||||||
Span::test_data(),
|
|
||||||
);
|
|
||||||
assert_eq!(actual, expected);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn base64_encode_standard_no_padding() {
|
|
||||||
let word = Value::test_string("Some Data Padding");
|
|
||||||
let expected = Value::test_string("U29tZSBEYXRhIFBhZGRpbmc");
|
|
||||||
|
|
||||||
let actual = action(
|
|
||||||
&word,
|
|
||||||
&Arguments {
|
|
||||||
encoding_config: Base64Config {
|
|
||||||
character_set: Spanned {
|
|
||||||
item: "standard-no-padding".to_string(),
|
|
||||||
span: Span::test_data(),
|
|
||||||
},
|
|
||||||
action_type: ActionType::Encode,
|
|
||||||
},
|
|
||||||
binary: true,
|
|
||||||
cell_paths: None,
|
|
||||||
},
|
|
||||||
Span::test_data(),
|
|
||||||
);
|
|
||||||
assert_eq!(actual, expected);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn base64_encode_url_safe() {
|
|
||||||
let word = Value::test_string("this is for url");
|
|
||||||
let expected = Value::test_string("dGhpcyBpcyBmb3IgdXJs");
|
|
||||||
|
|
||||||
let actual = action(
|
|
||||||
&word,
|
|
||||||
&Arguments {
|
|
||||||
encoding_config: Base64Config {
|
|
||||||
character_set: Spanned {
|
|
||||||
item: "url-safe".to_string(),
|
|
||||||
span: Span::test_data(),
|
|
||||||
},
|
|
||||||
action_type: ActionType::Encode,
|
|
||||||
},
|
|
||||||
binary: true,
|
|
||||||
cell_paths: None,
|
|
||||||
},
|
|
||||||
Span::test_data(),
|
|
||||||
);
|
|
||||||
assert_eq!(actual, expected);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn base64_decode_binhex() {
|
|
||||||
let word = Value::test_string(r#"B5"LD@jSCAJJG'9cG!"#);
|
|
||||||
let expected = Value::binary(b"a binhex test".as_slice(), Span::test_data());
|
|
||||||
|
|
||||||
let actual = action(
|
|
||||||
&word,
|
|
||||||
&Arguments {
|
|
||||||
encoding_config: Base64Config {
|
|
||||||
character_set: Spanned {
|
|
||||||
item: "binhex".to_string(),
|
|
||||||
span: Span::test_data(),
|
|
||||||
},
|
|
||||||
action_type: ActionType::Decode,
|
|
||||||
},
|
|
||||||
binary: true,
|
|
||||||
cell_paths: None,
|
|
||||||
},
|
|
||||||
Span::test_data(),
|
|
||||||
);
|
|
||||||
assert_eq!(actual, expected);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn base64_decode_binhex_with_new_line_input() {
|
|
||||||
let word = Value::test_string("B5\"LD@jSC\nAJJG'9cG!");
|
|
||||||
let expected = Value::binary(b"a binhex test".as_slice(), Span::test_data());
|
|
||||||
|
|
||||||
let actual = action(
|
|
||||||
&word,
|
|
||||||
&Arguments {
|
|
||||||
encoding_config: Base64Config {
|
|
||||||
character_set: Spanned {
|
|
||||||
item: "binhex".to_string(),
|
|
||||||
span: Span::test_data(),
|
|
||||||
},
|
|
||||||
action_type: ActionType::Decode,
|
|
||||||
},
|
|
||||||
binary: true,
|
|
||||||
cell_paths: None,
|
|
||||||
},
|
|
||||||
Span::test_data(),
|
|
||||||
);
|
|
||||||
assert_eq!(actual, expected);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn base64_encode_binary() {
|
|
||||||
let word = Value::binary(vec![77, 97, 110], Span::test_data());
|
|
||||||
let expected = Value::test_string("TWFu");
|
|
||||||
|
|
||||||
let actual = action(
|
|
||||||
&word,
|
|
||||||
&Arguments {
|
|
||||||
encoding_config: Base64Config {
|
|
||||||
character_set: Spanned {
|
|
||||||
item: "standard".to_string(),
|
|
||||||
span: Span::test_data(),
|
|
||||||
},
|
|
||||||
action_type: ActionType::Encode,
|
|
||||||
},
|
|
||||||
binary: true,
|
|
||||||
cell_paths: None,
|
|
||||||
},
|
|
||||||
Span::test_data(),
|
|
||||||
);
|
|
||||||
assert_eq!(actual, expected);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn base64_decode_binary_expect_error() {
|
|
||||||
let word = Value::binary(vec![77, 97, 110], Span::test_data());
|
|
||||||
|
|
||||||
let actual = action(
|
|
||||||
&word,
|
|
||||||
&Arguments {
|
|
||||||
encoding_config: Base64Config {
|
|
||||||
character_set: Spanned {
|
|
||||||
item: "standard".to_string(),
|
|
||||||
span: Span::test_data(),
|
|
||||||
},
|
|
||||||
action_type: ActionType::Decode,
|
|
||||||
},
|
|
||||||
binary: true,
|
|
||||||
cell_paths: None,
|
|
||||||
},
|
|
||||||
Span::test_data(),
|
|
||||||
);
|
|
||||||
|
|
||||||
match actual {
|
|
||||||
Value::Error { .. } => {}
|
|
||||||
_ => panic!("the result should be Value::Error"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,130 +0,0 @@
|
|||||||
use super::base64::{operate, ActionType, Base64CommandArguments, CHARACTER_SET_DESC};
|
|
||||||
use nu_engine::command_prelude::*;
|
|
||||||
use nu_protocol::report_shell_warning;
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct DecodeBase64Old;
|
|
||||||
|
|
||||||
impl Command for DecodeBase64Old {
|
|
||||||
fn name(&self) -> &str {
|
|
||||||
"decode base64"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn signature(&self) -> Signature {
|
|
||||||
Signature::build("decode base64")
|
|
||||||
.input_output_types(vec![
|
|
||||||
(Type::String, Type::Any),
|
|
||||||
(
|
|
||||||
Type::List(Box::new(Type::String)),
|
|
||||||
Type::List(Box::new(Type::Any)),
|
|
||||||
),
|
|
||||||
(Type::table(), Type::table()),
|
|
||||||
(Type::record(), Type::record()),
|
|
||||||
])
|
|
||||||
.allow_variants_without_examples(true)
|
|
||||||
.named(
|
|
||||||
"character-set",
|
|
||||||
SyntaxShape::String,
|
|
||||||
CHARACTER_SET_DESC,
|
|
||||||
Some('c'),
|
|
||||||
)
|
|
||||||
.switch(
|
|
||||||
"binary",
|
|
||||||
"Output a binary value instead of decoding payload as UTF-8",
|
|
||||||
Some('b'),
|
|
||||||
)
|
|
||||||
.rest(
|
|
||||||
"rest",
|
|
||||||
SyntaxShape::CellPath,
|
|
||||||
"For a data structure input, decode data at the given cell paths.",
|
|
||||||
)
|
|
||||||
.category(Category::Hash)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn description(&self) -> &str {
|
|
||||||
"Base64 decode a value."
|
|
||||||
}
|
|
||||||
|
|
||||||
fn extra_description(&self) -> &str {
|
|
||||||
r#"Will attempt to decode binary payload as an UTF-8 string by default. Use the `--binary(-b)` argument to force binary output."#
|
|
||||||
}
|
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
|
||||||
vec![
|
|
||||||
Example {
|
|
||||||
description: "Base64 decode a value and output as UTF-8 string",
|
|
||||||
example: "'U29tZSBEYXRh' | decode base64",
|
|
||||||
result: Some(Value::test_string("Some Data")),
|
|
||||||
},
|
|
||||||
Example {
|
|
||||||
description: "Base64 decode a value and output as binary",
|
|
||||||
example: "'U29tZSBEYXRh' | decode base64 --binary",
|
|
||||||
result: Some(Value::binary(
|
|
||||||
[0x53, 0x6f, 0x6d, 0x65, 0x20, 0x44, 0x61, 0x74, 0x61],
|
|
||||||
Span::test_data(),
|
|
||||||
)),
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_const(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(
|
|
||||||
&self,
|
|
||||||
engine_state: &EngineState,
|
|
||||||
stack: &mut Stack,
|
|
||||||
call: &Call,
|
|
||||||
input: PipelineData,
|
|
||||||
) -> Result<PipelineData, ShellError> {
|
|
||||||
report_shell_warning(
|
|
||||||
engine_state,
|
|
||||||
&ShellError::Deprecated {
|
|
||||||
old_command: "decode base64".into(),
|
|
||||||
new_suggestion: "the new `decode new-base64` version".into(),
|
|
||||||
span: call.head,
|
|
||||||
url: "`help decode new-base64`".into(),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
let character_set: Option<Spanned<String>> =
|
|
||||||
call.get_flag(engine_state, stack, "character-set")?;
|
|
||||||
let binary = call.has_flag(engine_state, stack, "binary")?;
|
|
||||||
let cell_paths: Vec<CellPath> = call.rest(engine_state, stack, 0)?;
|
|
||||||
let args = Base64CommandArguments {
|
|
||||||
action_type: ActionType::Decode,
|
|
||||||
binary,
|
|
||||||
character_set,
|
|
||||||
};
|
|
||||||
operate(engine_state, call, input, cell_paths, args)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_const(
|
|
||||||
&self,
|
|
||||||
working_set: &StateWorkingSet,
|
|
||||||
call: &Call,
|
|
||||||
input: PipelineData,
|
|
||||||
) -> Result<PipelineData, ShellError> {
|
|
||||||
let character_set: Option<Spanned<String>> =
|
|
||||||
call.get_flag_const(working_set, "character-set")?;
|
|
||||||
let binary = call.has_flag_const(working_set, "binary")?;
|
|
||||||
let cell_paths: Vec<CellPath> = call.rest_const(working_set, 0)?;
|
|
||||||
let args = Base64CommandArguments {
|
|
||||||
action_type: ActionType::Decode,
|
|
||||||
binary,
|
|
||||||
character_set,
|
|
||||||
};
|
|
||||||
operate(working_set.permanent(), call, input, cell_paths, args)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_examples() {
|
|
||||||
crate::test_examples(DecodeBase64Old)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,134 +0,0 @@
|
|||||||
use super::base64::{operate, ActionType, Base64CommandArguments, CHARACTER_SET_DESC};
|
|
||||||
use nu_engine::command_prelude::*;
|
|
||||||
use nu_protocol::report_shell_warning;
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct EncodeBase64Old;
|
|
||||||
|
|
||||||
impl Command for EncodeBase64Old {
|
|
||||||
fn name(&self) -> &str {
|
|
||||||
"encode base64"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn signature(&self) -> Signature {
|
|
||||||
Signature::build("encode base64")
|
|
||||||
.input_output_types(vec![
|
|
||||||
(Type::String, Type::String),
|
|
||||||
(Type::Binary, Type::String),
|
|
||||||
(
|
|
||||||
Type::List(Box::new(Type::String)),
|
|
||||||
Type::List(Box::new(Type::String)),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
Type::List(Box::new(Type::Binary)),
|
|
||||||
Type::List(Box::new(Type::String)),
|
|
||||||
),
|
|
||||||
// Relaxed for heterogeneous list.
|
|
||||||
// Should be removed as soon as the type system supports better restrictions
|
|
||||||
(
|
|
||||||
Type::List(Box::new(Type::Any)),
|
|
||||||
Type::List(Box::new(Type::String)),
|
|
||||||
),
|
|
||||||
(Type::table(), Type::table()),
|
|
||||||
(Type::record(), Type::record()),
|
|
||||||
])
|
|
||||||
.allow_variants_without_examples(true)
|
|
||||||
.named(
|
|
||||||
"character-set",
|
|
||||||
SyntaxShape::String,
|
|
||||||
CHARACTER_SET_DESC,
|
|
||||||
Some('c'),
|
|
||||||
)
|
|
||||||
.rest(
|
|
||||||
"rest",
|
|
||||||
SyntaxShape::CellPath,
|
|
||||||
"For a data structure input, encode data at the given cell paths.",
|
|
||||||
)
|
|
||||||
.category(Category::Hash)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn description(&self) -> &str {
|
|
||||||
"Encode a string or binary value using Base64."
|
|
||||||
}
|
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
|
||||||
vec![
|
|
||||||
Example {
|
|
||||||
description: "Encode binary data",
|
|
||||||
example: "0x[09 F9 11 02 9D 74 E3 5B D8 41 56 C5 63 56 88 C0] | encode base64",
|
|
||||||
result: Some(Value::test_string("CfkRAp1041vYQVbFY1aIwA==")),
|
|
||||||
},
|
|
||||||
Example {
|
|
||||||
description: "Encode a string with default settings",
|
|
||||||
example: "'Some Data' | encode base64",
|
|
||||||
result: Some(Value::test_string("U29tZSBEYXRh")),
|
|
||||||
},
|
|
||||||
Example {
|
|
||||||
description: "Encode a string with the binhex character set",
|
|
||||||
example: "'Some Data' | encode base64 --character-set binhex",
|
|
||||||
result: Some(Value::test_string(r#"8fpYC5"%BA4K"#)),
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_const(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(
|
|
||||||
&self,
|
|
||||||
engine_state: &EngineState,
|
|
||||||
stack: &mut Stack,
|
|
||||||
call: &Call,
|
|
||||||
input: PipelineData,
|
|
||||||
) -> Result<PipelineData, ShellError> {
|
|
||||||
report_shell_warning(
|
|
||||||
engine_state,
|
|
||||||
&ShellError::Deprecated {
|
|
||||||
old_command: "encode base64".into(),
|
|
||||||
new_suggestion: "the new `encode new-base64` version".into(),
|
|
||||||
span: call.head,
|
|
||||||
url: "`help encode new-base64`".into(),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
let character_set: Option<Spanned<String>> =
|
|
||||||
call.get_flag(engine_state, stack, "character-set")?;
|
|
||||||
let binary = call.has_flag(engine_state, stack, "binary")?;
|
|
||||||
let cell_paths: Vec<CellPath> = call.rest(engine_state, stack, 0)?;
|
|
||||||
let args = Base64CommandArguments {
|
|
||||||
action_type: ActionType::Encode,
|
|
||||||
binary,
|
|
||||||
character_set,
|
|
||||||
};
|
|
||||||
operate(engine_state, call, input, cell_paths, args)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_const(
|
|
||||||
&self,
|
|
||||||
working_set: &StateWorkingSet,
|
|
||||||
call: &Call,
|
|
||||||
input: PipelineData,
|
|
||||||
) -> Result<PipelineData, ShellError> {
|
|
||||||
let character_set: Option<Spanned<String>> =
|
|
||||||
call.get_flag_const(working_set, "character-set")?;
|
|
||||||
let binary = call.has_flag_const(working_set, "binary")?;
|
|
||||||
let cell_paths: Vec<CellPath> = call.rest_const(working_set, 0)?;
|
|
||||||
let args = Base64CommandArguments {
|
|
||||||
action_type: ActionType::Encode,
|
|
||||||
binary,
|
|
||||||
character_set,
|
|
||||||
};
|
|
||||||
operate(working_set.permanent(), call, input, cell_paths, args)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_examples() {
|
|
||||||
crate::test_examples(EncodeBase64Old)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,11 +1,6 @@
|
|||||||
mod base64;
|
|
||||||
mod decode;
|
mod decode;
|
||||||
mod decode_base64;
|
|
||||||
mod encode;
|
mod encode;
|
||||||
mod encode_base64;
|
|
||||||
mod encoding;
|
mod encoding;
|
||||||
|
|
||||||
pub use self::decode::Decode;
|
pub use self::decode::Decode;
|
||||||
pub use self::decode_base64::DecodeBase64Old;
|
|
||||||
pub use self::encode::Encode;
|
pub use self::encode::Encode;
|
||||||
pub use self::encode_base64::EncodeBase64Old;
|
|
||||||
|
@ -2,18 +2,18 @@ use nu_test_support::nu;
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn canonical() {
|
fn canonical() {
|
||||||
super::test_canonical("new-base64");
|
super::test_canonical("base64");
|
||||||
super::test_canonical("new-base64 --url");
|
super::test_canonical("base64 --url");
|
||||||
super::test_canonical("new-base64 --nopad");
|
super::test_canonical("base64 --nopad");
|
||||||
super::test_canonical("new-base64 --url --nopad");
|
super::test_canonical("base64 --url --nopad");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn const_() {
|
fn const_() {
|
||||||
super::test_const("new-base64");
|
super::test_const("base64");
|
||||||
super::test_const("new-base64 --url");
|
super::test_const("base64 --url");
|
||||||
super::test_const("new-base64 --nopad");
|
super::test_const("base64 --nopad");
|
||||||
super::test_const("new-base64 --url --nopad");
|
super::test_const("base64 --url --nopad");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -21,7 +21,7 @@ fn encode() {
|
|||||||
let text = "Ș̗͙̂̏o̲̲̗͗̌͊m̝̊̓́͂ë̡̦̞̤́̌̈́̀ ̥̝̪̎̿ͅf̧̪̻͉͗̈́̍̆u̮̝͌̈́ͅn̹̞̈́̊k̮͇̟͎̂͘y̧̲̠̾̆̕ͅ ̙͖̭͔̂̐t̞́́͘e̢̨͕̽x̥͋t͍̑̔͝";
|
let text = "Ș̗͙̂̏o̲̲̗͗̌͊m̝̊̓́͂ë̡̦̞̤́̌̈́̀ ̥̝̪̎̿ͅf̧̪̻͉͗̈́̍̆u̮̝͌̈́ͅn̹̞̈́̊k̮͇̟͎̂͘y̧̲̠̾̆̕ͅ ̙͖̭͔̂̐t̞́́͘e̢̨͕̽x̥͋t͍̑̔͝";
|
||||||
let encoded = "U8yCzI/MpsyXzZlvzZfMjM2KzLLMssyXbcyKzJPMgc2CzJ1lzYTMjM2EzIDMpsyhzJ7MpCDMjsy/zYXMpcydzKpmzZfNhMyNzIbMqsy7zKfNiXXNjM2EzK7Mnc2Fbs2EzIrMucyea82YzILMrs2HzJ/NjnnMvsyVzIbNhcyyzKfMoCDMgsyQzJnNlsytzZR0zIHNmMyBzJ5lzL3Mos2VzKh4zYvMpXTMkcyUzZ3NjQ==";
|
let encoded = "U8yCzI/MpsyXzZlvzZfMjM2KzLLMssyXbcyKzJPMgc2CzJ1lzYTMjM2EzIDMpsyhzJ7MpCDMjsy/zYXMpcydzKpmzZfNhMyNzIbMqsy7zKfNiXXNjM2EzK7Mnc2Fbs2EzIrMucyea82YzILMrs2HzJ/NjnnMvsyVzIbNhcyyzKfMoCDMgsyQzJnNlsytzZR0zIHNmMyBzJ5lzL3Mos2VzKh4zYvMpXTMkcyUzZ3NjQ==";
|
||||||
|
|
||||||
let outcome = nu!("'{}' | encode new-base64", text);
|
let outcome = nu!("'{}' | encode base64", text);
|
||||||
assert_eq!(outcome.out, encoded);
|
assert_eq!(outcome.out, encoded);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -30,7 +30,7 @@ fn decode_string() {
|
|||||||
let text = "Very important data";
|
let text = "Very important data";
|
||||||
let encoded = "VmVyeSBpbXBvcnRhbnQgZGF0YQ==";
|
let encoded = "VmVyeSBpbXBvcnRhbnQgZGF0YQ==";
|
||||||
|
|
||||||
let outcome = nu!("'{}' | decode new-base64 | decode", encoded);
|
let outcome = nu!("'{}' | decode base64 | decode", encoded);
|
||||||
assert_eq!(outcome.out, text);
|
assert_eq!(outcome.out, text);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,10 +40,10 @@ fn decode_pad_nopad() {
|
|||||||
let encoded_pad = "4oCdwqUuw6RAwrBiWsO2wqI=";
|
let encoded_pad = "4oCdwqUuw6RAwrBiWsO2wqI=";
|
||||||
let encoded_nopad = "4oCdwqUuw6RAwrBiWsO2wqI";
|
let encoded_nopad = "4oCdwqUuw6RAwrBiWsO2wqI";
|
||||||
|
|
||||||
let outcome = nu!("'{}' | decode new-base64 | decode", encoded_pad);
|
let outcome = nu!("'{}' | decode base64 | decode", encoded_pad);
|
||||||
assert_eq!(outcome.out, text);
|
assert_eq!(outcome.out, text);
|
||||||
|
|
||||||
let outcome = nu!("'{}' | decode new-base64 --nopad | decode", encoded_nopad);
|
let outcome = nu!("'{}' | decode base64 --nopad | decode", encoded_nopad);
|
||||||
assert_eq!(outcome.out, text);
|
assert_eq!(outcome.out, text);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,10 +53,10 @@ fn decode_url() {
|
|||||||
let encoded = "cDpn15jdvt+rdCs/";
|
let encoded = "cDpn15jdvt+rdCs/";
|
||||||
let encoded_url = "cDpn15jdvt-rdCs_";
|
let encoded_url = "cDpn15jdvt-rdCs_";
|
||||||
|
|
||||||
let outcome = nu!("'{}' | decode new-base64 | decode", encoded);
|
let outcome = nu!("'{}' | decode base64 | decode", encoded);
|
||||||
assert_eq!(outcome.out, text);
|
assert_eq!(outcome.out, text);
|
||||||
|
|
||||||
let outcome = nu!("'{}' | decode new-base64 --url | decode", encoded_url);
|
let outcome = nu!("'{}' | decode base64 --url | decode", encoded_url);
|
||||||
assert_eq!(outcome.out, text);
|
assert_eq!(outcome.out, text);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,9 +65,9 @@ fn reject_pad_nopad() {
|
|||||||
let encoded_nopad = "YQ";
|
let encoded_nopad = "YQ";
|
||||||
let encoded_pad = "YQ==";
|
let encoded_pad = "YQ==";
|
||||||
|
|
||||||
let outcome = nu!("'{}' | decode new-base64", encoded_nopad);
|
let outcome = nu!("'{}' | decode base64", encoded_nopad);
|
||||||
assert!(!outcome.err.is_empty());
|
assert!(!outcome.err.is_empty());
|
||||||
|
|
||||||
let outcome = nu!("'{}' | decode new-base64 --nopad", encoded_pad);
|
let outcome = nu!("'{}' | decode base64 --nopad", encoded_pad);
|
||||||
assert!(!outcome.err.is_empty())
|
assert!(!outcome.err.is_empty())
|
||||||
}
|
}
|
||||||
|
@ -10,43 +10,48 @@ fn base64_defaults_to_encoding_with_standard_character_type() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn base64_encode_characterset_binhex() {
|
fn base64_defaults_to_encoding_with_nopad() {
|
||||||
let actual = nu!(r#"
|
let actual = nu!(r#"
|
||||||
echo 'username:password' | encode base64 --character-set binhex
|
echo 'username:password' | encode base64 --nopad
|
||||||
"#);
|
"#);
|
||||||
|
|
||||||
assert_eq!(actual.out, "GA0PFQjKE@8kF'&cFhG[FQ3");
|
assert_eq!(actual.out, "dXNlcm5hbWU6cGFzc3dvcmQ");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn error_when_invalid_character_set_given() {
|
fn base64_decode_value() {
|
||||||
let actual = nu!(r#"
|
let actual = nu!(r#"
|
||||||
echo 'username:password' | encode base64 --character-set 'this is invalid'
|
echo 'YWJjeHl6' | decode base64 | decode
|
||||||
"#);
|
"#);
|
||||||
|
|
||||||
assert!(actual
|
assert_eq!(actual.out, "abcxyz");
|
||||||
.err
|
|
||||||
.contains("this is invalid is not a valid character-set"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn base64_decode_characterset_binhex() {
|
fn base64_decode_with_nopad() {
|
||||||
let actual = nu!(
|
let actual = nu!(r#"
|
||||||
r#""GA0PFQjKE@8kF'&cFhG[FQ3" | decode base64 --character-set binhex --binary | decode utf-8"#
|
echo 'R29vZCBsdWNrIHRvIHlvdQ' | decode base64 --nopad | decode
|
||||||
);
|
"#);
|
||||||
|
|
||||||
assert_eq!(actual.out, "username:password");
|
assert_eq!(actual.out, "Good luck to you");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn base64_decode_with_url() {
|
||||||
|
let actual = nu!(r#"
|
||||||
|
echo 'vu7_' | decode base64 --url | decode
|
||||||
|
"#);
|
||||||
|
|
||||||
|
assert_eq!(actual.out, "¾îÿ");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn error_invalid_decode_value() {
|
fn error_invalid_decode_value() {
|
||||||
let actual = nu!(r#"
|
let actual = nu!(r#"
|
||||||
echo "this should not be a valid encoded value" | decode base64 --character-set url-safe
|
echo "this should not be a valid encoded value" | decode base64
|
||||||
"#);
|
"#);
|
||||||
|
|
||||||
assert!(actual
|
assert!(actual.err.contains("nu::shell::incorrect_value"));
|
||||||
.err
|
|
||||||
.contains("invalid base64 input for character set url-safe"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user