fix: fix draft permissions (require writer instead of owner)

This commit is contained in:
Ruben Fiszel
2023-08-01 17:02:23 +02:00
parent 654efb7ec4
commit bf57c3a628
6 changed files with 150 additions and 2 deletions
+12
View File
@@ -840,6 +840,18 @@ fn get_on_behalf_of(policy: &Policy) -> Result<(String, String)> {
Ok((permissioned_as, email))
}
pub async fn require_is_writer(authed: &Authed, path: &str, w_id: &str, db: DB) -> Result<()> {
return crate::users::require_is_writer(
authed,
path,
w_id,
db,
"SELECT extra_perms FROM app WHERE path = $1 AND workspace_id = $2",
"app",
)
.await;
}
async fn exists_app(
Extension(db): Extension<DB>,
Path((w_id, path)): Path<(String, StripPath)>,
+21 -1
View File
@@ -42,6 +42,26 @@ pub struct Draft {
pub typ: DraftType,
}
pub async fn require_writer_of_path(
authed: &Authed,
path: &str,
w_id: &str,
db: DB,
kind: &DraftType,
) -> Result<()> {
if authed.is_admin {
return Ok(());
} else if require_owner_of_path(authed, path).is_ok() {
return Ok(());
} else {
match kind {
DraftType::Script => crate::scripts::require_is_writer(authed, path, w_id, db).await,
DraftType::Flow => crate::flows::require_is_writer(authed, path, w_id, db).await,
DraftType::App => crate::apps::require_is_writer(authed, path, w_id, db).await,
}
}
}
async fn create_draft(
authed: Authed,
Extension(db): Extension<DB>,
@@ -53,7 +73,7 @@ async fn create_draft(
let mut tx = user_db.begin(&authed).await?;
require_owner_of_path(&authed, &draft.path)?;
require_writer_of_path(&authed, &draft.path, &w_id, db, &draft.typ).await?;
sqlx::query!(
"INSERT INTO draft
+12
View File
@@ -304,6 +304,18 @@ async fn check_schedule_conflict<'c>(
Ok(())
}
pub async fn require_is_writer(authed: &Authed, path: &str, w_id: &str, db: DB) -> Result<()> {
return crate::users::require_is_writer(
authed,
path,
w_id,
db,
"SELECT extra_perms FROM flow WHERE path = $1 AND workspace_id = $2",
"flow",
)
.await;
}
async fn update_flow(
authed: Authed,
Extension(user_db): Extension<UserDB>,
+14
View File
@@ -738,6 +738,20 @@ async fn get_deployment_status(
Ok(Json(status))
}
pub async fn require_is_writer(authed: &Authed, path: &str, w_id: &str, db: DB) -> Result<()> {
return crate::users::require_is_writer(
authed,
path,
w_id,
db,
"SELECT extra_perms FROM script WHERE path = $1 AND workspace_id = $2 \
AND created_at = (SELECT max(created_at) FROM script WHERE path = $1 AND \
workspace_id = $2)",
"script",
)
.await;
}
async fn archive_script_by_path(
authed: Authed,
Extension(webhook): Extension<WebhookShared>,
+86
View File
@@ -1041,6 +1041,92 @@ pub fn require_owner_of_path(authed: &Authed, path: &str) -> Result<()> {
}
}
pub fn get_perm_in_extra_perms_for_authed(v: serde_json::Value, authed: &Authed) -> Option<bool> {
match v {
serde_json::Value::Object(obj) => {
let mut keys = vec![format!("u/{}", authed.username)];
for g in authed.groups.iter() {
keys.push(format!("g/{}", g));
}
let mut res = None;
for k in keys {
if let Some(v) = obj.get(&k) {
if let Some(v) = v.as_bool() {
if v {
return Some(true);
}
res = Some(v);
}
}
}
res
}
_ => None,
}
}
pub async fn require_is_writer(
authed: &Authed,
path: &str,
w_id: &str,
db: DB,
query: &str,
kind: &str,
) -> Result<()> {
if authed.is_admin {
return Ok(());
}
if !path.is_empty() {
if require_owner_of_path(authed, path).is_ok() {
return Ok(());
}
if path.starts_with("f/") && path.split('/').count() >= 2 {
let folder = path.split('/').nth(1).unwrap();
let extra_perms = sqlx::query_scalar!(
"SELECT extra_perms FROM folder WHERE name = $1 AND workspace_id = $2",
folder,
w_id
)
.fetch_optional(&db)
.await?;
if let Some(perms) = extra_perms {
let is_folder_writer =
get_perm_in_extra_perms_for_authed(perms, authed).unwrap_or(false);
if is_folder_writer {
return Ok(());
}
}
}
let extra_perms = sqlx::query_scalar(query)
.bind(path)
.bind(w_id)
.fetch_optional(&db)
.await?;
if let Some(perms) = extra_perms {
let perm = get_perm_in_extra_perms_for_authed(perms, authed);
match perm {
Some(true) => Ok(()),
Some(false) => Err(Error::BadRequest(format!(
"User {} is not a writer of {kind} path {path}",
authed.username
))),
None => Err(Error::BadRequest(format!(
"User {} has neither read or write permission on {kind} {path}",
authed.username
))),
}
} else {
Err(Error::BadRequest(format!(
"{path} does not exist yet and user {} is not an owner of the parent folder",
authed.username
)))
}
} else {
Err(Error::BadRequest(format!(
"Cannot be writer of an empty path"
)))
}
}
async fn whois(
Extension(db): Extension<DB>,
Path((w_id, username)): Path<(String, String)>,
@@ -53,7 +53,11 @@
}
async function loadInstanceGroup(): Promise<void> {
instance_group = await GroupService.getInstanceGroup({ name })
try {
instance_group = await GroupService.getInstanceGroup({ name })
} catch (e) {
instance_group = undefined
}
}
async function loadGroup(): Promise<void> {