Skip to content

Commit 3d7ecc3

Browse files
committed
Move encoding/decoding functions to hexora_io
1 parent d4fae24 commit 3d7ecc3

File tree

5 files changed

+53
-53
lines changed

5 files changed

+53
-53
lines changed

Cargo.lock

Lines changed: 7 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/hexora/Cargo.toml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ path = "src/main.rs"
3030
[dependencies]
3131
ruff_python_ast = { git = "https://github.com/astral-sh/ruff", rev="3f63ea4b504d50eaf3c479de68e4017d2434a160" }
3232
ruff_python_parser = { git = "https://github.com/astral-sh/ruff", rev="3f63ea4b504d50eaf3c479de68e4017d2434a160" }
33-
ruff_source_file = { git = "https://github.com/astral-sh/ruff/", rev="3f63ea4b504d50eaf3c479de68e4017d2434a160"}
3433
ruff_python_stdlib = { git = "https://github.com/astral-sh/ruff/", rev="3f63ea4b504d50eaf3c479de68e4017d2434a160" }
3534
ruff_text_size = { git = "https://github.com/astral-sh/ruff/", rev="3f63ea4b504d50eaf3c479de68e4017d2434a160" }
3635

@@ -49,8 +48,6 @@ strum_macros = "0.27.0"
4948
serde_json = "1.0.113"
5049
pythonize = "0.26.0"
5150
sha2 = "0.11.0-rc.2"
52-
encoding_rs = "0.8.35"
53-
base64 = "0.22.1"
5451
hexora_io = { path = "../hexora_io" }
5552

5653
[dev-dependencies]

crates/hexora/src/indexer/strings/transformer.rs

Lines changed: 5 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
use crate::indexer::model::Transformation;
22
use crate::indexer::node_transformer::NodeTransformer;
33
use crate::indexer::taint::TaintState;
4-
use base64::{Engine as _, engine::general_purpose};
5-
use hexora_io::encoding::{decode_bytes, unescape_to_bytes};
4+
use hexora_io::encoding::{
5+
base64_decode, bytes_to_escaped, decode_bytes, hex_to_escaped, unescape_to_bytes,
6+
};
67
use ruff_python_ast::{
78
self as ast, AtomicNodeIndex, ExprContext, HasNodeIndex, NodeIndex, Operator,
89
StringLiteralFlags,
@@ -204,9 +205,7 @@ impl<'a> NodeTransformer<'a> {
204205

205206
let arg_str = self.extract_string(&call.arguments.args[0])?;
206207
if name == "a2b_base64" {
207-
let bytes = general_purpose::STANDARD
208-
.decode(arg_str.trim().as_bytes())
209-
.ok()?;
208+
let bytes = base64_decode(&arg_str, false)?;
210209
return Some(self.make_string_expr(
211210
call.range,
212211
bytes_to_escaped(&bytes),
@@ -260,12 +259,7 @@ impl<'a> NodeTransformer<'a> {
260259
}
261260

262261
let arg_str = self.extract_string(&call.arguments.args[0])?;
263-
let bytes_arg = arg_str.trim().as_bytes();
264-
let bytes = if name == "urlsafe_b64decode" {
265-
general_purpose::URL_SAFE.decode(bytes_arg).ok()?
266-
} else {
267-
general_purpose::STANDARD.decode(bytes_arg).ok()?
268-
};
262+
let bytes = base64_decode(&arg_str, name == "urlsafe_b64decode")?;
269263

270264
let escaped = bytes_to_escaped(&bytes);
271265
Some(self.make_string_expr(call.range, escaped, Some(Transformation::Base64)))
@@ -378,33 +372,3 @@ impl<'a> NodeTransformer<'a> {
378372
}
379373
}
380374
}
381-
382-
#[inline]
383-
pub(crate) fn bytes_to_escaped(bytes: &[u8]) -> String {
384-
bytes.iter().map(|b| format!("\\x{:02x}", b)).collect()
385-
}
386-
387-
#[inline]
388-
pub(crate) fn hex_to_escaped(input: &str) -> Option<String> {
389-
let filtered: String = input.chars().filter(|c| !c.is_ascii_whitespace()).collect();
390-
if filtered.is_empty() || !filtered.len().is_multiple_of(2) {
391-
return None;
392-
}
393-
filtered
394-
.as_bytes()
395-
.chunks(2)
396-
.map(|chunk| {
397-
let h = chunk[0] as char;
398-
let l = chunk[1] as char;
399-
if h.is_ascii_hexdigit() && l.is_ascii_hexdigit() {
400-
Some(format!(
401-
"\\x{}{}",
402-
h.to_ascii_lowercase(),
403-
l.to_ascii_lowercase()
404-
))
405-
} else {
406-
None
407-
}
408-
})
409-
.collect()
410-
}

crates/hexora_io/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ tar = "0.4"
1111
flate2 = "1.0"
1212
encoding_rs = "0.8.35"
1313
once_cell = "1.21.3"
14+
base64 = "0.22.1"
1415
ruff_source_file = { git = "https://github.com/astral-sh/ruff/", rev="3f63ea4b504d50eaf3c479de68e4017d2434a160"}
1516
ruff_text_size = { git = "https://github.com/astral-sh/ruff/", rev="3f63ea4b504d50eaf3c479de68e4017d2434a160" }
1617

crates/hexora_io/src/encoding.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use base64::{Engine as _, engine::general_purpose};
12
use encoding_rs;
23
use once_cell::sync::Lazy;
34
use std::collections::HashMap;
@@ -298,6 +299,45 @@ pub fn unescape_to_bytes(input: &str) -> Option<Vec<u8>> {
298299
Some(bytes)
299300
}
300301

302+
#[inline]
303+
pub fn bytes_to_escaped(bytes: &[u8]) -> String {
304+
bytes.iter().map(|b| format!("\\x{:02x}", b)).collect()
305+
}
306+
307+
#[inline]
308+
pub fn hex_to_escaped(input: &str) -> Option<String> {
309+
let filtered: String = input.chars().filter(|c| !c.is_ascii_whitespace()).collect();
310+
if filtered.is_empty() || filtered.len() % 2 != 0 {
311+
return None;
312+
}
313+
filtered
314+
.as_bytes()
315+
.chunks(2)
316+
.map(|chunk| {
317+
let h = chunk[0] as char;
318+
let l = chunk[1] as char;
319+
if h.is_ascii_hexdigit() && l.is_ascii_hexdigit() {
320+
Some(format!(
321+
"\\x{}{}",
322+
h.to_ascii_lowercase(),
323+
l.to_ascii_lowercase()
324+
))
325+
} else {
326+
None
327+
}
328+
})
329+
.collect()
330+
}
331+
332+
pub fn base64_decode(input: &str, url_safe: bool) -> Option<Vec<u8>> {
333+
let input = input.trim();
334+
if url_safe {
335+
general_purpose::URL_SAFE.decode(input).ok()
336+
} else {
337+
general_purpose::STANDARD.decode(input).ok()
338+
}
339+
}
340+
301341
#[cfg(test)]
302342
mod tests {
303343
use super::*;

0 commit comments

Comments
 (0)