use base64::{engine::general_purpose::URL_SAFE as base64url, Engine}; use serde::{Serialize, Deserialize}; use tetratto_shared::hash::hash; use super::{Result, Error}; #[derive(Clone, Debug, Serialize, Deserialize)] pub struct AuthGrant { /// The ID of the application associated with this grant. pub app: usize, /// The code challenge for PKCE verifiers associated with this grant. /// /// This challenge is *all* that is required to refresh this grant's auth token. /// While there can only be one token at a time, it can be refreshed whenever as long /// as the provided verifier matches that of the challenge. /// /// The challenge should never be changed. To change the challenge, the grant /// should be removed and recreated. pub challenge: String, /// The encoding method for the initial verifier in the challenge. pub method: PkceChallengeMethod, /// The access token associated with the account. This is **not** the same as /// regular account access tokens, as the token can only be used with the requested `scopes`. pub token: String, /// The time in which the token was last refreshed. Tokens should stop being /// accepted after a week has passed since this time. pub last_updated: usize, /// Scopes define what the grant's token is actually allowed to do. /// /// No scope shall ever be allowed to change scopes or manage grants on behalf of the user. /// A regular user token **must** be provided to manage grants. pub scopes: Vec, } #[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)] pub enum PkceChallengeMethod { S256, } #[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)] pub enum AppScope { /// Read the profile of other users on behalf of the user. UserReadProfiles, /// Read the user's profile (username, bio, etc). UserReadProfile, /// Read the user's settings. UserReadSettings, /// Read the user's sessions and info. UserReadSessions, /// Read posts as the user. UserReadPosts, /// Read messages as the user. UserReadMessages, /// Read drafts as the user. UserReadDrafts, /// Read the user's communities. UserReadCommunities, /// Connect to sockets on the user's behalf. UserReadSockets, /// Read the user's notifications. UserReadNotifications, /// Read the user's requests. UserReadRequests, /// Read questions as the user. UserReadQuestions, /// Read the user's stacks. UserReadStacks, /// Read the user's journals. UserReadJournals, /// Read the user's notes. UserReadNotes, /// Read the user's links. UserReadLinks, /// Create posts as the user. UserCreatePosts, /// Create messages as the user. UserCreateMessages, /// Ask questions as the user. UserCreateQuestions, /// Create IP blocks as the user. UserCreateIpBlock, /// Create drafts on behalf of the user. UserCreateDrafts, /// Create communities on behalf of the user. UserCreateCommunities, /// Create stacks on behalf of the user. UserCreateStacks, /// Create journals on behalf of the user. UserCreateJournals, /// Create notes on behalf of the user. UserCreateNotes, /// Create links on behalf of the user. UserCreateLinks, /// Delete posts owned by the user. UserDeletePosts, /// Delete messages owned by the user. UserDeleteMessages, /// Delete questions as the user. UserDeleteQuestions, /// Delete drafts as the user. UserDeleteDrafts, /// Edit the user's settings and upload avatars/banners on behalf of the user. UserManageProfile, /// Manage stacks owned by the user. UserManageStacks, /// Manage the user's following/unfollowing. UserManageRelationships, /// Manage the user's community memberships. /// /// Also includes managing the membership of users in the user's communities. UserManageMemberships, /// Follow/unfollow users on behalf of the user. UserManageFollowing, /// Accept follow requests on behalf of the user. UserManageFollowers, /// Block/unblock users on behalf of the user. UserManageBlocks, /// Manage the user's notifications. UserManageNotifications, /// Manage the user's requests. UserManageRequests, /// Manage the user's uploads. UserManageUploads, /// Manage the user's journals. UserManageJournals, /// Manage the user's notes. UserManageNotes, /// Manage the user's links. UserManageLinks, /// Edit posts created by the user. UserEditPosts, /// Edit drafts created by the user. UserEditDrafts, /// Vote in polls as the user. UserVote, /// React to posts on behalf of the user. Also allows the removal of reactions. UserReact, /// Join communities on behalf of the user. UserJoinCommunities, /// Permanently delete posts. ModPurgePosts, /// Restore deleted posts. ModDeletePosts, /// Manage user warnings. ModManageWarnings, /// Get a list of all emojis available to the user. UserReadEmojis, /// Create emojis on behalf of the user. CommunityCreateEmojis, /// Manage emojis on behalf of the user. CommunityManageEmojis, /// Delete communities on behalf of the user. CommunityDelete, /// Manage communities on behalf of the user. CommunityManage, /// Transfer ownership of communities on behalf of the user. CommunityTransferOwnership, /// Read the membership of users in communities owned by the current user. CommunityReadMemberships, /// Create channels in the user's communities. CommunityCreateChannels, /// Manage channels in the user's communities. CommunityManageChannels, } impl AuthGrant { /// Check a verifier against the stored challenge (using the given [`PkceChallengeMethod`]). pub fn check_verifier(&self, verifier: &str) -> Result<()> { if self.method != PkceChallengeMethod::S256 { return Err(Error::MiscError("only S256 is supported".to_string())); } let decoded = match base64url.decode(self.challenge.as_bytes()) { Ok(hash) => hash, Err(e) => return Err(Error::MiscError(e.to_string())), }; let hash = hash(verifier.to_string()); if hash.as_bytes() != decoded { // the verifier we received does not match the verifier from the stored challenge return Err(Error::NotAllowed); } Ok(()) } }