crew_rs/
ruleset.rs

1use ridl::signing::SignerID;
2use ti64::MsSinceEpoch;
3
4use crate::{
5    changes::RevealSecretToParent, AddRole, CrewChange, EntrustInfo, MakeStatement, Member,
6    RevealSecret,
7};
8
9use crate::CrewState;
10
11pub trait CrewRuleset {
12    fn is_valid_change(
13        &self,
14        state: &CrewState,
15        change: &CrewChange,
16        made_by: &SignerID,
17        mate_at: MsSinceEpoch,
18    ) -> Result<(), String>;
19}
20
21pub struct CrewRulesV1;
22
23pub const READER_ROLE: &str = "reader";
24pub const WRITER_ROLE: &str = "writer";
25pub const ADMIN_ROLE: &str = "admin";
26pub const READ_INVITATION_ROLE: &str = "readInvitation";
27pub const WRITE_INVITATION_ROLE: &str = "writeInvitation";
28pub const ADMIN_INVITATION_ROLE: &str = "adminInvitation";
29
30pub const PARTICIPATION_SECRET: &str = "participation";
31pub const CONTENT_SECRET: &str = "content";
32
33pub const SET_WRITE_ACCESS_INFO_ID: &str = "setWriteAccess";
34
35impl CrewRuleset for CrewRulesV1 {
36    fn is_valid_change(
37        &self,
38        state: &CrewState,
39        change: &CrewChange,
40        made_by: &SignerID,
41        made_at: MsSinceEpoch,
42    ) -> Result<(), String> {
43        match change {
44            CrewChange::AddRole(AddRole { role, .. }) if role == READER_ROLE => {
45                if state.roles_of(made_by).contains(ADMIN_ROLE)
46                    || state.roles_of(made_by).contains(READ_INVITATION_ROLE)
47                {
48                    Ok(())
49                } else {
50                    Err("Only admins can change crew".to_string())
51                }
52            }
53            CrewChange::AddRole(AddRole { role, .. }) if role == WRITER_ROLE => {
54                if state.roles_of(made_by).contains(ADMIN_ROLE)
55                    || state.roles_of(made_by).contains(WRITE_INVITATION_ROLE)
56                {
57                    Ok(())
58                } else {
59                    Err("Only admins can change crew".to_string())
60                }
61            }
62            CrewChange::AddRole(AddRole { role, .. }) if role == ADMIN_ROLE => {
63                if state.roles_of(made_by).contains(ADMIN_ROLE)
64                    || state.roles_of(made_by).contains(ADMIN_INVITATION_ROLE)
65                {
66                    Ok(())
67                } else {
68                    Err("Only admins can change crew".to_string())
69                }
70            }
71            CrewChange::AddRole(_) | CrewChange::RemoveRole(_) => {
72                if state.roles_of(made_by).contains(ADMIN_ROLE) {
73                    Ok(())
74                } else {
75                    Err("Only admins can change crew".to_string())
76                }
77            }
78            CrewChange::RevealSecret(RevealSecret {
79                secret_kind, to, ..
80            }) => {
81                if secret_kind == PARTICIPATION_SECRET {
82                    if state.roles_of(&made_by).contains(ADMIN_ROLE)
83                        || state.roles_of(&made_by).contains(WRITE_INVITATION_ROLE)
84                        || state.roles_of(&made_by).contains(ADMIN_INVITATION_ROLE)
85                    {
86                        if state.roles_of(&to).contains(READ_INVITATION_ROLE)
87                            || state.roles_of(&to).contains(WRITE_INVITATION_ROLE)
88                            || state.roles_of(&to).contains(ADMIN_INVITATION_ROLE)
89                            || state.roles_of(&to).contains(WRITER_ROLE)
90                            || state.roles_of(&to).contains(ADMIN_ROLE)
91                        {
92                            Ok(())
93                        } else {
94                            Err("Only read_invitations, write_invitations, admin_invitations, writers and admins can receive participation secrets".to_string())
95                        }
96                    } else {
97                        Err("Only write_invitations, admin_invitations and admins can reveal participation secrets".to_string())
98                    }
99                } else if secret_kind == CONTENT_SECRET {
100                    if state.roles_of(&made_by).contains(ADMIN_ROLE)
101                        || state.roles_of(&made_by).contains(WRITER_ROLE)
102                        || state.roles_of(&made_by).contains(READ_INVITATION_ROLE)
103                        || state.roles_of(&made_by).contains(WRITE_INVITATION_ROLE)
104                        || state.roles_of(&made_by).contains(ADMIN_INVITATION_ROLE)
105                    {
106                        if state.roles_of(&to).contains(READ_INVITATION_ROLE)
107                            || state.roles_of(&to).contains(WRITE_INVITATION_ROLE)
108                            || state.roles_of(&to).contains(ADMIN_INVITATION_ROLE)
109                            || state.roles_of(&to).contains(READER_ROLE)
110                            || state.roles_of(&to).contains(WRITER_ROLE)
111                            || state.roles_of(&to).contains(ADMIN_ROLE)
112                        {
113                            Ok(())
114                        } else {
115                            Err("Only read_invitations, write_invitations, readers, writers and admins can receive content secrets".to_string())
116                        }
117                    } else {
118                        Err("Only read_invitations, write_invitations, admin_invitations, writers and admins can reveal content secrets".to_string())
119                    }
120                } else {
121                    todo!()
122                }
123            }
124            CrewChange::RevealSecretToParent(RevealSecretToParent { .. }) => {
125                if state.roles_of(&made_by).contains(ADMIN_ROLE) {
126                    Ok(())
127                } else {
128                    Err("Only admins can reveal secrets to parents".to_string())
129                }
130            }
131            CrewChange::EntrustInfo(EntrustInfo { to_secret_kind, .. }) => {
132                if to_secret_kind == PARTICIPATION_SECRET {
133                    if state.roles_of(&made_by).contains(ADMIN_ROLE) {
134                        Ok(())
135                    } else {
136                        Err("Only admins can entrust info to participation secrets".to_string())
137                    }
138                } else if to_secret_kind == CONTENT_SECRET {
139                    if state.roles_of(&made_by).contains(ADMIN_ROLE)
140                        || state.roles_of(&made_by).contains(WRITER_ROLE)
141                    {
142                        Ok(())
143                    } else {
144                        Err("Only admins or writers can entrust info to content secrets"
145                            .to_string())
146                    }
147                } else {
148                    todo!()
149                }
150            }
151            CrewChange::AddParent { .. } | CrewChange::RemoveParent { .. } => {
152                if state.roles_of(&made_by).contains(ADMIN_ROLE) {
153                    Ok(())
154                } else {
155                    Err("Only admins can add parent crews".to_string())
156                }
157            }
158            CrewChange::MakeStatement(MakeStatement { .. }) => {
159                if state.roles_of(&made_by).contains(ADMIN_ROLE)
160                    || state.roles_of(&made_by).contains(WRITER_ROLE)
161                {
162                    Ok(())
163                } else {
164                    Err("Only admins and writers can make statements".to_string())
165                }
166            }
167        }
168    }
169}