Skip to main content

openauth_plugins/organization/
permissions.rs

1use serde::{Deserialize, Serialize};
2
3use super::options::OrganizationOptions;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
6pub enum OrganizationRole {
7    Owner,
8    Admin,
9    Member,
10}
11
12impl OrganizationRole {
13    pub fn as_str(self) -> &'static str {
14        match self {
15            Self::Owner => "owner",
16            Self::Admin => "admin",
17            Self::Member => "member",
18        }
19    }
20}
21
22#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
23pub enum OrganizationPermission {
24    OrganizationUpdate,
25    OrganizationDelete,
26    MemberCreate,
27    MemberUpdate,
28    MemberDelete,
29    InvitationCreate,
30    InvitationCancel,
31    TeamCreate,
32    TeamUpdate,
33    TeamDelete,
34    AcCreate,
35    AcRead,
36    AcUpdate,
37    AcDelete,
38    ApiKeyCreate,
39    ApiKeyRead,
40    ApiKeyUpdate,
41    ApiKeyDelete,
42}
43
44impl OrganizationPermission {
45    pub(crate) fn resource_action(self) -> (&'static str, &'static str) {
46        match self {
47            Self::OrganizationUpdate => ("organization", "update"),
48            Self::OrganizationDelete => ("organization", "delete"),
49            Self::MemberCreate => ("member", "create"),
50            Self::MemberUpdate => ("member", "update"),
51            Self::MemberDelete => ("member", "delete"),
52            Self::InvitationCreate => ("invitation", "create"),
53            Self::InvitationCancel => ("invitation", "cancel"),
54            Self::TeamCreate => ("team", "create"),
55            Self::TeamUpdate => ("team", "update"),
56            Self::TeamDelete => ("team", "delete"),
57            Self::AcCreate => ("ac", "create"),
58            Self::AcRead => ("ac", "read"),
59            Self::AcUpdate => ("ac", "update"),
60            Self::AcDelete => ("ac", "delete"),
61            Self::ApiKeyCreate => ("apiKey", "create"),
62            Self::ApiKeyRead => ("apiKey", "read"),
63            Self::ApiKeyUpdate => ("apiKey", "update"),
64            Self::ApiKeyDelete => ("apiKey", "delete"),
65        }
66    }
67}
68
69pub fn has_permission(
70    role: &str,
71    options: &OrganizationOptions,
72    permission: OrganizationPermission,
73) -> bool {
74    role.split(',').map(str::trim).any(|role| {
75        if role == options.creator_role {
76            return true;
77        }
78        if custom_role_has_permission(role, options, permission) {
79            return true;
80        }
81        match role {
82            "owner" => true,
83            "admin" => !matches!(permission, OrganizationPermission::OrganizationDelete),
84            "member" => matches!(permission, OrganizationPermission::AcRead),
85            _ => false,
86        }
87    })
88}
89
90pub(crate) fn parse_roles(role: impl AsRef<str>) -> String {
91    role.as_ref()
92        .split(',')
93        .map(str::trim)
94        .filter(|role| !role.is_empty())
95        .collect::<Vec<_>>()
96        .join(",")
97}
98
99pub(crate) fn is_known_static_role(role: &str, options: &OrganizationOptions) -> bool {
100    role == options.creator_role
101        || options.custom_roles.contains_key(role)
102        || matches!(role, "owner" | "admin" | "member")
103}
104
105pub(crate) fn permission_value_has_permission(
106    permission: &serde_json::Value,
107    required: OrganizationPermission,
108) -> bool {
109    let (resource, action) = required.resource_action();
110    permission
111        .get(resource)
112        .or_else(|| {
113            (resource == "apiKey")
114                .then(|| permission.get("api_key"))
115                .flatten()
116        })
117        .and_then(serde_json::Value::as_array)
118        .map(|actions| actions.iter().any(|value| value.as_str() == Some(action)))
119        .unwrap_or(false)
120}
121
122fn custom_role_has_permission(
123    role: &str,
124    options: &OrganizationOptions,
125    permission: OrganizationPermission,
126) -> bool {
127    options
128        .custom_roles
129        .get(role)
130        .map(|value| permission_value_has_permission(value, permission))
131        .unwrap_or(false)
132}