create permissioned delete routes

This commit is contained in:
beckerinj
2022-12-01 22:58:22 -05:00
parent 209f6ebb87
commit 8c8b4ea488
5 changed files with 205 additions and 54 deletions
+89 -23
View File
@@ -1,45 +1,74 @@
use anyhow::{anyhow, Context};
use anyhow::anyhow;
use async_timing_util::unix_timestamp_ms;
use axum::{routing::post, Extension, Json, Router};
use axum::{
extract::Path,
routing::{delete, post},
Extension, Json, Router,
};
use db::DbExtension;
use helpers::handle_anyhow_error;
use types::{Build, Operation, PermissionLevel, Update, UpdateTarget};
use mungos::Deserialize;
use types::{traits::Permissioned, Build, Log, Operation, PermissionLevel, Update, UpdateTarget};
use crate::{auth::RequestUserExtension, ws::update};
use super::add_update;
use super::{add_update, PeripheryExtension};
#[derive(Deserialize)]
struct BuildId {
id: String,
}
#[derive(Deserialize)]
struct CreateBuildBody {
name: String,
server_id: String,
}
pub fn router() -> Router {
Router::new().route(
"/create",
post(|db, user, update_ws, build| async {
create(db, user, update_ws, build)
.await
.map_err(handle_anyhow_error)
}),
)
Router::new()
.route(
"/create",
post(|db, user, update_ws, build| async {
create(db, user, update_ws, build)
.await
.map_err(handle_anyhow_error)
}),
)
.route(
"/delete/:id",
delete(|db, user, update_ws, periphery, build_id| async {
delete_one(db, user, update_ws, periphery, build_id)
.await
.map_err(handle_anyhow_error)
}),
)
}
impl Into<Build> for CreateBuildBody {
fn into(self) -> Build {
Build {
name: self.name,
server_id: self.server_id,
..Default::default()
}
}
}
async fn create(
Extension(db): DbExtension,
Extension(user): RequestUserExtension,
Extension(update_ws): update::UpdateWsSenderExtension,
Json(mut build): Json<Build>,
Json(build): Json<CreateBuildBody>,
) -> anyhow::Result<()> {
let build_server = db
.servers
.find_one_by_id(&build.server_id)
.await
.context("failed at query to find server")?
.ok_or(anyhow!("did not find server with server_id given on build"))?;
let permissions = *build_server.permissions.get(&user.id).ok_or(anyhow!(
"user does not have permissions to create build on this server"
))?;
if permissions != PermissionLevel::Write {
let server = db.get_server(&build.server_id).await?;
let permissions = server.get_user_permissions(&user.id);
if !user.is_admin && permissions != PermissionLevel::Write {
return Err(anyhow!(
"user does not have permissions to create build on this server"
));
}
let mut build: Build = build.into();
build.permissions = [(user.id.clone(), PermissionLevel::Write)]
.into_iter()
.collect();
@@ -55,3 +84,40 @@ async fn create(
};
add_update(update, &db, &update_ws).await
}
async fn delete_one(
Extension(db): DbExtension,
Extension(user): RequestUserExtension,
Extension(update_ws): update::UpdateWsSenderExtension,
Extension(periphery): PeripheryExtension,
Path(BuildId { id }): Path<BuildId>,
) -> anyhow::Result<()> {
let build = db.get_build(&id).await?;
let permissions = build.get_user_permissions(&user.id);
if permissions != PermissionLevel::Write {
return Err(anyhow!(
"user does not have permissions to delete build {} ({id})",
build.name
));
}
let start_ts = unix_timestamp_ms() as i64;
let server = db.get_server(&build.server_id).await?;
// clean up anything left by the build (delete the repo)
db.builds.delete_one(&id).await?;
let update = Update {
target: UpdateTarget::System,
operation: Operation::DeleteDeployment,
start_ts,
end_ts: Some(unix_timestamp_ms() as i64),
operator: user.id.clone(),
log: vec![
// log,
Log::simple(format!(
"deleted build {} on server {}",
build.name, server.name
)),
],
..Default::default()
};
add_update(update, &db, &update_ws).await
}
+39 -10
View File
@@ -1,6 +1,10 @@
use anyhow::{anyhow, Context};
use async_timing_util::unix_timestamp_ms;
use axum::{routing::post, Extension, Json, Router};
use axum::{
extract::Path,
routing::{delete, post},
Extension, Json, Router,
};
use db::DbExtension;
use helpers::handle_anyhow_error;
use mungos::Deserialize;
@@ -13,10 +17,16 @@ use crate::{auth::RequestUserExtension, ws::update};
use super::{add_update, PeripheryExtension};
#[derive(Deserialize)]
pub struct DeploymentIdBody {
pub struct DeploymentId {
id: String,
}
#[derive(Deserialize)]
pub struct CreateDeploymentBody {
name: String,
server_id: String,
}
pub fn router() -> Router {
Router::new()
.route(
@@ -28,21 +38,39 @@ pub fn router() -> Router {
}),
)
.route(
"/delete",
post(|db, user, update_ws, periphery, deployment_id| async {
delete(db, user, update_ws, periphery, deployment_id)
"/delete/:id",
delete(|db, user, update_ws, periphery, deployment_id| async {
delete_one(db, user, update_ws, periphery, deployment_id)
.await
.map_err(handle_anyhow_error)
}),
)
}
impl Into<Deployment> for CreateDeploymentBody {
fn into(self) -> Deployment {
Deployment {
name: self.name,
server_id: self.server_id,
..Default::default()
}
}
}
async fn create(
Extension(db): DbExtension,
Extension(user): RequestUserExtension,
Extension(update_ws): update::UpdateWsSenderExtension,
Json(mut deployment): Json<Deployment>,
Json(deployment): Json<CreateDeploymentBody>,
) -> anyhow::Result<()> {
let server = db.get_server(&deployment.server_id).await?;
let permissions = server.get_user_permissions(&user.id);
if permissions != PermissionLevel::Write {
return Err(anyhow!(
"user does not have permissions to create deployment on this server"
));
}
let mut deployment: Deployment = deployment.into();
deployment.permissions = [(user.id.clone(), PermissionLevel::Write)]
.into_iter()
.collect();
@@ -63,22 +91,23 @@ async fn create(
add_update(update, &db, &update_ws).await
}
async fn delete(
async fn delete_one(
Extension(db): DbExtension,
Extension(user): RequestUserExtension,
Extension(update_ws): update::UpdateWsSenderExtension,
Extension(periphery): PeripheryExtension,
Json(DeploymentIdBody { id }): Json<DeploymentIdBody>,
Path(DeploymentId { id }): Path<DeploymentId>,
) -> anyhow::Result<()> {
let deployment = db.get_deployment(&id).await?;
let permissions = deployment.get_user_permissions(&user.id);
if permissions != PermissionLevel::Write {
return Err(anyhow!(
"user does not have permissions to delete deployment {id}"
"user does not have permissions to delete deployment {} ({id})",
deployment.name
));
}
let server = db.get_server(&deployment.server_id).await?;
let start_ts = unix_timestamp_ms() as i64;
let server = db.get_server(&deployment.server_id).await?;
let log = periphery
.container_remove(&server, &deployment.name)
.await?;
+71 -20
View File
@@ -2,20 +2,32 @@ use anyhow::{anyhow, Context};
use async_timing_util::unix_timestamp_ms;
use axum::{
extract::Path,
routing::{get, post},
routing::{delete, get, post},
Extension, Json, Router,
};
use db::DbExtension;
use helpers::handle_anyhow_error;
use mungos::Deserialize;
use types::{
traits::Permissioned, Operation, PermissionLevel, Server, SystemStats, Update, UpdateTarget,
traits::Permissioned, Log, Operation, PermissionLevel, Server, SystemStats, Update,
UpdateTarget,
};
use crate::{auth::RequestUserExtension, ws::update};
use super::{add_update, PeripheryExtension};
#[derive(Deserialize)]
struct ServerId {
id: String,
}
#[derive(Deserialize)]
struct CreateServerBody {
name: String,
address: String,
}
pub fn router() -> Router {
Router::new()
.route(
@@ -31,9 +43,17 @@ pub fn router() -> Router {
}),
)
.route(
"/stats/:server_id",
get(|db, user, periphery, path| async {
stats(db, user, periphery, path)
"/delete/:id",
delete(|db, user, update_ws, server_id| async {
delete_one(db, user, update_ws, server_id)
.await
.map_err(handle_anyhow_error)
}),
)
.route(
"/stats/:id",
get(|db, user, periphery, server_id| async {
stats(db, user, periphery, server_id)
.await
.map_err(handle_anyhow_error)
}),
@@ -54,10 +74,7 @@ async fn list(
if user.is_admin {
true
} else {
let permissions = *s
.permissions
.get(&user.id)
.unwrap_or(&PermissionLevel::None);
let permissions = s.get_user_permissions(&user.id);
permissions != PermissionLevel::None
}
})
@@ -66,12 +83,28 @@ async fn list(
Ok(Json(servers))
}
impl Into<Server> for CreateServerBody {
fn into(self) -> Server {
Server {
name: self.name,
address: self.address,
..Default::default()
}
}
}
async fn create(
Extension(db): DbExtension,
Extension(user): RequestUserExtension,
Extension(update_ws): update::UpdateWsSenderExtension,
Json(mut server): Json<Server>,
Json(server): Json<CreateServerBody>,
) -> anyhow::Result<()> {
if !user.is_admin {
return Err(anyhow!(
"user does not have permissions to add server (not admin)"
));
}
let mut server: Server = server.into();
server.permissions = [(user.id.clone(), PermissionLevel::Write)]
.into_iter()
.collect();
@@ -92,23 +125,41 @@ async fn create(
add_update(update, &db, &update_ws).await
}
#[derive(Deserialize)]
struct GetStatsPath {
server_id: String,
async fn delete_one(
Extension(db): DbExtension,
Extension(user): RequestUserExtension,
Extension(update_ws): update::UpdateWsSenderExtension,
Path(ServerId { id }): Path<ServerId>,
) -> anyhow::Result<()> {
let server = db.get_server(&id).await?;
let permissions = server.get_user_permissions(&user.id);
if !user.is_admin && permissions != PermissionLevel::Write {
return Err(anyhow!(
"user does not have permissions to delete server {} ({id})",
server.name
));
}
let start_ts = unix_timestamp_ms() as i64;
db.deployments.delete_one(&id).await?;
let update = Update {
target: UpdateTarget::System,
operation: Operation::DeleteServer,
start_ts,
end_ts: Some(unix_timestamp_ms() as i64),
operator: user.id.clone(),
log: vec![Log::simple(format!("deleted server {}", server.name))],
..Default::default()
};
add_update(update, &db, &update_ws).await
}
async fn stats(
Extension(db): DbExtension,
Extension(user): RequestUserExtension,
Extension(periphery): PeripheryExtension,
Path(GetStatsPath { server_id }): Path<GetStatsPath>,
Path(ServerId { id }): Path<ServerId>,
) -> anyhow::Result<Json<SystemStats>> {
let server = db
.servers
.find_one_by_id(&server_id)
.await
.context("failed at query to get server")?
.ok_or(anyhow!("failed to find server with id {server_id}"))?;
let server = db.get_server(&id).await?;
let permissions = server.get_user_permissions(&user.id);
if permissions == PermissionLevel::None {
return Err(anyhow!("user does not have permissions on this server"));