diff --git a/.github/workflows/rust-docker.yml b/.github/workflows/rust-docker.yml index a46adf67..cd628904 100644 --- a/.github/workflows/rust-docker.yml +++ b/.github/workflows/rust-docker.yml @@ -29,7 +29,7 @@ jobs: - uses: docker/setup-buildx-action@v1 # main docker build - - run: echo "BRANCH_NAME=${GITHUB_REF#refs/heads/}" >> $GITHUB_ENV + - run: echo "BRANCH_NAME=${GITHUB_REF#refs/heads/}" | sed 's|/|-|g' >> $GITHUB_ENV - uses: docker/build-push-action@v2 with: # https://github.com/docker/build-push-action/issues/378 diff --git a/crates/api/src/auth.rs b/crates/api/src/auth.rs index 3ced9675..156ac254 100644 --- a/crates/api/src/auth.rs +++ b/crates/api/src/auth.rs @@ -28,18 +28,24 @@ impl AccessLevel { pub struct AuthState { system_id: Option, app_id: Option, - api_key_id: Option, - access_level: AccessLevel, + api_key_id: Option, + access_level: AccessLevel, internal: bool, } impl AuthState { - pub fn new(system_id: Option, app_id: Option, api_key_id: Option, access_level: AccessLevel, internal: bool) -> Self { + pub fn new( + system_id: Option, + app_id: Option, + api_key_id: Option, + access_level: AccessLevel, + internal: bool, + ) -> Self { Self { system_id, app_id, - api_key_id, - access_level, + api_key_id, + access_level, internal, } } @@ -56,9 +62,9 @@ impl AuthState { self.api_key_id } - pub fn access_level(&self) -> AccessLevel { - self.access_level.clone() - } + pub fn access_level(&self) -> AccessLevel { + self.access_level.clone() + } pub fn internal(&self) -> bool { self.internal diff --git a/crates/api/src/endpoints/internal.rs b/crates/api/src/endpoints/internal.rs index 0d62ba9a..1bd1918a 100644 --- a/crates/api/src/endpoints/internal.rs +++ b/crates/api/src/endpoints/internal.rs @@ -1,12 +1,12 @@ -use crate::{util::json_err, AuthState, ApiContext}; -use pluralkit_models::{ApiKeyType, PKApiKey, PKSystem, SystemId}; +use crate::{util::json_err, ApiContext, AuthState}; use pk_macros::api_internal_endpoint; +use pluralkit_models::{ApiKeyType, PKApiKey, PKSystem, SystemId}; use axum::{ extract::State, http::StatusCode, response::{IntoResponse, Json, Response}, - Extension, + Extension, }; use sqlx::Postgres; @@ -23,7 +23,7 @@ pub struct NewApiKeyRequestData { #[api_internal_endpoint] pub async fn create_api_key_user( State(ctx): State, - Extension(auth): Extension, + Extension(auth): Extension, Json(req): Json, ) -> Response { let system: Option = sqlx::query_as("select * from systems where id = $1") @@ -76,7 +76,8 @@ pub async fn create_api_key_user( "valid": true, })) .expect("should not error"), - ).into_response()); + ) + .into_response()); } let token: PKApiKey = sqlx::query_as( @@ -110,5 +111,6 @@ pub async fn create_api_key_user( "token": token, })) .expect("should not error"), - ).into_response()) + ) + .into_response()) } diff --git a/crates/api/src/endpoints/private.rs b/crates/api/src/endpoints/private.rs index cebcaaf2..5a1661f1 100644 --- a/crates/api/src/endpoints/private.rs +++ b/crates/api/src/endpoints/private.rs @@ -1,6 +1,6 @@ use crate::{util::json_err, ApiContext}; use libpk::config; -use pluralkit_models::{PrivacyLevel, PKApiKey, PKSystem, PKSystemConfig}; +use pluralkit_models::{PKApiKey, PKSystem, PKSystemConfig, PrivacyLevel}; use axum::{ extract::{self, State}, @@ -201,5 +201,6 @@ pub async fn discord_callback( "token": token, })) .expect("should not error"), - ).into_response()) + ) + .into_response()) } diff --git a/crates/api/src/main.rs b/crates/api/src/main.rs index ffc75542..a0892b7f 100644 --- a/crates/api/src/main.rs +++ b/crates/api/src/main.rs @@ -1,6 +1,9 @@ #![feature(let_chains)] -use auth::{AuthState, INTERNAL_APPID_HEADER, INTERNAL_SYSTEMID_HEADER, INTERNAL_TOKENID_HEADER, INTERNAL_PRIVACYLEVEL_HEADER}; +use auth::{ + AuthState, INTERNAL_APPID_HEADER, INTERNAL_PRIVACYLEVEL_HEADER, INTERNAL_SYSTEMID_HEADER, + INTERNAL_TOKENID_HEADER, +}; use axum::{ body::Body, extract::{Request as ExtractRequest, State}, @@ -15,8 +18,8 @@ use hyper_util::{ }; use jsonwebtoken::{DecodingKey, EncodingKey}; -use tracing::{error, info}; use pk_macros::api_endpoint; +use tracing::{error, info}; mod auth; mod endpoints; @@ -57,21 +60,30 @@ async fn rproxy( headers.remove(INTERNAL_SYSTEMID_HEADER); headers.remove(INTERNAL_APPID_HEADER); - headers.remove(INTERNAL_TOKENID_HEADER); - headers.remove(INTERNAL_PRIVACYLEVEL_HEADER); + headers.remove(INTERNAL_TOKENID_HEADER); + headers.remove(INTERNAL_PRIVACYLEVEL_HEADER); if let Some(sid) = auth.system_id() { headers.append(INTERNAL_SYSTEMID_HEADER, sid.into()); - headers.append(INTERNAL_PRIVACYLEVEL_HEADER, HeaderValue::from_str(&auth.access_level().privacy_level().to_string())?); + headers.append( + INTERNAL_PRIVACYLEVEL_HEADER, + HeaderValue::from_str(&auth.access_level().privacy_level().to_string())?, + ); } if let Some(aid) = auth.app_id() { - headers.append(INTERNAL_APPID_HEADER, HeaderValue::from_str(&format!("{}", aid))?); + headers.append( + INTERNAL_APPID_HEADER, + HeaderValue::from_str(&format!("{}", aid))?, + ); + } + + if let Some(tid) = auth.api_key_id() { + headers.append( + INTERNAL_TOKENID_HEADER, + HeaderValue::from_str(&format!("{}", tid))?, + ); } - - if let Some(tid) = auth.api_key_id() { - headers.append(INTERNAL_TOKENID_HEADER, HeaderValue::from_str(&format!("{}", tid))?); - } Ok(ctx.rproxy_client.request(req).await?.into_response()) } diff --git a/crates/api/src/middleware/auth.rs b/crates/api/src/middleware/auth.rs index 2a1c757d..fa959198 100644 --- a/crates/api/src/middleware/auth.rs +++ b/crates/api/src/middleware/auth.rs @@ -1,19 +1,19 @@ use axum::{ - extract::{Request, State, MatchedPath}, + extract::{MatchedPath, Request, State}, http::StatusCode, middleware::Next, response::Response, }; -use uuid::Uuid; use subtle::ConstantTimeEq; +use uuid::Uuid; -use tracing::error; use sqlx::Postgres; +use tracing::error; -use pluralkit_models::{ApiKeyType, PKApiKey}; use crate::auth::{AccessLevel, AuthState}; use crate::{util::json_err, ApiContext}; +use pluralkit_models::{ApiKeyType, PKApiKey}; pub fn is_part_path<'a, 'b>(part: &'a str, endpoint: &'b str) -> bool { if !endpoint.starts_with("/v2/") { @@ -113,7 +113,7 @@ pub fn apikey_can_access(token: &PKApiKey, method: String, endpoint: String) -> } pub async fn auth(State(ctx): State, mut req: Request, next: Next) -> Response { - let endpoint = req + let endpoint = req .extensions() .get::() .cloned() @@ -122,8 +122,8 @@ pub async fn auth(State(ctx): State, mut req: Request, next: Next) - let mut authed_system_id: Option = None; let mut authed_app_id: Option = None; - let mut authed_api_key_id: Option = None; - let mut access_level = AccessLevel::None; + let mut authed_api_key_id: Option = None; + let mut access_level = AccessLevel::None; // fetch user authorization if let Some(system_auth_header) = req @@ -131,10 +131,12 @@ pub async fn auth(State(ctx): State, mut req: Request, next: Next) - .get("authorization") .map(|h| h.to_str().ok()) .flatten() - { - if system_auth_header.starts_with("Bearer ") - && let Some(tid) = - PKApiKey::parse_header_str(system_auth_header[7..].to_string(), &ctx.token_publickey) + { + if system_auth_header.starts_with("Bearer ") + && let Some(tid) = PKApiKey::parse_header_str( + system_auth_header[7..].to_string(), + &ctx.token_publickey, + ) && let Some(token) = sqlx::query_as::("select * from api_keys where id = $1") .bind(&tid) @@ -142,11 +144,10 @@ pub async fn auth(State(ctx): State, mut req: Request, next: Next) - .await .expect("failed to query apitoken in postgres") { - authed_system_id = Some(token.system); - authed_api_key_id = Some(tid); - access_level = apikey_can_access(&token, req.method().to_string(), endpoint.clone()); - } - else if let Some(system_id) = + authed_system_id = Some(token.system); + authed_api_key_id = Some(tid); + access_level = apikey_can_access(&token, req.method().to_string(), endpoint.clone()); + } else if let Some(system_id) = match libpk::db::repository::legacy_token_auth(&ctx.db, system_auth_header).await { Ok(val) => val, Err(err) => { @@ -157,11 +158,11 @@ pub async fn auth(State(ctx): State, mut req: Request, next: Next) - ); } } - { - authed_system_id = Some(system_id); - access_level = AccessLevel::Full; - } - } + { + authed_system_id = Some(system_id); + access_level = AccessLevel::Full; + } + } // fetch app authorization if let Some(app_auth_header) = req @@ -170,7 +171,7 @@ pub async fn auth(State(ctx): State, mut req: Request, next: Next) - .map(|h| h.to_str().ok()) .flatten() && let Some(app_id) = - match libpk::db::repository::app_token_auth(&ctx.db, app_auth_header).await { + match libpk::db::repository::app_token_auth(&ctx.db, app_auth_header).await { Ok(val) => val, Err(err) => { error!(?err, "failed to query authorization token in postgres"); @@ -199,8 +200,13 @@ pub async fn auth(State(ctx): State, mut req: Request, next: Next) - false }; - req.extensions_mut() - .insert(AuthState::new(authed_system_id, authed_app_id, authed_api_key_id, access_level, internal)); + req.extensions_mut().insert(AuthState::new( + authed_system_id, + authed_app_id, + authed_api_key_id, + access_level, + internal, + )); next.run(req).await } diff --git a/crates/api/src/middleware/ratelimit.rs b/crates/api/src/middleware/ratelimit.rs index a0889ea7..756ac85a 100644 --- a/crates/api/src/middleware/ratelimit.rs +++ b/crates/api/src/middleware/ratelimit.rs @@ -12,9 +12,9 @@ use sqlx::Postgres; use tracing::{debug, error, info, warn}; use crate::{ - ApiContext, auth::AuthState, util::{header_or_unknown, json_err}, + ApiContext, }; use pluralkit_models::PKExternalApp; diff --git a/crates/libpk/src/db/repository/auth.rs b/crates/libpk/src/db/repository/auth.rs index 6e33621e..25c4053b 100644 --- a/crates/libpk/src/db/repository/auth.rs +++ b/crates/libpk/src/db/repository/auth.rs @@ -22,10 +22,10 @@ struct LegacyTokenDbResponse { } pub async fn app_token_auth( - pool: &sqlx::postgres::PgPool, - token: &str, + pool: &sqlx::postgres::PgPool, + token: &str, ) -> anyhow::Result> { - let mut app: Vec = + let mut app: Vec = sqlx::query_as("select id from external_apps where api_rl_token = $1") .bind(token) .fetch_all(pool) diff --git a/crates/macros/src/api.rs b/crates/macros/src/api.rs index 3eeb2c5d..6569f447 100644 --- a/crates/macros/src/api.rs +++ b/crates/macros/src/api.rs @@ -9,7 +9,7 @@ fn pretty_print(ts: &proc_macro2::TokenStream) -> String { pub fn macro_impl( _args: proc_macro::TokenStream, input: proc_macro::TokenStream, - is_internal: bool, + is_internal: bool, ) -> proc_macro::TokenStream { let input = parse_macro_input!(input as ItemFn); @@ -35,15 +35,15 @@ pub fn macro_impl( }) .collect(); - let internal_res = if is_internal { - quote! { - if !auth.internal() { - return crate::error::FORBIDDEN_INTERNAL_ROUTE.into_response(); - } - } - } else { - quote!() - }; + let internal_res = if is_internal { + quote! { + if !auth.internal() { + return crate::error::FORBIDDEN_INTERNAL_ROUTE.into_response(); + } + } + } else { + quote!() + }; let res = quote! { #[allow(unused_mut)] @@ -52,7 +52,7 @@ pub fn macro_impl( #fn_body } - #internal_res + #internal_res match inner(#(#pms),*).await { Ok(res) => res.into_response(), Err(err) => err.into_response(), diff --git a/crates/models/src/lib.rs b/crates/models/src/lib.rs index f589f5da..39c5c1dc 100644 --- a/crates/models/src/lib.rs +++ b/crates/models/src/lib.rs @@ -21,12 +21,12 @@ impl From for PrivacyLevel { } impl PrivacyLevel { - pub fn to_string(&self) -> String { - match self { - PrivacyLevel::Public => "public".into(), - PrivacyLevel::Private => "private".into(), - } - } + pub fn to_string(&self) -> String { + match self { + PrivacyLevel::Public => "public".into(), + PrivacyLevel::Private => "private".into(), + } + } } macro_rules! model {