107 lines
3.6 KiB
Rust
107 lines
3.6 KiB
Rust
use std::{error::Error, fs::File, io::{Cursor, Read, Seek, Write}, path::{Path, PathBuf}};
|
|
|
|
use zip::{write::SimpleFileOptions, CompressionMethod, ZipWriter};
|
|
|
|
fn find_subsequence(haystack: &[u8], needle: &[u8]) -> Vec<usize> {
|
|
haystack.windows(needle.len())
|
|
.enumerate()
|
|
.filter_map(|(i, arr)| if arr == needle { Some(i) } else { None })
|
|
.collect()
|
|
}
|
|
|
|
fn recursively_find_classes(path: PathBuf) -> Vec<PathBuf> {
|
|
let e = std::fs::read_dir(path).unwrap();
|
|
let mut classes = Vec::new();
|
|
for entry in e {
|
|
if let Ok(entry) = entry {
|
|
match entry.metadata().unwrap().is_dir() {
|
|
true => classes.append(&mut recursively_find_classes(entry.path())),
|
|
false => {
|
|
if entry.file_name().to_str().unwrap().ends_with(".class") {
|
|
classes.push(entry.path());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
classes
|
|
}
|
|
|
|
// patch_jar(r#"D:\Documents\RustroverProjects\XCraft\xcraft\libraries\com\mojang\authlib\1.5.22\authlib-1.5.22__.jar"#, "authlib_patched.jar", "http://localhost:8999/api/")
|
|
|
|
pub fn patch_jar(input_jar: &str, output_jar: &str, endpoint: &str) -> Result<(), Box<dyn Error + Sync + Send>> {
|
|
let mut target_dir = PathBuf::new();
|
|
target_dir.push("out");
|
|
|
|
let archive = std::fs::read(input_jar)?;
|
|
|
|
zip_extract::extract(Cursor::new(archive), &target_dir, true)?;
|
|
|
|
let needle = b"https://sessionserver.mojang.com/session/minecraft/";
|
|
let replacement = endpoint.as_bytes();
|
|
|
|
for path in recursively_find_classes(PathBuf::from(".\\out")) {
|
|
let mut haystack = std::fs::read(&path).unwrap();
|
|
let mut v = find_subsequence(&haystack, needle);
|
|
if v.is_empty() { continue; }
|
|
while let Some(g) = v.first() {
|
|
let (a,b) = haystack.split_at(*g);
|
|
let l = a[a.len()-1];
|
|
let mut a = a[..a.len()-1].to_vec();
|
|
a.push( if l as usize > needle.len() { (replacement.len() + (l as usize - needle.len())) as u8 } else { replacement.len() as u8 });
|
|
a.append(&mut replacement.to_vec());
|
|
a.append(&mut b[needle.len()..].to_vec());
|
|
haystack = a;
|
|
v = find_subsequence(&haystack, needle);
|
|
}
|
|
|
|
std::fs::write(path, haystack)?;
|
|
}
|
|
|
|
let jar = File::create(output_jar)?;
|
|
|
|
zip_dir(&target_dir, &target_dir, jar)?;
|
|
|
|
std::fs::remove_dir_all(&target_dir)?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
|
|
fn zip_dir<T: Write + Seek>(
|
|
src_dir: &Path,
|
|
prefix: &Path,
|
|
writer: T,
|
|
) -> zip::result::ZipResult<()> {
|
|
let mut zip = ZipWriter::new(writer);
|
|
|
|
let file_options = SimpleFileOptions::default()
|
|
.compression_method(CompressionMethod::Deflated)
|
|
.unix_permissions(0o644); // Simulating a DOS file attribute
|
|
|
|
let dir_options = SimpleFileOptions::default()
|
|
.compression_method(CompressionMethod::Deflated)
|
|
.unix_permissions(0o755);
|
|
|
|
let mut buffer = Vec::new();
|
|
|
|
for entry in walkdir::WalkDir::new(src_dir).same_file_system(true).min_depth(1) {
|
|
let entry = entry.unwrap();
|
|
let path = entry.path();
|
|
let name = path.strip_prefix(prefix).unwrap();
|
|
let dos_path = name.to_string_lossy().replace("/", "\\");
|
|
if path.is_file() {
|
|
let mut f = File::open(path)?;
|
|
f.read_to_end(&mut buffer)?;
|
|
|
|
zip.start_file(dos_path, file_options)?;
|
|
zip.write_all(&buffer)?;
|
|
buffer.clear();
|
|
} else if path.is_dir() {
|
|
zip.add_directory(dos_path, dir_options)?;
|
|
}
|
|
}
|
|
zip.finish()?;
|
|
Ok(())
|
|
}
|