use std::sync::Arc; use axum::{extract::Path, Extension, Json}; use axum_auth::AuthBearer; use hyper::StatusCode; use solarlib::ship::{DbShip, Sha256, Ship}; use sqlx::{query, query_as, Error as SqlxError}; use tracing::log::warn; use crate::{ errors::{JsonResult, ServiceError, StringResult}, State, }; pub async fn list(state: Extension>) -> JsonResult>> { let mut conn = state.conn.acquire().await?; let db_ships = query_as!(DbShip, "SELECT * FROM ships") .fetch_all(&mut conn) .await?; let ships = db_ships .into_iter() .map(|d| d.into()) .collect::>(); Ok(Json(ships)) } pub async fn new( Json(new_ship): Json, state: Extension>, AuthBearer(token): AuthBearer, ) -> StringResult { check_bearer(token)?; let mut conn = state.conn.acquire().await?; query!( "INSERT INTO ships (name, shasum, download_url, version) VALUES ($1, $2, $3, $4)", new_ship.name, new_ship.shasum.to_string(), new_ship.download_url, new_ship.version ) .execute(&mut conn) .await?; Ok("OK") } pub async fn delete( Path(shasum): Path, state: Extension>, AuthBearer(token): AuthBearer, ) -> StringResult { check_bearer(token)?; let mut conn = state.conn.acquire().await?; query!("DELETE FROM ships WHERE shasum=$1", shasum.to_string()) .execute(&mut conn) .await?; Ok("OK") } pub async fn get( Path(shasum): Path, state: Extension>, ) -> JsonResult> { let mut conn = state.conn.acquire().await?; let db_ship = match query_as!( DbShip, "SELECT * FROM ships WHERE shasum=$1", shasum.to_string() ) .fetch_one(&mut conn) .await { Ok(d) => d, Err(e) => match e { SqlxError::RowNotFound => return Err(ServiceError::NotFound), _ => { return Err(e.into()); } }, }; Ok(Json(db_ship)) } fn check_bearer(token: String) -> Result<(), ServiceError> { let expected_token = match std::env::var("SHARED_KEY") { Ok(t) => t, Err(_) => { warn!("No pre-shared key set in environment. This is not secure!"); "bad-key".into() } }; if token != expected_token { Err(ServiceError::NotAuthorized) } else { Ok(()) } }