mirror of
https://github.com/moghtech/komodo.git
synced 2026-08-03 08:56:41 -05:00
basic add permissions
This commit is contained in:
@@ -26,7 +26,7 @@ pub fn router() -> Router {
|
||||
async fn create(
|
||||
Extension(db): DbExtension,
|
||||
Extension(user): RequestUserExtension,
|
||||
Extension(update_ws): update::WsSenderExtension,
|
||||
Extension(update_ws): update::UpdateWsSenderExtension,
|
||||
Json(mut build): Json<Build>,
|
||||
) -> anyhow::Result<()> {
|
||||
let build_server = db
|
||||
|
||||
@@ -23,7 +23,7 @@ pub fn router() -> Router {
|
||||
async fn create(
|
||||
Extension(db): DbExtension,
|
||||
Extension(user): RequestUserExtension,
|
||||
Extension(update_ws): update::WsSenderExtension,
|
||||
Extension(update_ws): update::UpdateWsSenderExtension,
|
||||
Json(mut deployment): Json<Deployment>,
|
||||
) -> anyhow::Result<()> {
|
||||
deployment.permissions = [(user.id.clone(), PermissionLevel::Write)]
|
||||
|
||||
+3
-1
@@ -15,6 +15,7 @@ use crate::{
|
||||
|
||||
mod build;
|
||||
mod deployment;
|
||||
mod permissions;
|
||||
mod server;
|
||||
|
||||
type PeripheryExtension = Extension<Arc<PeripheryClient>>;
|
||||
@@ -28,6 +29,7 @@ pub fn router() -> Router {
|
||||
.nest("/build", build::router())
|
||||
.nest("/deployment", deployment::router())
|
||||
.nest("/server", server::router())
|
||||
.nest("/permissions", permissions::router())
|
||||
.layer(Extension(Arc::new(PeripheryClient::new())))
|
||||
.layer(middleware::from_fn(auth_request))
|
||||
}
|
||||
@@ -48,7 +50,7 @@ async fn get_user(
|
||||
async fn add_update(
|
||||
mut update: Update,
|
||||
db: &DbClient,
|
||||
update_ws: &update::WsSender,
|
||||
update_ws: &update::UpdateWsSender,
|
||||
) -> anyhow::Result<()> {
|
||||
let update_id = db
|
||||
.updates
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
use anyhow::{anyhow, Context};
|
||||
use axum::{routing::post, Extension, Json, Router};
|
||||
use db::DbExtension;
|
||||
use helpers::handle_anyhow_error;
|
||||
use mungos::{doc, Deserialize, Update};
|
||||
use types::{PermissionLevel, PermissionsTarget, Server};
|
||||
|
||||
use crate::{auth::RequestUserExtension, helpers::get_user_permissions};
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct PermissionsUpdate {
|
||||
user_id: String,
|
||||
permission: PermissionLevel,
|
||||
target_type: PermissionsTarget,
|
||||
target_id: String,
|
||||
}
|
||||
|
||||
pub fn router() -> Router {
|
||||
Router::new().route(
|
||||
"/add",
|
||||
post(|db, user, update| async {
|
||||
add_permissions(db, user, update)
|
||||
.await
|
||||
.map_err(handle_anyhow_error)
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
async fn add_permissions(
|
||||
Extension(db): DbExtension,
|
||||
Extension(user): RequestUserExtension,
|
||||
Json(update): Json<PermissionsUpdate>,
|
||||
) -> anyhow::Result<()> {
|
||||
match update.target_type {
|
||||
PermissionsTarget::Server => {
|
||||
let server = db
|
||||
.servers
|
||||
.find_one_by_id(&update.target_id)
|
||||
.await
|
||||
.context("failed at find server query")?
|
||||
.ok_or(anyhow!(
|
||||
"failed to find a server with id {}",
|
||||
update.target_id
|
||||
))?;
|
||||
let permissions = get_user_permissions(&user.id, &server.permissions);
|
||||
if user.is_admin || permissions == PermissionLevel::Write {
|
||||
let target_user = db
|
||||
.users
|
||||
.find_one_by_id(&update.user_id)
|
||||
.await
|
||||
.context("failed at find target user query")?
|
||||
.ok_or(anyhow!("failed to find a user with id {}", update.user_id))?;
|
||||
if !target_user.enabled {
|
||||
return Err(anyhow!("target user not enabled"));
|
||||
}
|
||||
db.servers
|
||||
.update_one::<Server>(&update.target_id, Update::Set(doc! {
|
||||
format!("permissions.{}", update.user_id): update.permission.to_string()
|
||||
}))
|
||||
.await?;
|
||||
Ok(())
|
||||
} else {
|
||||
Err(anyhow!("user is not authorized for this action"))
|
||||
}
|
||||
}
|
||||
PermissionsTarget::Deployment => {
|
||||
todo!()
|
||||
}
|
||||
PermissionsTarget::Build => {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -57,7 +57,7 @@ async fn list(
|
||||
async fn create(
|
||||
Extension(db): DbExtension,
|
||||
Extension(user): RequestUserExtension,
|
||||
Extension(update_ws): update::WsSenderExtension,
|
||||
Extension(update_ws): update::UpdateWsSenderExtension,
|
||||
Json(mut server): Json<Server>,
|
||||
) -> anyhow::Result<()> {
|
||||
server.permissions = [(user.id.clone(), PermissionLevel::Write)]
|
||||
|
||||
+1
-1
@@ -25,5 +25,5 @@ fn print_startup_log(config: &CoreConfig) {
|
||||
}
|
||||
|
||||
pub fn default_config_path() -> String {
|
||||
"/config/config.json".to_string()
|
||||
"/config/config.toml".to_string()
|
||||
}
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
use types::{PermissionLevel, PermissionsMap};
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! response {
|
||||
($x:expr) => {
|
||||
Ok::<_, (axum::http::StatusCode, String)>($x)
|
||||
};
|
||||
}
|
||||
|
||||
pub fn get_user_permissions(user_id: &str, permissions: &PermissionsMap) -> PermissionLevel {
|
||||
*permissions.get(user_id).unwrap_or(&PermissionLevel::None)
|
||||
}
|
||||
|
||||
+1
-2
@@ -21,9 +21,8 @@ async fn main() {
|
||||
let app = Router::new()
|
||||
.nest("/api", api::router())
|
||||
.nest("/auth", auth::router(&config))
|
||||
.nest("/ws", ws::router())
|
||||
.nest("/ws", ws::router(reciever))
|
||||
.layer(sender)
|
||||
.layer(reciever)
|
||||
.layer(DbClient::extension(config.mongo.clone()).await)
|
||||
.layer(JwtClient::extension(&config));
|
||||
|
||||
|
||||
+5
-5
@@ -6,10 +6,10 @@ pub mod update;
|
||||
|
||||
pub use update::make_update_ws_sender_reciver;
|
||||
|
||||
pub fn router() -> Router {
|
||||
Router::new().route("/update", get(update::ws_handler))
|
||||
}
|
||||
use self::update::UpdateWsRecieverExtension;
|
||||
|
||||
fn user_permissions(user_id: &str, permissions: &PermissionsMap) -> PermissionLevel {
|
||||
*permissions.get(user_id).unwrap_or(&PermissionLevel::None)
|
||||
pub fn router(reciever: UpdateWsRecieverExtension) -> Router {
|
||||
Router::new()
|
||||
.route("/update", get(update::ws_handler))
|
||||
.layer(reciever)
|
||||
}
|
||||
|
||||
+15
-20
@@ -21,17 +21,18 @@ use tokio::{
|
||||
},
|
||||
};
|
||||
use tokio_util::sync::CancellationToken;
|
||||
use types::{PermissionLevel, Update, User, UpdateTarget};
|
||||
use types::{PermissionLevel, Update, UpdateTarget, User};
|
||||
|
||||
use crate::auth::{JwtClient, JwtExtension};
|
||||
use crate::{
|
||||
auth::{JwtClient, JwtExtension},
|
||||
helpers::get_user_permissions,
|
||||
};
|
||||
|
||||
use super::user_permissions;
|
||||
pub type UpdateWsSender = Arc<Mutex<Sender<Update>>>;
|
||||
pub type UpdateWsSenderExtension = Extension<UpdateWsSender>;
|
||||
|
||||
pub type WsSender = Arc<Mutex<Sender<Update>>>;
|
||||
pub type WsSenderExtension = Extension<WsSender>;
|
||||
|
||||
pub type WsReciever = Receiver<Update>;
|
||||
pub type WsRecieverExtension = Extension<WsReciever>;
|
||||
pub type UpdateWsReciever = Receiver<Update>;
|
||||
pub type UpdateWsRecieverExtension = Extension<UpdateWsReciever>;
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct UpdateMsg {
|
||||
@@ -58,7 +59,7 @@ impl UpdateMsg {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn make_update_ws_sender_reciver() -> (WsSenderExtension, WsRecieverExtension) {
|
||||
pub fn make_update_ws_sender_reciver() -> (UpdateWsSenderExtension, UpdateWsRecieverExtension) {
|
||||
let (sender, reciever) = watch::channel(Default::default());
|
||||
(
|
||||
Extension(Arc::new(Mutex::new((sender)))),
|
||||
@@ -69,7 +70,7 @@ pub fn make_update_ws_sender_reciver() -> (WsSenderExtension, WsRecieverExtensio
|
||||
pub async fn ws_handler(
|
||||
Extension(jwt_client): JwtExtension,
|
||||
Extension(db_client): DbExtension,
|
||||
Extension(mut reciever): WsRecieverExtension,
|
||||
Extension(mut reciever): UpdateWsRecieverExtension,
|
||||
ws: WebSocketUpgrade,
|
||||
) -> impl IntoResponse {
|
||||
ws.on_upgrade(|socket| async move {
|
||||
@@ -101,13 +102,7 @@ pub async fn ws_handler(
|
||||
}
|
||||
let user = user.unwrap().unwrap(); // already handle cases where this panics in the above early return
|
||||
let update = reciever.borrow().to_owned();
|
||||
match user_can_see_update(
|
||||
&user,
|
||||
&user_id,
|
||||
&update.target,
|
||||
&db_client,
|
||||
)
|
||||
.await
|
||||
match user_can_see_update(&user, &user_id, &update.target, &db_client).await
|
||||
{
|
||||
Ok(_) => {
|
||||
let _ = ws_sender
|
||||
@@ -216,7 +211,7 @@ async fn user_can_see_update(
|
||||
.await
|
||||
.context(format!("failed at query to get server at {server_id}"))?
|
||||
.ok_or(anyhow!("did not server with id {server_id}"))?;
|
||||
if user_permissions(user_id, &server.permissions) != PermissionLevel::None {
|
||||
if get_user_permissions(user_id, &server.permissions) != PermissionLevel::None {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(anyhow!("user does not have permissions on server"))
|
||||
@@ -231,7 +226,7 @@ async fn user_can_see_update(
|
||||
"failed at query to get deployment at {deployment_id}"
|
||||
))?
|
||||
.ok_or(anyhow!("did not deployment with id {deployment_id}"))?;
|
||||
if user_permissions(user_id, &deployment.permissions) != PermissionLevel::None {
|
||||
if get_user_permissions(user_id, &deployment.permissions) != PermissionLevel::None {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(anyhow!("user does not have permissions on deployment"))
|
||||
@@ -244,7 +239,7 @@ async fn user_can_see_update(
|
||||
.await
|
||||
.context(format!("failed at query to get build at {build_id}"))?
|
||||
.ok_or(anyhow!("did not build with id {build_id}"))?;
|
||||
if user_permissions(user_id, &build.permissions) != PermissionLevel::None {
|
||||
if get_user_permissions(user_id, &build.permissions) != PermissionLevel::None {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(anyhow!("user does not have permissions on build"))
|
||||
|
||||
+14
-5
@@ -269,10 +269,6 @@ pub struct CoreConfig {
|
||||
#[serde(default = "default_core_port")]
|
||||
pub port: u16,
|
||||
|
||||
// github integration
|
||||
pub github_oauth: OauthCredentials,
|
||||
pub github_webhook_secret: Option<String>,
|
||||
|
||||
// jwt config
|
||||
pub jwt_secret: String,
|
||||
#[serde(default = "default_jwt_valid_for")]
|
||||
@@ -281,6 +277,10 @@ pub struct CoreConfig {
|
||||
// integration with slack app
|
||||
pub slack_url: Option<String>,
|
||||
|
||||
// github integration
|
||||
pub github_oauth: OauthCredentials,
|
||||
pub github_webhook_secret: Option<String>,
|
||||
|
||||
// mongo config
|
||||
pub mongo: MongoConfig,
|
||||
}
|
||||
@@ -386,7 +386,7 @@ pub enum UpdateTarget {
|
||||
System,
|
||||
Build(String),
|
||||
Deployment(String),
|
||||
Server(String)
|
||||
Server(String),
|
||||
}
|
||||
|
||||
impl Default for UpdateTarget {
|
||||
@@ -443,6 +443,15 @@ pub enum PermissionLevel {
|
||||
Write,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Display, EnumString, PartialEq, Hash, Eq, Clone, Copy)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
#[strum(serialize_all = "snake_case")]
|
||||
pub enum PermissionsTarget {
|
||||
Server,
|
||||
Deployment,
|
||||
Build,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Display, EnumString, PartialEq, Hash, Eq, Clone, Copy)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
#[strum(serialize_all = "snake_case")]
|
||||
|
||||
Reference in New Issue
Block a user