chore: clean up, rename types.rs to server.rs
This commit is contained in:
parent
a8bc61f40c
commit
0c68399210
9 changed files with 110 additions and 41 deletions
|
@ -17,4 +17,4 @@ hosts: # ignore this it doesn't function
|
||||||
|
|
||||||
clients:
|
clients:
|
||||||
- name: 'eu-central-1' # Example Client right here (the client in this case would be for example the stereo.cat backend)
|
- name: 'eu-central-1' # Example Client right here (the client in this case would be for example the stereo.cat backend)
|
||||||
secret: '$2b$12$5wH/0p702PPqVp7fCpVS4.1GA2/wAbk89w2nMjwuS8439OhjCUGbK' # password123
|
hashed_secret: '$2b$12$5wH/0p702PPqVp7fCpVS4.1GA2/wAbk89w2nMjwuS8439OhjCUGbK' # password123
|
||||||
|
|
|
@ -27,7 +27,26 @@ pub struct Api {
|
||||||
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
|
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
|
||||||
pub struct Client {
|
pub struct Client {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub secret: String,
|
pub hashed_secret: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Client {
|
||||||
|
pub async fn verify(us: String, config: Config) -> bool {
|
||||||
|
// us stands for user:secret btw
|
||||||
|
let us_split: Vec<&str> = us.split(':').collect();
|
||||||
|
|
||||||
|
let name = us_split.first().unwrap();
|
||||||
|
let secret = us_split.last().unwrap();
|
||||||
|
|
||||||
|
let client: Client = config
|
||||||
|
.clients
|
||||||
|
.into_iter()
|
||||||
|
.filter(|x| x.name.eq(name))
|
||||||
|
.nth(0)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
return bcrypt::verify(secret, client.hashed_secret.as_str()).unwrap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
|
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
use std::{error::Error, net::{IpAddr, SocketAddr}};
|
use std::{
|
||||||
|
error::Error,
|
||||||
|
net::{IpAddr, SocketAddr},
|
||||||
|
};
|
||||||
|
|
||||||
use tokio_postgres::{Client, Socket, tls::MakeTlsConnect};
|
use tokio_postgres::{Client, Socket, tls::MakeTlsConnect};
|
||||||
|
|
||||||
|
|
20
src/main.rs
20
src/main.rs
|
@ -1,7 +1,7 @@
|
||||||
mod config;
|
mod config;
|
||||||
mod db;
|
mod db;
|
||||||
|
mod server;
|
||||||
mod services;
|
mod services;
|
||||||
mod types;
|
|
||||||
|
|
||||||
use std::{env, sync::Arc};
|
use std::{env, sync::Arc};
|
||||||
|
|
||||||
|
@ -11,16 +11,20 @@ use db::BoxyDatabase;
|
||||||
use log::{error, info};
|
use log::{error, info};
|
||||||
use nanoid::nanoid;
|
use nanoid::nanoid;
|
||||||
use ring::rand::SystemRandom;
|
use ring::rand::SystemRandom;
|
||||||
|
use server::Server;
|
||||||
use services::{api::ApiService, controller::ControllerService};
|
use services::{api::ApiService, controller::ControllerService};
|
||||||
use tokio::{fs::File, io::AsyncReadExt, sync::Mutex};
|
use tokio::{fs::File, io::AsyncReadExt, sync::Mutex};
|
||||||
use tokio_postgres::{NoTls, tls::NoTlsError};
|
use tokio_postgres::{NoTls, tls::NoTlsError};
|
||||||
use types::Server;
|
|
||||||
|
const VERSION: &str = "v0.1a";
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
pretty_env_logger::formatted_builder()
|
if env::var("RUST_LOG").is_err() {
|
||||||
.filter(None, log::LevelFilter::Info)
|
unsafe { env::set_var("RUST_LOG", "info") };
|
||||||
.init();
|
}
|
||||||
|
|
||||||
|
pretty_env_logger::init();
|
||||||
|
|
||||||
let args: Vec<String> = env::args().collect();
|
let args: Vec<String> = env::args().collect();
|
||||||
|
|
||||||
|
@ -37,6 +41,10 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
"version" => {
|
||||||
|
info!("Version: {}", VERSION);
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -64,7 +72,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let api_svc = ApiService {
|
let api_svc = ApiService {
|
||||||
database: database_shared.clone(),
|
database: database_shared.clone(),
|
||||||
config: config.clone(),
|
config: config.clone(),
|
||||||
_address: None
|
_address: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let svc = ControllerService {
|
let svc = ControllerService {
|
||||||
|
|
|
@ -25,7 +25,7 @@ pub struct Server<S> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait TcpIntercept {
|
pub trait TcpIntercept {
|
||||||
fn handle(&mut self, stream: &TcpStream);
|
fn stream(&mut self, stream: &TcpStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S> Server<S>
|
impl<S> Server<S>
|
||||||
|
@ -43,7 +43,7 @@ where
|
||||||
let (stream, _) = self.listener.accept().await.unwrap();
|
let (stream, _) = self.listener.accept().await.unwrap();
|
||||||
|
|
||||||
let mut svc_clone = self.service.clone();
|
let mut svc_clone = self.service.clone();
|
||||||
svc_clone.handle(&stream);
|
svc_clone.stream(&stream);
|
||||||
|
|
||||||
let io = TokioIo::new(stream);
|
let io = TokioIo::new(stream);
|
||||||
tokio::task::spawn(async move {
|
tokio::task::spawn(async move {
|
|
@ -1,3 +1,3 @@
|
||||||
pub mod proxy;
|
|
||||||
pub mod controller;
|
|
||||||
pub mod api;
|
pub mod api;
|
||||||
|
pub mod controller;
|
||||||
|
pub mod proxy;
|
||||||
|
|
|
@ -1,16 +1,20 @@
|
||||||
use std::{hash, net::{IpAddr, SocketAddr}, pin::Pin, sync::Arc};
|
use std::{net::IpAddr, pin::Pin, sync::Arc};
|
||||||
|
|
||||||
use base64::{Engine, prelude::BASE64_STANDARD};
|
use base64::{Engine, prelude::BASE64_STANDARD};
|
||||||
use bcrypt::DEFAULT_COST;
|
use bcrypt::bcrypt;
|
||||||
use http_body_util::{BodyExt, Full};
|
use http_body_util::{BodyExt, Full};
|
||||||
use hyper::{
|
use hyper::{
|
||||||
body::{Bytes, Incoming}, service::Service, Method, Request, Response, StatusCode, Uri
|
Method, Request, Response, StatusCode,
|
||||||
|
body::{Bytes, Incoming},
|
||||||
|
service::Service,
|
||||||
};
|
};
|
||||||
use log::{info, trace};
|
use log::{debug, info, warn};
|
||||||
use tokio::{net::TcpStream, sync::Mutex};
|
use tokio::{net::TcpStream, sync::Mutex};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
config::{Client, Config}, db::{BoxyDatabase, Endpoint}, types::{GeneralBody, GeneralResponse, TcpIntercept}
|
config::{Client, Config},
|
||||||
|
db::{BoxyDatabase, Endpoint},
|
||||||
|
server::{GeneralBody, GeneralResponse, TcpIntercept},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
@ -20,7 +24,7 @@ pub struct ApiService {
|
||||||
pub _address: Option<IpAddr>,
|
pub _address: Option<IpAddr>,
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn default_response() -> Response<http_body_util::Either<Incoming, Full<Bytes>>> {
|
async fn default_response() -> GeneralResponse {
|
||||||
Response::builder()
|
Response::builder()
|
||||||
.status(404)
|
.status(404)
|
||||||
.body(GeneralBody::Right(Full::from(Bytes::from(
|
.body(GeneralBody::Right(Full::from(Bytes::from(
|
||||||
|
@ -29,7 +33,7 @@ async fn default_response() -> Response<http_body_util::Either<Incoming, Full<By
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn custom_resp(e: StatusCode, m: String) -> Response<http_body_util::Either<Incoming, Full<Bytes>>> {
|
async fn custom_resp(e: StatusCode, m: &'static str) -> GeneralResponse {
|
||||||
Response::builder()
|
Response::builder()
|
||||||
.status(e)
|
.status(e)
|
||||||
.body(GeneralBody::Right(Full::from(Bytes::from(m))))
|
.body(GeneralBody::Right(Full::from(Bytes::from(m))))
|
||||||
|
@ -37,7 +41,7 @@ async fn custom_resp(e: StatusCode, m: String) -> Response<http_body_util::Eithe
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TcpIntercept for ApiService {
|
impl TcpIntercept for ApiService {
|
||||||
fn handle(&mut self, stream: &TcpStream) {
|
fn stream(&mut self, stream: &TcpStream) {
|
||||||
self._address = Some(stream.peer_addr().unwrap().ip());
|
self._address = Some(stream.peer_addr().unwrap().ip());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -51,37 +55,73 @@ impl Service<Request<Incoming>> for ApiService {
|
||||||
let database = self.database.clone();
|
let database = self.database.clone();
|
||||||
let config = self.config.clone();
|
let config = self.config.clone();
|
||||||
let address = self._address.clone().unwrap();
|
let address = self._address.clone().unwrap();
|
||||||
|
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
match *req.method() {
|
match *req.method() {
|
||||||
Method::POST => match req.uri().path() {
|
Method::POST => match req.uri().path() {
|
||||||
"/register" => {
|
"/register" => {
|
||||||
let encoded_header = req.headers().get(hyper::header::AUTHORIZATION).unwrap().to_str().unwrap();
|
debug!("new api register request from {}", address);
|
||||||
|
|
||||||
let auth_string = String::from_utf8(BASE64_STANDARD.decode(&encoded_header[6..]).unwrap()).unwrap();
|
let encoded_header = req
|
||||||
|
.headers()
|
||||||
|
.get(hyper::header::AUTHORIZATION)
|
||||||
|
.unwrap()
|
||||||
|
.to_str()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let auth_string_split: Vec<&str> = auth_string.split(':').collect();
|
debug!("authorization header: {}", encoded_header);
|
||||||
|
|
||||||
let name = auth_string_split.first().unwrap();
|
let auth_string = String::from_utf8(
|
||||||
let secret = auth_string_split.get(1).unwrap();
|
BASE64_STANDARD.decode(&encoded_header[6..]).unwrap(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let matched_clients: Vec<&Client> = config.clients.iter().filter(|x| x.name.eq(name)).collect();
|
debug!("decoded auth string: {}", auth_string);
|
||||||
|
|
||||||
let client = matched_clients.first().unwrap();
|
if !Client::verify(auth_string.clone(), config).await {
|
||||||
|
warn!(
|
||||||
|
"Authentication for string {} from {} failed.",
|
||||||
|
auth_string, address
|
||||||
|
);
|
||||||
|
|
||||||
if !bcrypt::verify(secret, client.secret.as_str()).unwrap() {
|
return Ok(custom_resp(
|
||||||
return Ok(custom_resp(StatusCode::UNAUTHORIZED, "Invalid credentials.".to_string()).await);
|
StatusCode::UNAUTHORIZED,
|
||||||
|
"Invalid credentials.",
|
||||||
|
)
|
||||||
|
.await);
|
||||||
}
|
}
|
||||||
|
|
||||||
let body = String::from_utf8(req.collect().await.unwrap().to_bytes().iter().cloned().collect::<Vec<u8>>()).unwrap();
|
let body = String::from_utf8(
|
||||||
|
req.collect()
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.to_bytes()
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.collect::<Vec<u8>>(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
let json = json::parse(body.as_str()).unwrap();
|
let json = json::parse(body.as_str()).unwrap();
|
||||||
|
|
||||||
info!("body: {}", body);
|
debug!("body: {}", body);
|
||||||
|
|
||||||
let mut endpoint = Endpoint::new(None, address, json["port"].as_u16().unwrap(), json["callback"].as_str().unwrap_or("/").to_string()).await;
|
let mut endpoint = Endpoint::new(
|
||||||
|
None,
|
||||||
|
address,
|
||||||
|
json["port"].as_u16().unwrap(),
|
||||||
|
json["callback"].as_str().unwrap_or("/").to_string(),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
endpoint.register(*database.lock().await, json["hostname"].as_str().unwrap().to_string()).await.unwrap();
|
endpoint
|
||||||
|
.register(
|
||||||
|
*database.lock().await,
|
||||||
|
json["hostname"].as_str().unwrap().to_string(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
Ok(custom_resp(StatusCode::OK, "yay".to_string()).await)
|
Ok(custom_resp(StatusCode::OK, "").await)
|
||||||
}
|
}
|
||||||
_ => Ok(default_response().await),
|
_ => Ok(default_response().await),
|
||||||
},
|
},
|
||||||
|
|
|
@ -12,7 +12,7 @@ use tokio::sync::Mutex;
|
||||||
use crate::{
|
use crate::{
|
||||||
config::{self, Client, Config, Host},
|
config::{self, Client, Config, Host},
|
||||||
db::{BoxyDatabase, Endpoint},
|
db::{BoxyDatabase, Endpoint},
|
||||||
types::{GeneralBody, GeneralResponse, TcpIntercept},
|
server::{GeneralBody, GeneralResponse, TcpIntercept},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::proxy::ProxyService;
|
use super::proxy::ProxyService;
|
||||||
|
@ -23,8 +23,7 @@ pub struct ControllerService {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TcpIntercept for ControllerService {
|
impl TcpIntercept for ControllerService {
|
||||||
fn handle(&mut self, stream: &tokio::net::TcpStream) {
|
fn stream(&mut self, _: &tokio::net::TcpStream) {}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Service<Request<Incoming>> for ControllerService {
|
impl Service<Request<Incoming>> for ControllerService {
|
||||||
|
|
|
@ -5,7 +5,7 @@ use hyper_util::rt::TokioIo;
|
||||||
use log::error;
|
use log::error;
|
||||||
use tokio::net::TcpStream;
|
use tokio::net::TcpStream;
|
||||||
|
|
||||||
use crate::types::{GeneralResponse, to_general_response};
|
use crate::server::{GeneralResponse, to_general_response};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct ProxyService {
|
pub struct ProxyService {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue