its working, gonna try bashing the commands
This commit is contained in:
commit
9ff5d4b44f
4 changed files with 194 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
/target
|
7
Cargo.lock
generated
Normal file
7
Cargo.lock
generated
Normal file
|
@ -0,0 +1,7 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "injector"
|
||||
version = "0.1.0"
|
8
Cargo.toml
Normal file
8
Cargo.toml
Normal file
|
@ -0,0 +1,8 @@
|
|||
[package]
|
||||
name = "injector"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
178
src/main.rs
Normal file
178
src/main.rs
Normal file
|
@ -0,0 +1,178 @@
|
|||
use std::str::from_utf8_unchecked;
|
||||
use std::{str::from_utf8, process::Command};
|
||||
use std::fs::{self, File, OpenOptions};
|
||||
use std::io::{Read, Write, Seek, SeekFrom};
|
||||
use std::ffi::OsString;
|
||||
use std::path::Path;
|
||||
#[derive(Debug)]
|
||||
struct Ops {
|
||||
folder: Option<String>,
|
||||
output: Option<String>,
|
||||
recursive: bool,
|
||||
|
||||
}
|
||||
|
||||
// Father please forgive me for the sins im about to commit
|
||||
static mut HOME_DIR: String = String::new();
|
||||
|
||||
fn main() {
|
||||
let ops = read_ops();
|
||||
println!("{:?}", ops);
|
||||
if ops.folder.is_none() || ops.output.is_none() {
|
||||
panic!("missing folder/output!");
|
||||
}
|
||||
unsafe { HOME_DIR = ops.folder.clone().unwrap(); }
|
||||
inject_folder(&ops.folder.unwrap(), &ops.output.unwrap(), ops.recursive);
|
||||
}
|
||||
|
||||
fn inject_folder(folder: &str, output: &str, rec: bool) {
|
||||
// Create the directory just in case
|
||||
let _ = fs::create_dir_all(output);
|
||||
|
||||
let f = fs::read_dir(folder).expect(&format!("Couldn't open folder {}", folder));
|
||||
for i in f.filter(|x| x.is_ok()).map(|x| x.unwrap()) {
|
||||
if i.file_name().to_str().unwrap().starts_with('.') {
|
||||
continue; // Invis folder/file, we dont want to copy them
|
||||
}
|
||||
let pbuf = i.path();
|
||||
let p = pbuf.as_path();
|
||||
if p.is_file() {
|
||||
let op = String::from_iter([output, "/", i.file_name().to_str().unwrap()]);
|
||||
inject_file(&p, &Path::new(&op));
|
||||
}
|
||||
else if rec && p.is_dir() {
|
||||
let fol = p.as_os_str().to_str().unwrap();
|
||||
let out = String::from_iter([output, "/", i.file_name().to_str().unwrap()]);
|
||||
inject_folder(fol, &out, rec);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn inject_file(file: &Path, output: &Path) {
|
||||
println!("injecting {:?} to {:?}", file, output);
|
||||
let mut inp = OpenOptions::new().read(true).open(file).expect(&format!("Cannot open {:?}", file.as_os_str()));
|
||||
let mut out = File::create(output).expect(&format!("Cannot create file {:?}", output.as_os_str()));
|
||||
let mut buf: [u8; 2048] = [0; 2048];
|
||||
|
||||
|
||||
if file.extension().unwrap_or(&OsString::new()) == "html" {
|
||||
// Copy while also reading and searching for <INJECT> ... </INJECT>
|
||||
while let Ok(len) = inp.read(&mut buf) {
|
||||
if len == 0 {
|
||||
// EOF
|
||||
break;
|
||||
}
|
||||
match from_utf8(&buf[..len]) {
|
||||
Ok(s) => {
|
||||
write_injection(s, &mut out, &mut inp, file.parent().unwrap().as_os_str().to_str().unwrap());
|
||||
},
|
||||
Err(e) => {
|
||||
if e.valid_up_to() == 0 {
|
||||
panic!("File is not valid UTF8");
|
||||
}
|
||||
// Safety: we know all bytes are valid from the error...
|
||||
let s = unsafe { from_utf8_unchecked(&buf[..e.valid_up_to()]) };
|
||||
inp.seek(SeekFrom::Current(-1 * (len - e.valid_up_to()) as i64)).unwrap();
|
||||
|
||||
write_injection(s, &mut out, &mut inp, file.parent().unwrap().as_os_str().to_str().unwrap());
|
||||
},
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Just copy the file!
|
||||
while let Ok(len) = inp.read(&mut buf) {
|
||||
if len == 0 {
|
||||
// EOF
|
||||
break;
|
||||
}
|
||||
let res = out.write(&buf[..len]);
|
||||
if res.is_err() {
|
||||
panic!("Cannot write to {:?}", output.as_os_str());
|
||||
}
|
||||
else if res.unwrap() != len {
|
||||
panic!("cannot continue writing to {:?}", output.as_os_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
out.flush().expect(&format!("Cannot flush file {:?}", output.as_os_str()));
|
||||
}
|
||||
|
||||
fn write_injection(s: &str, out: &mut File, inp: &mut File, cfolder: &str) {
|
||||
let tag : &str = "<INJECT>";
|
||||
let ctag : &str = "</INJECT>";
|
||||
|
||||
if s.contains(tag) && s.contains(ctag) {
|
||||
let (pre,post) = s.split_once(tag).unwrap();
|
||||
let (com, post) = post.split_once(ctag).unwrap();
|
||||
|
||||
out.write(pre.as_bytes()).unwrap();
|
||||
|
||||
let mut com_iter = com.split(' ');
|
||||
let com = Command::new(com_iter.next().unwrap())
|
||||
.args(
|
||||
com_iter.map(|x| x
|
||||
.replace("$HOME", unsafe { &HOME_DIR })
|
||||
.replace("$CURRENT", cfolder)
|
||||
)
|
||||
)
|
||||
.output();
|
||||
|
||||
let com = match com {
|
||||
Ok(o) => String::from_utf8(o.stdout).unwrap_or(String::from("UTF8 conversion error")),
|
||||
Err(_) => String::from("Failed running command :("),
|
||||
};
|
||||
|
||||
out.write(com.as_bytes()).unwrap();
|
||||
write_injection(post, out, inp, cfolder);
|
||||
}
|
||||
else if s.contains(tag) {
|
||||
// We have the first tag but not the second, so we want to go back in the input file..
|
||||
let (copy, keep) = s.split_once(tag).unwrap();
|
||||
|
||||
out.write(copy.as_bytes()).unwrap();
|
||||
// Return the length of whatever we just read and the tag length
|
||||
inp.seek(SeekFrom::Current(-1 * (keep.as_bytes().len() + tag.as_bytes().len()) as i64)).unwrap();
|
||||
}
|
||||
else {
|
||||
// Make sure we are not just cutting it in the middle
|
||||
let chars = tag.chars().collect::<Vec<_>>();
|
||||
let mut wrote = false;
|
||||
for i in 1..chars.len() {
|
||||
if s.ends_with(&chars[..i]) {
|
||||
let back: usize = chars[..i].iter().map(|x| x.len_utf8()).sum();
|
||||
let to_write = s.replace(&chars[..i], "");
|
||||
out.write(to_write.as_bytes()).unwrap();
|
||||
|
||||
inp.seek(SeekFrom::Current(-1 * back as i64)).unwrap();
|
||||
wrote = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if !wrote {
|
||||
out.write(s.as_bytes()).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn read_ops() -> Ops {
|
||||
let args = std::env::args();
|
||||
let mut ops = Ops { folder: None, output: None, recursive: false };
|
||||
|
||||
for a in args.skip(1) {
|
||||
if a.starts_with('-') {
|
||||
if a.trim() == "-r" || a.trim() == "--recursive" {
|
||||
ops.recursive = true;
|
||||
}
|
||||
}
|
||||
else if ops.folder.is_none() {
|
||||
ops.folder = Some(a);
|
||||
}
|
||||
else if ops.output.is_none() {
|
||||
ops.output = Some(a);
|
||||
}
|
||||
}
|
||||
|
||||
ops
|
||||
}
|
Loading…
Reference in a new issue