tundlebool/src/omori_locator.rs
2025-04-15 18:08:34 +02:00

115 lines
3.8 KiB
Rust

use anyhow::Context;
use regex::bytes::Regex;
use sha2::Digest;
use std::{fs::File, io::Read, path::PathBuf};
#[cfg(any(target_os = "linux", target_os = "macos"))]
fn get_steam_root() -> anyhow::Result<PathBuf> {
let mut base = dirs::home_dir().with_context(|| "Couldn't figure out your home directory")?;
#[cfg(target_os="linux")]
base.push(".steam/root");
#[cfg(target_os="macos")]
base.push("Library/Application Support/Steam");
Ok(base)
}
#[cfg(target_os = "windows")]
fn get_steam_root() -> anyhow::Result<PathBuf> {
use registry::{self, Security, Data};
let key = registry::Hive::LocalMachine.open(r"SOFTWARE\Wow6432Node\Valve\Steam", Security::Read)?;
let value = match key.value("InstallPath")? {
Data::String(s) => Some(s.to_string_lossy()),
Data::ExpandString(s) => Some(s.to_string_lossy()),
_ => None
}.with_context(|| "Couldn't read the steam install path from registry")?;
let mut base = PathBuf::from(value);
Ok(base)
}
pub fn get_omori_path() -> anyhow::Result<PathBuf> {
let mut base = get_steam_root()?;
base.push("steamapps/libraryfolders.vdf");
let mut buffer = Vec::new();
let mut fd = File::open(base)?;
fd.read_to_end(&mut buffer)?;
let data = String::from_utf8(buffer)?;
let data = keyvalues_parser::Vdf::parse(&data.as_str())?;
let data = data.value.get_obj().with_context(|| "Couldn't get the steam library libraryfolders object.")?;
let keys = data.keys();
let mut omori_path: Option<PathBuf> = None;
for key in keys {
println!("{:?}", key);
let entry = data.get(key).with_context(|| "Couldn't read specific steam library libraryfolders object.")?;
let entry = entry.get(0).with_context(|| "Couldn't read specific steam library libraryfolders object.")?;
let entry = entry.get_obj().with_context(|| "libraryfolders parsing failed: Not an object")?;
let apps = entry.get("apps").with_context(|| "libraryfolders parsing failed: No apps")?;
let apps = apps.get(0).with_context(|| "libraryfolders parsing failed: No apps")?;
let apps = apps.get_obj().with_context(|| "libraryfolders parsing failed: No apps")?;
let apps: Vec<_> = apps.keys().collect();
let path = entry.get("path").with_context(|| "libraryfolders parsing failed: No path")?;
let path = path.get(0).with_context(|| "libraryfolders parsing failed: No path")?;
let path = path.get_str().with_context(|| "libraryfolders parsing failed: No path")?;
if apps.iter().find(|x| (**x).eq("1150690")).is_some() {
let mut base = PathBuf::from(path);
#[cfg(not(target_os = "macos"))]
base.push("steamapps/common/OMORI/www");
#[cfg(target_os = "macos")]
base.push("steamapps/common/OMORI/OMORI.app/Contents/Resources/app.nw");
omori_path = Some(base);
}
}
omori_path.with_context(|| "Failed to find omori")
}
const GAME_KEY_HASH: &[u8; 32] = include_bytes!("keyhash");
pub fn get_omori_key() -> anyhow::Result<Vec<u8>> {
let mut base: PathBuf = get_steam_root()?;
base.push("appcache/appinfo.vdf");
let mut buffer = Vec::new();
let mut fd = File::open(base)?;
fd.read_to_end(&mut buffer)?;
drop(fd);
let re = Regex::new(r"--([0-9a-f]{32})")?;
for (_, [key]) in re.captures_iter(&buffer).map(|c| c.extract()) {
let hash = sha2::Sha256::digest(key);
let mut equal = true;
for i in 0..32 {
if hash[i] != GAME_KEY_HASH[i] {
equal = false;
}
}
if equal {
return Ok(key.to_vec())
}
}
Err(anyhow::anyhow!("Couldn't find any valid decryption key for OMORI in your Steam installation."))
}