Replace axum with salvo
This commit is contained in:
Generated
+1469
-86
File diff suppressed because it is too large
Load Diff
@@ -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"] }
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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(¶ms.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 = ¶ms.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, ¶ms.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
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user