Replace axum with salvo

This commit is contained in:
2025-07-01 23:10:58 -06:00
parent d9aa724b90
commit 8857e226fe
4 changed files with 1542 additions and 161 deletions
Generated
+1469 -86
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -5,7 +5,6 @@ edition = "2024"
[dependencies] [dependencies]
anyhow = "1.0.98" anyhow = "1.0.98"
axum = "0.8.4"
directories = "6.0.0" directories = "6.0.0"
getrandom = { version = "0.3.3", features = ["std"] } getrandom = { version = "0.3.3", features = ["std"] }
hex = "0.4.3" hex = "0.4.3"
@@ -16,6 +15,7 @@ rand = "0.9.1"
reqwest = { version = "0.12.20", features = [ reqwest = { version = "0.12.20", features = [
"rustls-tls", "rustls-tls",
], default-features = false } ], default-features = false }
salvo = { version = "0.79.0", features = ["oapi"] }
serde = { version = "1.0.219", features = ["serde_derive"] } serde = { version = "1.0.219", features = ["serde_derive"] }
serde-xml-rs = "0.8.1" serde-xml-rs = "0.8.1"
tokio = { version = "1.45.1", features = ["full"] } tokio = { version = "1.45.1", features = ["full"] }
+9 -9
View File
@@ -1,4 +1,4 @@
use axum::{Router, routing::get}; use salvo::prelude::*;
use std::ffi::CString; use std::ffi::CString;
use moonlight_common_c_sys::{ use moonlight_common_c_sys::{
@@ -101,12 +101,12 @@ fn barmain() {
#[tokio::main] #[tokio::main]
async fn main() { async fn main() {
// Create a router with a test endpoint let mut router = Router::new().push(Router::with_path("pair").post(pair::post_pair));
let app = Router::new().route("/pair/{url}/{port}", get(pair::get_pair)); let doc = OpenApi::new("test api", "0.0.1").merge_router(&router);
let router = router
// Bind to port 3000 .unshift(doc.into_router("/api-doc/openapi.json"))
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap(); .unshift(SwaggerUi::new("/api-doc/openapi.json").into_router("/swagger-ui"));
let listener = TcpListener::new("0.0.0.0:3001");
// Start the server let acceptor = listener.join(TcpListener::new("0.0.0.0:3000")).bind().await;
axum::serve(listener, app).await.unwrap(); salvo::Server::new(acceptor).serve(router).await;
} }
+63 -65
View File
@@ -1,20 +1,26 @@
use anyhow::Result;
use openssl::hash::MessageDigest;
use openssl::pkey::{PKey, Private};
use openssl::rsa::Rsa;
use openssl::sha::Sha256;
use openssl::x509::X509;
use rand::Rng;
use salvo::prelude::*;
use serde::{Deserialize, Serialize};
use std::fs; use std::fs;
use std::io::Write; use std::io::Write;
use axum::Json; #[derive(Debug, Deserialize, ToSchema)]
use axum::extract::Path; struct PostPairParams {
use axum::http::StatusCode; host: String,
use axum::response::{IntoResponse, Response}; port: u16,
use openssl::hash::MessageDigest; pair_endpoint: Option<String>,
use openssl::sha::Sha256; }
use rand::Rng;
use serde::{Deserialize, Serialize};
use openssl::pkey::{PKey, Private}; #[derive(Debug, Serialize, ToSchema)]
use openssl::rsa::Rsa; struct PostPairReturn {
use openssl::x509::X509; paired: bool,
}
use anyhow::Result;
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
struct ServerCertResponse { struct ServerCertResponse {
@@ -23,18 +29,18 @@ struct ServerCertResponse {
} }
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
pub struct ClientChallengeResponse { struct ClientChallengeResponse {
challengeresponse: String, challengeresponse: String,
} }
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
pub struct ServerChallengeResponseResponse { struct ServerChallengeResponseResponse {
paired: i32, paired: i32,
pairingsecret: String, pairingsecret: String,
} }
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
pub struct ClientPairingSecretResponse { struct ClientPairingSecretResponse {
paired: i32, paired: i32,
} }
@@ -44,16 +50,11 @@ struct ServerCert {
} }
#[derive(Debug)] #[derive(Debug)]
pub struct ServerPairingSecret { struct ServerPairingSecret {
pairing_secret: Vec<u8>, pairing_secret: Vec<u8>,
signature: Vec<u8>, signature: Vec<u8>,
} }
#[derive(Debug, Serialize)]
struct PairResult {
paired: bool,
}
fn get_cert_and_private_key() -> Result<(X509, PKey<Private>)> { fn get_cert_and_private_key() -> Result<(X509, PKey<Private>)> {
let rsa = Rsa::generate(2048)?; let rsa = Rsa::generate(2048)?;
let key_pair = PKey::from_rsa(rsa)?; let key_pair = PKey::from_rsa(rsa)?;
@@ -274,7 +275,7 @@ async fn send_server_challenge_response(
Ok(serde_xml_rs::from_str(&text)?) Ok(serde_xml_rs::from_str(&text)?)
} }
async fn generate_aes_key(salt: [u8; 16], pin: [u8; 4]) -> Vec<u8> { fn generate_aes_key(salt: [u8; 16], pin: [u8; 4]) -> Vec<u8> {
let mut salt_pin = Vec::with_capacity(salt.len() + pin.len()); let mut salt_pin = Vec::with_capacity(salt.len() + pin.len());
salt_pin.extend_from_slice(&salt); salt_pin.extend_from_slice(&salt);
salt_pin.extend_from_slice(&pin); salt_pin.extend_from_slice(&pin);
@@ -291,7 +292,7 @@ async fn do_challenge(
salt: [u8; 16], salt: [u8; 16],
cert: &X509, cert: &X509,
) -> Result<ServerPairingSecret> { ) -> Result<ServerPairingSecret> {
let aes_key = generate_aes_key(salt, pin).await; let aes_key = generate_aes_key(salt, pin);
let aes_hex = hex::encode(&aes_key); let aes_hex = hex::encode(&aes_key);
//println!("aes_hex: {aes_hex}"); //println!("aes_hex: {aes_hex}");
@@ -315,11 +316,7 @@ async fn do_challenge(
}) })
} }
pub async fn get_base_url( fn get_base_url(host: &String, port: u16, unique_id: String) -> url_constructor::UrlConstructor {
host: &String,
port: u16,
unique_id: String,
) -> url_constructor::UrlConstructor {
let mut base_url = url_constructor::UrlConstructor::new(); let mut base_url = url_constructor::UrlConstructor::new();
base_url base_url
.scheme("http") .scheme("http")
@@ -332,7 +329,7 @@ pub async fn get_base_url(
base_url base_url
} }
pub async fn generate_pin() -> [u8; 4] { fn generate_pin() -> [u8; 4] {
let mut pin = [0u8; 4]; let mut pin = [0u8; 4];
{ {
print!("pairing pin: "); print!("pairing pin: ");
@@ -349,7 +346,7 @@ pub async fn generate_pin() -> [u8; 4] {
pin pin
} }
pub async fn verify_signature(secret: Vec<u8>, signature: Vec<u8>, cert: Vec<u8>) -> Result<()> { fn verify_signature(secret: Vec<u8>, signature: Vec<u8>, cert: Vec<u8>) -> Result<()> {
let cert_x509 = openssl::x509::X509::from_pem(&cert)?; let cert_x509 = openssl::x509::X509::from_pem(&cert)?;
let cert_pubkey = cert_x509.public_key()?; let cert_pubkey = cert_x509.public_key()?;
@@ -366,7 +363,7 @@ pub async fn verify_signature(secret: Vec<u8>, signature: Vec<u8>, cert: Vec<u8>
} }
} }
pub async fn create_signature(data: &[u8; 16], private_key: &PKey<Private>) -> Result<Vec<u8>> { fn create_signature(data: &[u8; 16], private_key: &PKey<Private>) -> Result<Vec<u8>> {
let mut signature = Vec::new(); let mut signature = Vec::new();
let md = openssl::md::Md::sha256(); let md = openssl::md::Md::sha256();
@@ -380,12 +377,12 @@ pub async fn create_signature(data: &[u8; 16], private_key: &PKey<Private>) -> R
Ok(signature) Ok(signature)
} }
pub async fn send_client_pairing_secret( async fn send_client_pairing_secret(
mut base_url: url_constructor::UrlConstructor, mut base_url: url_constructor::UrlConstructor,
client_secret_data: &[u8; 16], client_secret_data: &[u8; 16],
private_key: &PKey<Private>, private_key: &PKey<Private>,
) -> Result<ClientPairingSecretResponse> { ) -> Result<ClientPairingSecretResponse> {
let signature = create_signature(client_secret_data, private_key).await?; let signature = create_signature(client_secret_data, private_key)?;
let mut client_secret = Vec::with_capacity(client_secret_data.len() + signature.len()); let mut client_secret = Vec::with_capacity(client_secret_data.len() + signature.len());
client_secret.extend_from_slice(client_secret_data); client_secret.extend_from_slice(client_secret_data);
@@ -400,27 +397,32 @@ pub async fn send_client_pairing_secret(
Ok(serde_xml_rs::from_str(&text)?) Ok(serde_xml_rs::from_str(&text)?)
} }
async fn get_unique_id() -> Result<String> { fn get_unique_id() -> Result<String> {
let mut bytes = [0u8; 8]; let mut bytes = [0u8; 8];
openssl::rand::rand_bytes(&mut bytes)?; openssl::rand::rand_bytes(&mut bytes)?;
Ok(hex::encode(bytes)) Ok(hex::encode(bytes))
} }
// Do a pairing operation #[salvo::oapi::endpoint]
pub async fn get_pair(Path((host, port)): Path<(String, u16)>) -> Response { pub async fn post_pair(body: salvo::oapi::extract::JsonBody<PostPairParams>) -> StatusCode {
//let unique_id = "0123456789ABCDEF".to_string(); let params = body.into_inner();
//let uuidv2 = "23060a17e4fc40f5a83fee298995dd18".to_string();
let unique_id = get_unique_id().await.unwrap(); let unique_id = match get_unique_id() {
Ok(u) => u,
Err(e) => {
println!("Could not generate unique id: {e}");
return StatusCode::INTERNAL_SERVER_ERROR;
}
};
let base_url = get_base_url(&host, port, unique_id).await; let base_url = get_base_url(&params.host, params.port, unique_id);
let pin = generate_pin().await; let pin = generate_pin();
let mut client_secret_data = [0u8; 16]; let mut client_secret_data = [0u8; 16];
if let Err(e) = openssl::rand::rand_bytes(&mut client_secret_data) { if let Err(e) = openssl::rand::rand_bytes(&mut client_secret_data) {
println!("Could not generate client secret data: {e}"); println!("Could not generate client secret data: {e}");
return StatusCode::INTERNAL_SERVER_ERROR.into_response(); return StatusCode::INTERNAL_SERVER_ERROR;
} }
// Generate certificates // Generate certificates
@@ -428,7 +430,7 @@ pub async fn get_pair(Path((host, port)): Path<(String, u16)>) -> Response {
Ok(v) => v, Ok(v) => v,
Err(e) => { Err(e) => {
println!("Could not generate certs: {e}"); println!("Could not generate certs: {e}");
return StatusCode::INTERNAL_SERVER_ERROR.into_response(); return StatusCode::INTERNAL_SERVER_ERROR;
} }
}; };
@@ -447,8 +449,8 @@ pub async fn get_pair(Path((host, port)): Path<(String, u16)>) -> Response {
let server_cert = match get_server_cert(base_url.clone(), salt_hex, cert_hex).await { let server_cert = match get_server_cert(base_url.clone(), salt_hex, cert_hex).await {
Ok(s) => s, Ok(s) => s,
Err(e) => { Err(e) => {
println!("could not get server cert: {e}"); println!("Could not get server cert: {e}");
return StatusCode::INTERNAL_SERVER_ERROR.into_response(); return StatusCode::INTERNAL_SERVER_ERROR;
} }
}; };
//println!("{server_cert:?}"); //println!("{server_cert:?}");
@@ -459,8 +461,8 @@ pub async fn get_pair(Path((host, port)): Path<(String, u16)>) -> Response {
match do_challenge(base_url.clone(), &client_secret_data, pin, salt, &cert).await { match do_challenge(base_url.clone(), &client_secret_data, pin, salt, &cert).await {
Ok(s) => s, Ok(s) => s,
Err(e) => { Err(e) => {
println!("could not do challenge: {e}"); println!("Could not do challenge: {e}");
return StatusCode::INTERNAL_SERVER_ERROR.into_response(); return StatusCode::INTERNAL_SERVER_ERROR;
} }
}; };
//println!("{server_pairing_secret:?}"); //println!("{server_pairing_secret:?}");
@@ -470,11 +472,9 @@ pub async fn get_pair(Path((host, port)): Path<(String, u16)>) -> Response {
server_pairing_secret.pairing_secret, server_pairing_secret.pairing_secret,
server_pairing_secret.signature, server_pairing_secret.signature,
server_cert.cert, server_cert.cert,
) ) {
.await
{
println!("Could not verify signature: {e}"); println!("Could not verify signature: {e}");
return StatusCode::INTERNAL_SERVER_ERROR.into_response(); return StatusCode::INTERNAL_SERVER_ERROR;
} }
let client_pairing_secret_response = let client_pairing_secret_response =
@@ -483,26 +483,24 @@ pub async fn get_pair(Path((host, port)): Path<(String, u16)>) -> Response {
Ok(p) => p, Ok(p) => p,
Err(e) => { Err(e) => {
println!("Could not send client pairing secret: {e}"); println!("Could not send client pairing secret: {e}");
return StatusCode::INTERNAL_SERVER_ERROR.into_response(); return StatusCode::INTERNAL_SERVER_ERROR;
} }
}; };
let pairing_result = PairResult { if client_pairing_secret_response.paired != 1 {
paired: client_pairing_secret_response.paired == 1, println!("Failed to pair with server");
}; return StatusCode::INTERNAL_SERVER_ERROR;
if pairing_result.paired {
println!("Successfully paired to server {host}:{port}");
} else { } else {
println!("Failed to pair with server {host}:{port}"); let host = &params.host;
return Json(pairing_result).into_response(); let port = params.port;
println!("Paired with server {host}:{port} successfully!");
} }
// Save certificate to disk so it can be used for subsequent connections // Save certificate to disk so it can be used for subsequent connections
if let Err(e) = save_cert_and_key_to_disk(cert, private_key, &host, port) { if let Err(e) = save_cert_and_key_to_disk(cert, private_key, &params.host, params.port) {
println!("Could not save cert and key to disk: {e}"); println!("Could not save cert and key to disk");
return StatusCode::INTERNAL_SERVER_ERROR.into_response(); return StatusCode::INTERNAL_SERVER_ERROR;
}; };
Json(pairing_result).into_response() StatusCode::OK
} }