diff --git a/extensions/crypto/Cargo.toml b/extensions/crypto/Cargo.toml index 9cd714156..84bd10efc 100644 --- a/extensions/crypto/Cargo.toml +++ b/extensions/crypto/Cargo.toml @@ -13,9 +13,13 @@ crate-type = ["cdylib", "lib"] static= [ "limbo_ext/static" ] [dependencies] +ascii85 = "0.2.1" blake3 = "1.5.5" +data-encoding = "2.7.0" limbo_ext = { path = "../core", features = ["static"] } +md5 = "0.7.0" ring = "0.17.8" +urlencoding = "2.1.3" [target.'cfg(not(target_family = "wasm"))'.dependencies] mimalloc = { version = "*", default-features = false } diff --git a/extensions/crypto/src/crypto.rs b/extensions/crypto/src/crypto.rs index 472b8dac1..654307bd4 100644 --- a/extensions/crypto/src/crypto.rs +++ b/extensions/crypto/src/crypto.rs @@ -1,5 +1,6 @@ use crate::Error; use blake3::Hasher; +use data_encoding::{BASE32, BASE64, HEXLOWER}; use limbo_ext::{Value, ValueType}; use ring::digest::{self, digest}; @@ -53,3 +54,38 @@ pub fn sha1(data: &Value) -> Result, Error> { } } } + +pub fn md5(data: &Value) -> Result, Error> { + match data.value_type() { + ValueType::Error | ValueType::Null => Err(Error::InvalidType), + _ => { + let digest = md5::compute::<&Vec>(data.as_bytes().as_ref()); + + Ok(digest.as_ref().to_vec()) + } + } +} + +pub fn encode(data: &Value, format: &Value) -> Result { + match (data.value_type(), format.value_type()) { + (ValueType::Error, _) | (ValueType::Null, _) => Err(Error::InvalidType), + (_, ValueType::Text) => match format.to_text().unwrap().to_lowercase().as_str() { + "base32" => Ok(Value::from_text(BASE32.encode(data.as_bytes().as_ref()))), + "base64" => Ok(Value::from_text(BASE64.encode(data.as_bytes().as_ref()))), + "hex" => Ok(Value::from_text(HEXLOWER.encode(data.as_bytes().as_ref()))), + "base85" => { + let result = ascii85::encode(data.as_bytes().as_ref()) + .replace("<~", "") + .replace("~>", ""); + Ok(Value::from_text(result)) + } + "url" => { + let data = data.as_bytes(); + let url = urlencoding::encode_binary(&data); + Ok(Value::from_text(url.to_string())) + } + _ => Err(Error::UnknownOperation), + }, + _ => Err(Error::InvalidType), + } +} diff --git a/extensions/crypto/src/lib.rs b/extensions/crypto/src/lib.rs index 49f6d3e9b..09fe28c38 100644 --- a/extensions/crypto/src/lib.rs +++ b/extensions/crypto/src/lib.rs @@ -1,4 +1,4 @@ -use crypto::{blake3, sha1, sha256, sha384, sha512}; +use crypto::{blake3, encode, md5, sha1, sha256, sha384, sha512}; use limbo_ext::{register_extension, scalar, ResultCode, Value}; mod crypto; @@ -6,6 +6,7 @@ mod crypto; #[derive(Debug)] enum Error { InvalidType, + UnknownOperation, } #[scalar(name = "crypto_sha256", alias = "crypto_sha256")] @@ -73,6 +74,32 @@ fn crypto_sha1(args: &[Value]) -> Value { Value::from_blob(hash) } -register_extension! { - scalars: { crypto_sha256, crypto_sha512, crypto_sha384, crypto_blake3, crypto_sha1 }, +#[scalar(name = "crypto_md5", alias = "crypto_md5")] +fn crypto_md5(args: &[Value]) -> Value { + if args.len() != 1 { + return Value::error(ResultCode::Error); + } + + let Ok(hash) = md5(&args[0]) else { + return Value::error(ResultCode::Error); + }; + + Value::from_blob(hash) +} + +#[scalar(name = "crypto_encode", alias = "crypto_encode")] +fn crypto_encode(args: &[Value]) -> Value { + if args.len() != 2 { + return Value::error(ResultCode::Error); + } + + let Ok(payload) = encode(&args[0], &args[1]) else { + return Value::error(ResultCode::Error); + }; + + payload +} + +register_extension! { + scalars: { crypto_sha256, crypto_sha512, crypto_sha384, crypto_blake3, crypto_sha1, crypto_md5, crypto_encode }, }