openauth_plugins/organization/
permissions.rs1use 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}
39
40impl OrganizationPermission {
41 pub(crate) fn resource_action(self) -> (&'static str, &'static str) {
42 match self {
43 Self::OrganizationUpdate => ("organization", "update"),
44 Self::OrganizationDelete => ("organization", "delete"),
45 Self::MemberCreate => ("member", "create"),
46 Self::MemberUpdate => ("member", "update"),
47 Self::MemberDelete => ("member", "delete"),
48 Self::InvitationCreate => ("invitation", "create"),
49 Self::InvitationCancel => ("invitation", "cancel"),
50 Self::TeamCreate => ("team", "create"),
51 Self::TeamUpdate => ("team", "update"),
52 Self::TeamDelete => ("team", "delete"),
53 Self::AcCreate => ("ac", "create"),
54 Self::AcRead => ("ac", "read"),
55 Self::AcUpdate => ("ac", "update"),
56 Self::AcDelete => ("ac", "delete"),
57 }
58 }
59}
60
61pub fn has_permission(
62 role: &str,
63 options: &OrganizationOptions,
64 permission: OrganizationPermission,
65) -> bool {
66 role.split(',').map(str::trim).any(|role| {
67 if role == options.creator_role {
68 return true;
69 }
70 if custom_role_has_permission(role, options, permission) {
71 return true;
72 }
73 match role {
74 "owner" => true,
75 "admin" => !matches!(permission, OrganizationPermission::OrganizationDelete),
76 "member" => matches!(permission, OrganizationPermission::AcRead),
77 _ => false,
78 }
79 })
80}
81
82pub(crate) fn parse_roles(role: impl AsRef<str>) -> String {
83 role.as_ref()
84 .split(',')
85 .map(str::trim)
86 .filter(|role| !role.is_empty())
87 .collect::<Vec<_>>()
88 .join(",")
89}
90
91pub(crate) fn is_known_static_role(role: &str, options: &OrganizationOptions) -> bool {
92 role == options.creator_role
93 || options.custom_roles.contains_key(role)
94 || matches!(role, "owner" | "admin" | "member")
95}
96
97pub(crate) fn permission_value_has_permission(
98 permission: &serde_json::Value,
99 required: OrganizationPermission,
100) -> bool {
101 let (resource, action) = required.resource_action();
102 permission
103 .get(resource)
104 .and_then(serde_json::Value::as_array)
105 .map(|actions| actions.iter().any(|value| value.as_str() == Some(action)))
106 .unwrap_or(false)
107}
108
109fn custom_role_has_permission(
110 role: &str,
111 options: &OrganizationOptions,
112 permission: OrganizationPermission,
113) -> bool {
114 options
115 .custom_roles
116 .get(role)
117 .map(|value| permission_value_has_permission(value, permission))
118 .unwrap_or(false)
119}