From f2c016701c7cd6803ae87e3e7e41a7b6f0e9d33c Mon Sep 17 00:00:00 2001 From: Jordan Doyle Date: Tue, 07 Sep 2021 16:30:54 +0100 Subject: [PATCH] Don't allow user to download a crate over the API if they don't have the VISIBLE permission :tada: --- chartered-db/src/users.rs | 25 ++++++++++++++++++++++++- chartered-web/src/middleware/auth.rs | 2 +- chartered-web/src/endpoints/cargo_api/download.rs | 18 ++++++++++++++++++ 3 files changed, 41 insertions(+), 4 deletions(-) diff --git a/chartered-db/src/users.rs b/chartered-db/src/users.rs index 5be434e..905ae65 100644 --- a/chartered-db/src/users.rs +++ a/chartered-db/src/users.rs @@ -80,7 +80,7 @@ } bitflags::bitflags! { - #[derive(FromSqlRow, AsExpression)] + #[derive(FromSqlRow, AsExpression, Default)] pub struct UserCratePermissionValue: i32 { const VISIBLE = 0b0000_0000_0000_0000_0000_0000_0000_0001; const PUBLISH_VERSION = 0b0000_0000_0000_0000_0000_0000_0000_0010; @@ -103,13 +103,34 @@ } } -#[derive(Identifiable, Queryable, Associations, PartialEq, Eq, Hash, Debug)] +#[derive(Identifiable, Queryable, Associations, Default, PartialEq, Eq, Hash, Debug)] #[belongs_to(User)] pub struct UserCratePermission { pub id: i32, pub user_id: i32, pub crate_id: i32, pub permissions: UserCratePermissionValue, +} + +impl UserCratePermission { + pub async fn find( + conn: ConnectionPool, + given_user_id: i32, + given_crate_id: i32, + ) -> Result> { + use crate::schema::user_crate_permissions::dsl::{crate_id, user_id}; + + tokio::task::spawn_blocking(move || { + let conn = conn.get()?; + + Ok(crate::schema::user_crate_permissions::table + .filter(user_id.eq(given_user_id)) + .filter(crate_id.eq(given_crate_id)) + .get_result(&conn) + .optional()?) + }) + .await? + } } #[derive(Identifiable, Queryable, Associations, PartialEq, Eq, Hash, Debug)] diff --git a/chartered-web/src/middleware/auth.rs b/chartered-web/src/middleware/auth.rs index af2112d..c3a53c8 100644 --- a/chartered-web/src/middleware/auth.rs +++ a/chartered-web/src/middleware/auth.rs @@ -54,7 +54,7 @@ .await .unwrap() { - Some(user) => user, + Some(user) => std::sync::Arc::new(user), None => { return Ok(Response::builder() .status(StatusCode::UNAUTHORIZED) diff --git a/chartered-web/src/endpoints/cargo_api/download.rs b/chartered-web/src/endpoints/cargo_api/download.rs index 828a864..7f4e64a 100644 --- a/chartered-web/src/endpoints/cargo_api/download.rs +++ a/chartered-web/src/endpoints/cargo_api/download.rs @@ -1,5 +1,9 @@ use axum::extract; -use chartered_db::{crates::Crate, ConnectionPool}; +use chartered_db::{ + crates::Crate, + users::{User, UserCratePermission, UserCratePermissionValue}, + ConnectionPool, +}; use chartered_fs::FileSystem; use std::{str::FromStr, sync::Arc}; @@ -13,10 +17,22 @@ pub async fn handle( extract::Path((_api_key, name, version)): extract::Path<(String, String, String)>, extract::Extension(db): extract::Extension, + extract::Extension(user): extract::Extension>, ) -> Result, Error> { let c = Crate::find_by_name(db.clone(), name) .await? .ok_or(Error::NoCrate)?; + + let perms = UserCratePermission::find(db.clone(), user.id, c.id) + .await? + .unwrap_or_default(); + + if !perms + .permissions + .contains(UserCratePermissionValue::VISIBLE) + { + return Err(Error::NoCrate); + } let version = Arc::new(c) .version(db, version) -- rgit 0.1.3