steel_core/server/
permissions.rs1use super::{
2 Arc, FnServerJob, OP_GROUP, PermissionGroupManager, PermissionGroupManagerError,
3 PermissionGroupUpdateError, PermissionGroupsConfig, PermissionSet, PermissionSubjectState,
4 Player, PlayerPermissionUpdateError, Server, ServerJobContext, Uuid,
5};
6
7pub(super) fn validate_player_permission_group_update<E>(
8 manager: &PermissionGroupManager,
9 previous_groups: &[String],
10 updated_groups: &[String],
11) -> Result<(), PlayerPermissionUpdateError<E>> {
12 for group in updated_groups {
13 let already_assigned = previous_groups.iter().any(|current| current == group);
14 if !already_assigned && !manager.contains_group(group) {
15 return Err(PlayerPermissionUpdateError::UnknownGroup(group.clone()));
16 }
17 }
18 Ok(())
19}
20
21impl Server {
22 pub(super) fn apply_cached_or_default_permission_state(&self, player: &Player) -> u64 {
23 let state = self
24 .player_permission_states
25 .read()
26 .get(player.gameprofile.id)
27 .cloned()
28 .unwrap_or_default();
29 self.apply_player_permission_state(player, state)
30 }
31
32 fn apply_player_permission_state(&self, player: &Player, state: PermissionSubjectState) -> u64 {
33 let (groups, overrides, metadata_overrides) = state.into_parts();
34 for group in &groups {
35 if !self.permission_groups.contains_group(group) {
36 log::warn!(
37 "Player {} has unknown permission group {group}",
38 player.gameprofile.name
39 );
40 }
41 }
42 let effective = self
43 .permission_groups
44 .effective_permissions(&groups, &overrides);
45 let effective_metadata = self
46 .permission_groups
47 .effective_metadata(&groups, &metadata_overrides);
48 player.set_permission_state(
49 groups,
50 overrides,
51 metadata_overrides,
52 effective,
53 effective_metadata,
54 )
55 }
56
57 #[must_use]
59 pub fn player_permission_state(&self, uuid: Uuid) -> Option<PermissionSubjectState> {
60 self.player_permission_states.read().get(uuid).cloned()
61 }
62
63 #[must_use]
65 pub(crate) fn is_operator(&self, uuid: Uuid) -> bool {
66 self.player_permission_states
67 .read()
68 .get(uuid)
69 .is_some_and(|state| state.groups().iter().any(|group| group == OP_GROUP))
70 }
71
72 #[must_use]
74 pub(crate) fn command_permission_snapshot(&self, uuid: Uuid) -> PermissionSet {
75 let subject = self.player_permission_state(uuid).unwrap_or_default();
76 self.permission_groups
77 .effective_permissions(subject.groups(), subject.overrides())
78 }
79
80 pub async fn try_update_player_permissions<T, E>(
89 self: &Arc<Self>,
90 uuid: Uuid,
91 update: impl FnOnce(PermissionSubjectState) -> Result<(PermissionSubjectState, T), E> + Send,
92 ) -> Result<(PermissionSubjectState, T), PlayerPermissionUpdateError<E>>
93 where
94 T: Send,
95 E: Send,
96 {
97 let _guard = self.player_permission_updates.lock().await;
98 let mut states = self.player_permission_states.read().clone();
99 let current = states.get(uuid).cloned().unwrap_or_default();
100 let previous_groups = current.groups().to_vec();
101 let (updated, result) = update(current).map_err(PlayerPermissionUpdateError::Edit)?;
102 validate_player_permission_group_update(
103 &self.permission_groups,
104 &previous_groups,
105 updated.groups(),
106 )?;
107
108 if updated.is_empty() {
109 states.remove(uuid);
110 } else {
111 states.set(uuid, updated.clone());
112 }
113 self.player_data_storage
114 .save_permission_subjects(&states)
115 .await?;
116
117 *self.player_permission_states.write() = states;
118 self.queue_player_permission_refresh(uuid);
119 Ok((updated, result))
120 }
121
122 pub async fn replace_permission_groups(
128 self: &Arc<Self>,
129 config: PermissionGroupsConfig,
130 ) -> Result<(), PermissionGroupManagerError> {
131 self.permission_groups.replace_config(config).await?;
132 self.queue_online_permission_group_refresh();
133 Ok(())
134 }
135
136 pub async fn update_permission_groups(
142 self: &Arc<Self>,
143 update: impl FnOnce(&mut PermissionGroupsConfig) + Send,
144 ) -> Result<(), PermissionGroupManagerError> {
145 self.permission_groups.update_config(update).await?;
146 self.queue_online_permission_group_refresh();
147 Ok(())
148 }
149
150 pub async fn try_update_permission_groups<T, E>(
156 self: &Arc<Self>,
157 update: impl FnOnce(&mut PermissionGroupsConfig) -> Result<T, E> + Send,
158 ) -> Result<T, PermissionGroupUpdateError<E>>
159 where
160 T: Send,
161 E: Send,
162 {
163 let result = self.permission_groups.try_update_config(update).await?;
164 self.queue_online_permission_group_refresh();
165 Ok(result)
166 }
167
168 fn queue_player_permission_refresh(self: &Arc<Self>, uuid: Uuid) {
169 self.jobs
170 .spawn(FnServerJob::new(move |context: &mut ServerJobContext| {
171 if let Some(server) = context.server() {
172 server.refresh_player_permission_state(uuid);
173 }
174 }));
175 }
176
177 pub(crate) fn refresh_player_permission_state(self: &Arc<Self>, uuid: Uuid) {
178 let Some(player) = self.online_players.get_by_uuid(&uuid) else {
179 return;
180 };
181 let state = self.player_permission_state(uuid).unwrap_or_default();
182 self.apply_player_permission_state(&player, state);
183 self.resend_player_permission_context(&player);
184 }
185
186 fn queue_online_permission_group_refresh(self: &Arc<Self>) {
187 self.jobs
188 .spawn(FnServerJob::new(|context: &mut ServerJobContext| {
189 if let Some(server) = context.server() {
190 server.refresh_online_permission_groups();
191 }
192 }));
193 }
194
195 fn refresh_online_permission_groups(self: &Arc<Self>) {
196 for player in self.get_players() {
197 let state = self
198 .player_permission_state(player.gameprofile.id)
199 .unwrap_or_default();
200 self.apply_player_permission_state(&player, state);
201 self.resend_player_permission_context(&player);
202 }
203 }
204}