mirror of
https://github.com/ivabus/binhost
synced 2024-11-09 17:55:17 +03:00
0.3.3: Ununsafe binhost (server) and update deps
Signed-off-by: Ivan Bushchik <ivabus@ivabus.dev>
This commit is contained in:
parent
debff608d2
commit
652196c247
|
@ -1,19 +1,20 @@
|
|||
|
||||
[package]
|
||||
name = "binhost"
|
||||
version = "0.3.2"
|
||||
version = "0.3.3"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
repository = "https://github.com/ivabus/binhost"
|
||||
description = "HTTP server to easily serve files"
|
||||
|
||||
[dependencies]
|
||||
clap = { version = "4.4.18", features = ["derive"] }
|
||||
clap = { version = "4.5.3", features = ["derive"] }
|
||||
rocket = "0.5.0"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
sha2 = { version = "0.10" }
|
||||
ed25519-compact = { version = "2.0.6", default-features = false, features = [
|
||||
ed25519-compact = { version = "2.1.1", default-features = false, features = [
|
||||
"random",
|
||||
"self-verify",
|
||||
"std",
|
||||
] }
|
||||
once_cell = "1.19"
|
||||
|
|
207
src/main.rs
207
src/main.rs
|
@ -1,5 +1,7 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#![forbid(unsafe_code)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate rocket;
|
||||
|
||||
|
@ -8,10 +10,12 @@ use std::time::Instant;
|
|||
|
||||
use clap::Parser;
|
||||
use ed25519_compact::{KeyPair, Noise};
|
||||
use once_cell::sync::Lazy;
|
||||
use rocket::figment::Figment;
|
||||
use rocket::fs::{FileServer, NamedFile};
|
||||
use rocket::http::Status;
|
||||
use rocket::response::content::RawText;
|
||||
use rocket::tokio::sync::RwLock;
|
||||
use sha2::digest::FixedOutput;
|
||||
use sha2::Digest;
|
||||
|
||||
|
@ -19,17 +23,62 @@ use structs::*;
|
|||
|
||||
mod structs;
|
||||
|
||||
static mut BINS: Option<(HashMap<String, Bin>, Instant)> = None;
|
||||
static mut MANIFEST: Option<Vec<u8>> = None;
|
||||
static mut KEYPAIR: Option<KeyPair> = None;
|
||||
static BINS: Lazy<RwLock<(HashMap<String, Bin>, Instant)>> =
|
||||
Lazy::new(|| RwLock::new((get_bins(&Args::parse()), Instant::now())));
|
||||
static KEYPAIR: Lazy<KeyPair> = Lazy::new(|| {
|
||||
println!("Generating keypair");
|
||||
let kp = KeyPair::generate();
|
||||
|
||||
println!(
|
||||
"Keypair generated. Public key: {}",
|
||||
kp.pk.iter().map(|x| format!("{:x}", x)).collect::<Vec<String>>().join("")
|
||||
);
|
||||
kp
|
||||
});
|
||||
static MANIFEST: Lazy<Vec<u8>> = Lazy::new(|| {
|
||||
let args = Args::parse();
|
||||
|
||||
println!("Generating manifest");
|
||||
let mut manifest: Vec<u8> = Vec::new();
|
||||
let mut bin_pub_key: Vec<u8> = KEYPAIR.pk.to_vec();
|
||||
manifest.append(&mut bin_pub_key);
|
||||
let mut runners = 0;
|
||||
|
||||
for element in std::fs::read_dir(args.runners_dir).unwrap() {
|
||||
let en = element.unwrap();
|
||||
if en.path().is_file() {
|
||||
let mut hasher = sha2::Sha256::new();
|
||||
hasher.update(std::fs::read(en.path()).unwrap().as_slice());
|
||||
let mut contents = Vec::from(
|
||||
format!(
|
||||
"{:x} {}\n",
|
||||
hasher.finalize_fixed(),
|
||||
en.path().file_name().unwrap().to_str().unwrap()
|
||||
)
|
||||
.as_bytes(),
|
||||
);
|
||||
runners += 1;
|
||||
manifest.append(&mut contents);
|
||||
}
|
||||
}
|
||||
let mut hasher = sha2::Sha256::new();
|
||||
hasher.update(&manifest);
|
||||
println!(
|
||||
"Manifest generated with {} runners and SHA256: {:x}",
|
||||
runners,
|
||||
hasher.finalize_fixed()
|
||||
);
|
||||
manifest
|
||||
});
|
||||
static WEB_SH: &str = include_str!("../web.sh");
|
||||
|
||||
static HASH_CALCULATION_SH: &str = "";
|
||||
|
||||
fn reload_bins(bins: (&mut HashMap<String, Bin>, &mut Instant), args: &Args) {
|
||||
if (Instant::now() - *bins.1).as_secs() > args.refresh {
|
||||
*bins.0 = get_bins(args);
|
||||
*bins.1 = Instant::now();
|
||||
async fn reload_bins(args: &Args) {
|
||||
let (bins, time) = &mut *BINS.write().await;
|
||||
if (Instant::now() - *time).as_secs() > args.refresh {
|
||||
*bins = get_bins(args);
|
||||
*time = Instant::now();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -71,79 +120,64 @@ fn format_platform_list(bin: &Bin) -> String {
|
|||
async fn index() -> RawText<String> {
|
||||
let args = Args::parse();
|
||||
let mut ret = String::new();
|
||||
unsafe {
|
||||
if let Some(manifest) = &MANIFEST {
|
||||
let mut hasher = sha2::Sha256::new();
|
||||
hasher.update(manifest);
|
||||
ret.push_str(&format!("Manifest hashsum: {:x}\n", hasher.finalize_fixed()));
|
||||
}
|
||||
|
||||
let mut hasher = sha2::Sha256::new();
|
||||
hasher.update(&*MANIFEST);
|
||||
ret.push_str(&format!("Manifest hashsum: {:x}\n", hasher.finalize_fixed()));
|
||||
|
||||
reload_bins(&args).await;
|
||||
let (bins, _) = &*BINS.read().await;
|
||||
|
||||
if bins.is_empty() {
|
||||
return RawText(String::from("No binaries found"));
|
||||
}
|
||||
unsafe {
|
||||
if let Some((bins, time)) = &mut BINS {
|
||||
reload_bins((bins, time), &args);
|
||||
if bins.is_empty() {
|
||||
return RawText(String::from("No binaries found"));
|
||||
}
|
||||
for (name, bin) in bins {
|
||||
ret.push_str(&format!(
|
||||
"- {} (platforms: {:?})\n",
|
||||
name,
|
||||
bin.platforms
|
||||
.iter()
|
||||
.map(|plat| format!("{}-{}", plat.system, plat.arch))
|
||||
.collect::<Vec<String>>()
|
||||
))
|
||||
}
|
||||
}
|
||||
for (name, bin) in bins {
|
||||
ret.push_str(&format!(
|
||||
"- {} (platforms: {:?})\n",
|
||||
name,
|
||||
bin.platforms
|
||||
.iter()
|
||||
.map(|plat| format!("{}-{}", plat.system, plat.arch))
|
||||
.collect::<Vec<String>>()
|
||||
))
|
||||
}
|
||||
|
||||
RawText(ret)
|
||||
}
|
||||
|
||||
#[get("/runner/manifest")]
|
||||
async fn get_manifest() -> Vec<u8> {
|
||||
unsafe {
|
||||
match &MANIFEST {
|
||||
Some(man) => man.clone(),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
async fn get_manifest<'a>() -> Vec<u8> {
|
||||
let manifest = &*MANIFEST;
|
||||
manifest.clone()
|
||||
}
|
||||
#[get("/<bin>")]
|
||||
async fn get_script(bin: &str) -> ScriptResponse {
|
||||
let args = Args::parse();
|
||||
unsafe {
|
||||
if let Some((bins, time)) = &mut BINS {
|
||||
reload_bins((bins, time), &args);
|
||||
return match bins.get(bin) {
|
||||
None => ScriptResponse::Status(Status::NotFound),
|
||||
Some(bin) => {
|
||||
let mut script = String::from(WEB_SH);
|
||||
script = script
|
||||
.replace("{{HASH_CALCULATION}}", HASH_CALCULATION_SH)
|
||||
.replace("{{NAME}}", &bin.name)
|
||||
.replace("{{PLATFORM_LIST}}", &format_platform_list(bin))
|
||||
.replace("{{EXTERNAL_ADDRESS}}", &args.url);
|
||||
ScriptResponse::Text(RawText(script))
|
||||
}
|
||||
};
|
||||
reload_bins(&args).await;
|
||||
let (bins, _) = &*BINS.read().await;
|
||||
match bins.get(bin) {
|
||||
None => ScriptResponse::Status(Status::NotFound),
|
||||
Some(bin) => {
|
||||
let mut script = String::from(WEB_SH);
|
||||
script = script
|
||||
.replace("{{HASH_CALCULATION}}", HASH_CALCULATION_SH)
|
||||
.replace("{{NAME}}", &bin.name)
|
||||
.replace("{{PLATFORM_LIST}}", &format_platform_list(bin))
|
||||
.replace("{{EXTERNAL_ADDRESS}}", &args.url);
|
||||
ScriptResponse::Text(RawText(script))
|
||||
}
|
||||
}
|
||||
ScriptResponse::Status(Status::NotFound)
|
||||
}
|
||||
|
||||
#[get("/<bin>/platforms")]
|
||||
async fn get_platforms(bin: &str) -> ScriptResponse {
|
||||
let args = Args::parse();
|
||||
unsafe {
|
||||
if let Some((bins, time)) = &mut BINS {
|
||||
reload_bins((bins, time), &args);
|
||||
return match bins.get(bin) {
|
||||
None => ScriptResponse::Status(Status::NotFound),
|
||||
Some(bin) => ScriptResponse::Text(RawText(format_platform_list(bin))),
|
||||
};
|
||||
}
|
||||
reload_bins(&args).await;
|
||||
let (bins, _) = &*BINS.read().await;
|
||||
match bins.get(bin) {
|
||||
None => ScriptResponse::Status(Status::NotFound),
|
||||
Some(bin) => ScriptResponse::Text(RawText(format_platform_list(bin))),
|
||||
}
|
||||
ScriptResponse::Status(Status::NotFound)
|
||||
}
|
||||
|
||||
#[get("/bin/<bin>/<platform>/<arch>")]
|
||||
|
@ -178,12 +212,7 @@ async fn get_binary_sign(bin: &str, platform: &str, arch: &str) -> SignResponse
|
|||
Ok(f) => f,
|
||||
Err(_) => return SignResponse::Status(Status::BadRequest),
|
||||
};
|
||||
let keypair = unsafe {
|
||||
match &KEYPAIR {
|
||||
Some(pair) => pair,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
};
|
||||
let keypair = &*KEYPAIR;
|
||||
SignResponse::Bin(keypair.sk.sign(file.as_slice(), Some(Noise::generate())).as_slice().to_vec())
|
||||
}
|
||||
#[launch]
|
||||
|
@ -194,47 +223,7 @@ async fn rocket() -> _ {
|
|||
std::process::exit(1);
|
||||
}
|
||||
|
||||
unsafe {
|
||||
BINS = Some((get_bins(&args), Instant::now()));
|
||||
println!("Generating keypair");
|
||||
let kp = KeyPair::generate();
|
||||
KEYPAIR = Some(kp.clone());
|
||||
println!(
|
||||
"Keypair generated. Public key: {}",
|
||||
&kp.pk.iter().map(|x| format!("{:x}", x)).collect::<Vec<String>>().join("")
|
||||
);
|
||||
println!("Generating manifest");
|
||||
let mut manifest: Vec<u8> = Vec::new();
|
||||
let mut bin_pub_key: Vec<u8> = kp.pk.to_vec();
|
||||
manifest.append(&mut bin_pub_key);
|
||||
let mut runners = 0;
|
||||
|
||||
for element in std::fs::read_dir(args.runners_dir).unwrap() {
|
||||
let en = element.unwrap();
|
||||
if en.path().is_file() {
|
||||
let mut hasher = sha2::Sha256::new();
|
||||
hasher.update(std::fs::read(en.path()).unwrap().as_slice());
|
||||
let mut contents = Vec::from(
|
||||
format!(
|
||||
"{:x} {}\n",
|
||||
hasher.finalize_fixed(),
|
||||
en.path().file_name().unwrap().to_str().unwrap()
|
||||
)
|
||||
.as_bytes(),
|
||||
);
|
||||
runners += 1;
|
||||
manifest.append(&mut contents);
|
||||
}
|
||||
}
|
||||
let mut hasher = sha2::Sha256::new();
|
||||
hasher.update(&manifest);
|
||||
println!(
|
||||
"Manifest generated with {} runners and SHA256: {:x}",
|
||||
runners,
|
||||
hasher.finalize_fixed()
|
||||
);
|
||||
MANIFEST = Some(manifest)
|
||||
};
|
||||
let _ = &*BINS.read().await;
|
||||
|
||||
let figment = Figment::from(rocket::Config::default())
|
||||
.merge(("ident", "Binhost"))
|
||||
|
|
Loading…
Reference in a new issue