diff --git a/src/auth.rs b/src/auth.rs index b86d461b..2fcd9740 100644 --- a/src/auth.rs +++ b/src/auth.rs @@ -14,7 +14,9 @@ use std::{ net::IpAddr, }; -use crate::db::models::{AttachmentId, CipherId, CollectionId, DeviceId, MembershipId, OrganizationId, UserId}; +use crate::db::models::{ + AttachmentId, CipherId, CollectionId, DeviceId, MembershipId, OrgApiKeyId, OrganizationId, UserId, +}; use crate::{error::Error, CONFIG}; const JWT_ALGORITHM: Algorithm = Algorithm::RS256; @@ -264,20 +266,23 @@ pub struct OrgApiKeyLoginJwtClaims { // Issuer pub iss: String, // Subject - pub sub: String, + pub sub: OrgApiKeyId, pub client_id: String, pub client_sub: OrganizationId, pub scope: Vec, } -pub fn generate_organization_api_key_login_claims(uuid: String, org_id: OrganizationId) -> OrgApiKeyLoginJwtClaims { +pub fn generate_organization_api_key_login_claims( + org_api_key_uuid: OrgApiKeyId, + org_id: OrganizationId, +) -> OrgApiKeyLoginJwtClaims { let time_now = Utc::now(); OrgApiKeyLoginJwtClaims { nbf: time_now.timestamp(), exp: (time_now + TimeDelta::try_hours(1).unwrap()).timestamp(), iss: JWT_ORG_API_KEY_ISSUER.to_string(), - sub: uuid, + sub: org_api_key_uuid, client_id: format!("organization.{}", org_id), client_sub: org_id, scope: vec!["api.organization".into()], diff --git a/src/db/models/mod.rs b/src/db/models/mod.rs index 9b2105a8..2817fb56 100644 --- a/src/db/models/mod.rs +++ b/src/db/models/mod.rs @@ -28,7 +28,8 @@ pub use self::folder::{Folder, FolderCipher, FolderId}; pub use self::group::{CollectionGroup, Group, GroupId, GroupUser}; pub use self::org_policy::{OrgPolicy, OrgPolicyErr, OrgPolicyType}; pub use self::organization::{ - Membership, MembershipId, MembershipStatus, MembershipType, Organization, OrganizationApiKey, OrganizationId, + Membership, MembershipId, MembershipStatus, MembershipType, OrgApiKeyId, Organization, OrganizationApiKey, + OrganizationId, }; pub use self::send::{Send, SendType}; pub use self::two_factor::{TwoFactor, TwoFactorType}; diff --git a/src/db/models/organization.rs b/src/db/models/organization.rs index 15bd25af..6b37d302 100644 --- a/src/db/models/organization.rs +++ b/src/db/models/organization.rs @@ -48,7 +48,7 @@ db_object! { #[diesel(table_name = organization_api_key)] #[diesel(primary_key(uuid, org_uuid))] pub struct OrganizationApiKey { - pub uuid: String, + pub uuid: OrgApiKeyId, pub org_uuid: OrganizationId, pub atype: i32, pub api_key: String, @@ -263,7 +263,7 @@ impl Membership { impl OrganizationApiKey { pub fn new(org_uuid: OrganizationId, api_key: String) -> Self { Self { - uuid: crate::util::get_uuid(), + uuid: OrgApiKeyId(crate::util::get_uuid()), org_uuid, atype: 0, // Type 0 is the default and only type we support currently @@ -1107,6 +1107,54 @@ impl<'r> FromParam<'r> for OrganizationId { } } +#[derive(DieselNewType, FromForm, Clone, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)] +pub struct OrgApiKeyId(String); + +impl AsRef for OrgApiKeyId { + fn as_ref(&self) -> &str { + &self.0 + } +} + +impl Deref for OrgApiKeyId { + type Target = str; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl Borrow for OrgApiKeyId { + fn borrow(&self) -> &str { + &self.0 + } +} + +impl Display for OrgApiKeyId { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.0) + } +} + +impl From for OrgApiKeyId { + fn from(raw: String) -> Self { + Self(raw) + } +} + +impl<'r> FromParam<'r> for OrgApiKeyId { + type Error = (); + + #[inline(always)] + fn from_param(param: &'r str) -> Result { + if param.chars().all(|c| matches!(c, 'a'..='z' | 'A'..='Z' |'0'..='9' | '-')) { + Ok(Self(param.to_string())) + } else { + Err(()) + } + } +} + #[derive(DieselNewType, FromForm, Clone, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)] pub struct MembershipId(String);