0.1.1
This commit is contained in:
+37
-10
@@ -22,7 +22,7 @@ use tokio::{
|
||||
use tower_http::cors::CorsLayer;
|
||||
use uuid::Uuid;
|
||||
|
||||
use tracing::{debug, info};
|
||||
use tracing::{debug, info, warn};
|
||||
|
||||
use crate::{
|
||||
AppState,
|
||||
@@ -30,12 +30,20 @@ use crate::{
|
||||
webrtc_ingest::handle_whip_injest,
|
||||
};
|
||||
|
||||
const MAX_USERNAME_LEN: usize = 32;
|
||||
const MAX_LABEL_LEN: usize = 64;
|
||||
|
||||
pub struct HttpServerConfig {
|
||||
pub signup_code: String,
|
||||
}
|
||||
|
||||
pub struct HttpServer {
|
||||
pub offer_tx: Sender<(i32, i32, String)>,
|
||||
pub accept_rx: async_broadcast::InactiveReceiver<(i32, Option<String>)>,
|
||||
pub appstate: Arc<Mutex<AppState>>,
|
||||
pub request_count: Mutex<i32>,
|
||||
pub db: DatabaseConnection,
|
||||
pub config: HttpServerConfig,
|
||||
}
|
||||
|
||||
impl HttpServer {
|
||||
@@ -73,7 +81,7 @@ impl HttpServer {
|
||||
.layer(cors)
|
||||
.with_state(state);
|
||||
|
||||
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
|
||||
let addr = SocketAddr::from(([0, 0, 0, 0], 3000));
|
||||
let listener = TcpListener::bind(addr).await.unwrap();
|
||||
axum::serve(listener, app).await.unwrap();
|
||||
});
|
||||
@@ -175,12 +183,18 @@ async fn create_stream_key_handler(
|
||||
.await
|
||||
.unwrap()
|
||||
.len();
|
||||
if payload.label.is_empty() || payload.label.len() > MAX_LABEL_LEN {
|
||||
warn!(user_id = auth.0.id, label_len = payload.label.len(), max = MAX_LABEL_LEN, "stream key creation rejected: label length invalid");
|
||||
return StatusCode::UNPROCESSABLE_ENTITY;
|
||||
}
|
||||
if key_amount >= auth.0.stream_key_limit.try_into().unwrap() {
|
||||
warn!(user_id = auth.0.id, limit = auth.0.stream_key_limit, "stream key limit reached");
|
||||
return StatusCode::NOT_ACCEPTABLE;
|
||||
}
|
||||
let key = stream_key::Entity::create(&state.db, auth.0.id, value, payload.label, false).await;
|
||||
|
||||
if let Ok(_key) = key {
|
||||
if let Ok(ref k) = key {
|
||||
info!(user_id = auth.0.id, stream_key_id = k.id, label = %k.label, "stream key created");
|
||||
StatusCode::CREATED
|
||||
} else {
|
||||
StatusCode::INTERNAL_SERVER_ERROR
|
||||
@@ -226,15 +240,17 @@ async fn login_handler(
|
||||
State(state): State<Arc<HttpServer>>,
|
||||
Json(payload): Json<LoginForm>,
|
||||
) -> impl IntoResponse {
|
||||
if let Ok(x) = users::Entity::find_by_username(&state.db, payload.username).await {
|
||||
if let Ok(x) = users::Entity::find_by_username(&state.db, payload.username.clone()).await {
|
||||
if let Some(x) = x {
|
||||
let pass = verify_password(&payload.password, &x.hashed_password);
|
||||
if !pass {
|
||||
warn!(username = %payload.username, "login failed: wrong password");
|
||||
let mut meow = Response::new("".to_string());
|
||||
*meow.status_mut() = StatusCode::UNAUTHORIZED;
|
||||
return meow;
|
||||
};
|
||||
let auth = auth_session::Entity::create(&state.db, x.id).await.unwrap(); // This should be ok (hopefully)
|
||||
info!(user_id = x.id, username = %x.username, "login successful");
|
||||
let auth = auth_session::Entity::create(&state.db, x.id).await.unwrap();
|
||||
let token = auth.value;
|
||||
let mut meow = Response::new("".to_string());
|
||||
meow.headers_mut().insert(
|
||||
@@ -246,11 +262,13 @@ async fn login_handler(
|
||||
*meow.status_mut() = StatusCode::OK;
|
||||
return meow;
|
||||
} else {
|
||||
warn!(username = %payload.username, "login failed: user not found");
|
||||
let mut meow = Response::new("".to_string());
|
||||
*meow.status_mut() = StatusCode::UNAUTHORIZED;
|
||||
return meow;
|
||||
}
|
||||
} else {
|
||||
warn!(username = %payload.username, "login failed: DB error");
|
||||
let mut meow = Response::new("".to_string());
|
||||
*meow.status_mut() = StatusCode::UNAUTHORIZED;
|
||||
return meow;
|
||||
@@ -268,23 +286,30 @@ async fn create_user_handler(
|
||||
State(state): State<Arc<HttpServer>>,
|
||||
Json(payload): Json<CreateUserForm>,
|
||||
) -> (HeaderMap, StatusCode) {
|
||||
if payload.ref_token != "TEST" {
|
||||
if state.config.signup_code.is_empty() || payload.ref_token != state.config.signup_code {
|
||||
warn!(username = %payload.username, "signup rejected: invalid signup code");
|
||||
return (HeaderMap::new(), StatusCode::UNAUTHORIZED);
|
||||
}
|
||||
if payload.username.is_empty() || payload.username.len() > MAX_USERNAME_LEN {
|
||||
warn!(username = %payload.username, max = MAX_USERNAME_LEN, "signup rejected: username length invalid");
|
||||
return (HeaderMap::new(), StatusCode::UNPROCESSABLE_ENTITY);
|
||||
}
|
||||
|
||||
let meow = users::Entity::create(
|
||||
&state.db,
|
||||
payload.username,
|
||||
payload.username.clone(),
|
||||
hash_password(&payload.password).unwrap(),
|
||||
)
|
||||
.await;
|
||||
|
||||
// Create session
|
||||
let session: auth_session::Model = if let Ok(meow) = meow {
|
||||
auth_session::Entity::create(&state.db, meow.id)
|
||||
let session: auth_session::Model = if let Ok(ref user) = meow {
|
||||
info!(user_id = user.id, username = %user.username, "user created");
|
||||
auth_session::Entity::create(&state.db, user.id)
|
||||
.await
|
||||
.unwrap() // This should be ok (hopefully)
|
||||
.unwrap()
|
||||
} else {
|
||||
warn!(username = %payload.username, "user creation failed (likely username conflict)");
|
||||
return (HeaderMap::new(), StatusCode::CONFLICT);
|
||||
};
|
||||
let token = session.value;
|
||||
@@ -319,6 +344,7 @@ async fn stream_handler(
|
||||
let stream_key_id = if let Some(id) = stream_key_id {
|
||||
id
|
||||
} else {
|
||||
warn!(slug = %slug, "WHEP request for unknown or inactive stream");
|
||||
return Response::builder()
|
||||
.status(StatusCode::NOT_FOUND)
|
||||
.header("content-type", "application/text")
|
||||
@@ -326,6 +352,7 @@ async fn stream_handler(
|
||||
.unwrap();
|
||||
};
|
||||
|
||||
info!(request_id = request_id_clone, slug = %slug, stream_key_id, "WHEP offer received");
|
||||
let mut accept_rx = state.accept_rx.activate_cloned();
|
||||
let _ = state
|
||||
.offer_tx
|
||||
|
||||
Reference in New Issue
Block a user