Skip to main content

shared/
permissions.rs

1use indexmap::IndexMap;
2use serde::Serialize;
3use std::{collections::HashSet, sync::LazyLock};
4use utoipa::ToSchema;
5
6#[derive(ToSchema, Serialize, Clone)]
7pub struct PermissionGroup {
8    pub description: &'static str,
9    pub permissions: IndexMap<&'static str, &'static str>,
10}
11
12impl PermissionGroup {
13    pub fn add_permission(&mut self, key: &'static str, description: &'static str) {
14        self.permissions.insert(key, description);
15    }
16}
17
18pub(crate) fn flatten_permissions(
19    map: &IndexMap<&'static str, PermissionGroup>,
20) -> HashSet<String> {
21    map.iter()
22        .flat_map(|(key, group)| {
23            group
24                .permissions
25                .keys()
26                .map(move |permission| format!("{key}.{permission}"))
27        })
28        .collect()
29}
30
31#[derive(ToSchema, Serialize)]
32pub struct PermissionMap {
33    #[serde(skip)]
34    list: HashSet<String>,
35    #[serde(skip)]
36    inert: HashSet<String>,
37    #[serde(flatten)]
38    map: IndexMap<&'static str, PermissionGroup>,
39}
40
41impl PermissionMap {
42    pub(crate) fn new() -> Self {
43        Self {
44            list: HashSet::new(),
45            inert: HashSet::new(),
46            map: IndexMap::new(),
47        }
48    }
49
50    pub(crate) fn replace(&mut self, map: IndexMap<&'static str, PermissionGroup>) {
51        self.list = flatten_permissions(&map);
52        self.map = map;
53    }
54
55    /// Marks permissions as valid without listing them, used for permissions belonging to
56    /// disabled extensions. They stay grantable so re-enabling the extension restores them,
57    /// but they are not offered anywhere since nothing checks them while the extension is off.
58    pub(crate) fn set_inert(&mut self, inert: HashSet<String>) {
59        self.inert = inert;
60    }
61
62    #[inline]
63    pub fn list(&self) -> &HashSet<String> {
64        &self.list
65    }
66
67    pub fn validate_permissions(
68        &self,
69        permissions: &[compact_str::CompactString],
70    ) -> Result<(), garde::Error> {
71        for permission in permissions {
72            if !self.list().contains(&**permission) && !self.inert.contains(&**permission) {
73                return Err(garde::Error::new(compact_str::format_compact!(
74                    "invalid permission: {permission}"
75                )));
76            }
77        }
78
79        Ok(())
80    }
81}
82
83pub(crate) static BASE_USER_PERMISSIONS: LazyLock<IndexMap<&'static str, PermissionGroup>> =
84    LazyLock::new(|| {
85        IndexMap::from([
86            (
87                "account",
88                PermissionGroup {
89                    description: "Permissions that control the ability to change account settings.",
90                    permissions: IndexMap::from([
91                        (
92                            "infos",
93                            "Allows changing the account's basic account information.",
94                        ),
95                        ("email", "Allows changing the account's email address."),
96                        ("password", "Allows changing the account's password."),
97                        (
98                            "password-login",
99                            "Allows enabling and disabling password login for the account.",
100                        ),
101                        (
102                            "two-factor",
103                            "Allows adding and removing two-factor authentication.",
104                        ),
105                        (
106                            "avatar",
107                            "Allows updating and removing the account's avatar.",
108                        ),
109                    ]),
110                },
111            ),
112            (
113                "servers",
114                PermissionGroup {
115                    description: "Permissions that control the ability to list servers and manage server groups.",
116                    permissions: IndexMap::from([
117                        ("create", "Allows creating new server groups."),
118                        ("read", "Allows viewing servers and server groups."),
119                        ("update", "Allows modifying server groups."),
120                        ("delete", "Allows deleting server groups."),
121                    ]),
122                },
123            ),
124            (
125                "api-keys",
126                PermissionGroup {
127                    description: "Permissions that control the ability to manage API keys on an account. API keys can never edit themselves or assign permissions they do not have.",
128                    permissions: IndexMap::from([
129                        ("create", "Allows creating new API keys."),
130                        ("read", "Allows viewing API keys and their permissions."),
131                        ("update", "Allows modifying other API keys."),
132                        ("delete", "Allows deleting API keys."),
133                        ("recreate", "Allows recreating API keys."),
134                    ]),
135                },
136            ),
137            (
138                "security-keys",
139                PermissionGroup {
140                    description: "Permissions that control the ability to manage security keys on an account.",
141                    permissions: IndexMap::from([
142                        ("create", "Allows creating new security keys."),
143                        ("read", "Allows viewing security keys."),
144                        ("update", "Allows modifying security keys."),
145                        ("delete", "Allows deleting security keys."),
146                    ]),
147                },
148            ),
149            (
150                "ssh-keys",
151                PermissionGroup {
152                    description: "Permissions that control the ability to manage SSH keys on an account.",
153                    permissions: IndexMap::from([
154                        ("create", "Allows creating or importing new SSH keys."),
155                        ("read", "Allows viewing SSH keys."),
156                        ("update", "Allows modifying other SSH keys."),
157                        ("delete", "Allows deleting SSH keys."),
158                    ]),
159                },
160            ),
161            (
162                "oauth-links",
163                PermissionGroup {
164                    description: "Permissions that control the ability to manage OAuth links on an account.",
165                    permissions: IndexMap::from([
166                        ("create", "Allows creating new OAuth links."),
167                        ("read", "Allows viewing OAuth links."),
168                        ("delete", "Allows deleting OAuth links."),
169                    ]),
170                },
171            ),
172            (
173                "command-snippets",
174                PermissionGroup {
175                    description: "Permissions that control the ability to manage command snippets on an account.",
176                    permissions: IndexMap::from([
177                        ("create", "Allows creating new command snippets."),
178                        ("read", "Allows viewing command snippets."),
179                        ("update", "Allows modifying command snippets."),
180                        ("delete", "Allows deleting command snippets."),
181                    ]),
182                },
183            ),
184            (
185                "sessions",
186                PermissionGroup {
187                    description: "Permissions that control the ability to manage sessions on an account.",
188                    permissions: IndexMap::from([
189                        ("read", "Allows viewing sessions and their IP addresses."),
190                        ("delete", "Allows deleting sessions."),
191                    ]),
192                },
193            ),
194            (
195                "settings",
196                PermissionGroup {
197                    description: "Permissions that control the ability to manage synced user settings on an account.",
198                    permissions: IndexMap::from([
199                        ("read", "Allows viewing the account's synced user settings."),
200                        (
201                            "update",
202                            "Allows modifying the account's synced user settings.",
203                        ),
204                    ]),
205                },
206            ),
207            (
208                "activity",
209                PermissionGroup {
210                    description: "Permissions that control the ability to view the activity log on an account.",
211                    permissions: IndexMap::from([(
212                        "read",
213                        "Allows viewing the account's activity logs.",
214                    )]),
215                },
216            ),
217        ])
218    });
219
220pub(crate) static USER_PERMISSIONS: LazyLock<parking_lot::RwLock<PermissionMap>> =
221    LazyLock::new(|| parking_lot::RwLock::new(PermissionMap::new()));
222
223#[inline]
224pub fn get_user_permissions() -> parking_lot::RwLockReadGuard<'static, PermissionMap> {
225    USER_PERMISSIONS.read()
226}
227
228#[inline]
229pub fn validate_user_permissions(
230    permissions: &[compact_str::CompactString],
231    _context: &(),
232) -> Result<(), garde::Error> {
233    get_user_permissions().validate_permissions(permissions)
234}
235
236pub(crate) static BASE_ADMIN_PERMISSIONS: LazyLock<IndexMap<&'static str, PermissionGroup>> =
237    LazyLock::new(|| {
238        IndexMap::from([
239            (
240                "stats",
241                PermissionGroup {
242                    description: "Permissions that control the ability to view stats for the panel.",
243                    permissions: IndexMap::from([("read", "Allows viewing panel statistics.")]),
244                },
245            ),
246            (
247                "settings",
248                PermissionGroup {
249                    description: "Permissions that control the ability to manage settings for the panel.",
250                    permissions: IndexMap::from([
251                        ("read", "Allows viewing panel settings and secrets."),
252                        ("update", "Allows modifying panel settings and secrets."),
253                    ]),
254                },
255            ),
256            (
257                "email-templates",
258                PermissionGroup {
259                    description: "Permissions that control the ability to manage email templates and variables for the panel.",
260                    permissions: IndexMap::from([
261                        ("read", "Allows viewing email templates and variables."),
262                        ("update", "Allows modifying email templates and variables."),
263                    ]),
264                },
265            ),
266            (
267                "extensions",
268                PermissionGroup {
269                    description: "Permissions that control the ability to manage extensions for the panel.",
270                    permissions: IndexMap::from([
271                        ("read", "Allows viewing panel extensions."),
272                        (
273                            "manage",
274                            "Allows installing, updating, and removing panel extensions, usually also used to manage extension settings.",
275                        ),
276                    ]),
277                },
278            ),
279            (
280                "announcements",
281                PermissionGroup {
282                    description: "Permissions that control the ability to manage announcements for the panel.",
283                    permissions: IndexMap::from([
284                        ("create", "Allows creating new announcements."),
285                        ("read", "Allows viewing announcements."),
286                        ("update", "Allows modifying announcements."),
287                        ("delete", "Allows deleting announcements."),
288                    ]),
289                },
290            ),
291            (
292                "assets",
293                PermissionGroup {
294                    description: "Permissions that control the ability to manage assets for the panel.",
295                    permissions: IndexMap::from([
296                        ("read", "Allows viewing panel assets."),
297                        ("upload", "Allows creating and modifying assets."),
298                        ("delete", "Allows deleting panel assets."),
299                    ]),
300                },
301            ),
302            (
303                "users",
304                PermissionGroup {
305                    description: "Permissions that control the ability to manage users for the panel.",
306                    permissions: IndexMap::from([
307                        ("create", "Allows creating new users."),
308                        ("read", "Allows viewing users."),
309                        ("update", "Allows modifying users."),
310                        (
311                            "disable-two-factor",
312                            "Allows removing two-factor authentication from users.",
313                        ),
314                        ("delete", "Allows deleting users."),
315                        (
316                            "email",
317                            "Allows sending email actions to users, such as password resets, and marking a user's email as verified.",
318                        ),
319                        ("activity", "Allows viewing a user's activity log."),
320                        (
321                            "oauth-links",
322                            "Allows viewing and managing a user's OAuth links.",
323                        ),
324                        ("impersonate", "Allows impersonating other users."),
325                    ]),
326                },
327            ),
328            (
329                "roles",
330                PermissionGroup {
331                    description: "Permissions that control the ability to manage roles for the panel.",
332                    permissions: IndexMap::from([
333                        ("create", "Allows creating new roles."),
334                        ("read", "Allows viewing roles."),
335                        ("update", "Allows modifying roles."),
336                        ("delete", "Allows deleting roles."),
337                    ]),
338                },
339            ),
340            (
341                "locations",
342                PermissionGroup {
343                    description: "Permissions that control the ability to manage locations for the panel.",
344                    permissions: IndexMap::from([
345                        ("create", "Allows creating new locations."),
346                        ("read", "Allows viewing locations."),
347                        ("update", "Allows modifying locations."),
348                        ("delete", "Allows deleting locations."),
349                        (
350                            "database-hosts",
351                            "Allows viewing and managing a location's database hosts.",
352                        ),
353                        (
354                            "database-agent-hosts",
355                            "Allows viewing and managing a location's database agent hosts.",
356                        ),
357                    ]),
358                },
359            ),
360            (
361                "backup-configurations",
362                PermissionGroup {
363                    description: "Permissions that control the ability to manage backup configurations for the panel.",
364                    permissions: IndexMap::from([
365                        ("create", "Allows creating new backup configurations."),
366                        (
367                            "read",
368                            "Allows viewing backup configurations and their passwords.",
369                        ),
370                        (
371                            "update",
372                            "Allows modifying backup configurations and their passwords.",
373                        ),
374                        ("delete", "Allows deleting backup configurations."),
375                        (
376                            "backups",
377                            "Allows viewing backups associated with a backup configuration.",
378                        ),
379                    ]),
380                },
381            ),
382            (
383                "system-backup-policies",
384                PermissionGroup {
385                    description: "Permissions that control the ability to manage system backup policies for the panel.",
386                    permissions: IndexMap::from([
387                        ("create", "Allows creating new system backup policies."),
388                        ("read", "Allows viewing system backup policies."),
389                        (
390                            "update",
391                            "Allows modifying system backup policies and their attached nodes, database agent hosts, locations and servers.",
392                        ),
393                        ("delete", "Allows deleting system backup policies."),
394                        (
395                            "backups",
396                            "Allows viewing backups associated with a system backup policy.",
397                        ),
398                    ]),
399                },
400            ),
401            (
402                "nodes",
403                PermissionGroup {
404                    description: "Permissions that control the ability to manage nodes for the panel.",
405                    permissions: IndexMap::from([
406                        ("create", "Allows creating new nodes."),
407                        ("read", "Allows viewing nodes."),
408                        ("update", "Allows modifying nodes."),
409                        ("delete", "Allows deleting nodes."),
410                        ("read-token", "Allows viewing a node's token."),
411                        ("reset-token", "Allows resetting a node's token."),
412                        (
413                            "allocations",
414                            "Allows viewing and managing a node's allocations.",
415                        ),
416                        ("mounts", "Allows viewing and managing a node's mounts."),
417                        ("devices", "Allows viewing and managing a node's devices."),
418                        (
419                            "database-hosts",
420                            "Allows viewing and managing a node's database hosts.",
421                        ),
422                        (
423                            "database-agent-hosts",
424                            "Allows viewing and managing a node's database agent hosts.",
425                        ),
426                        ("backups", "Allows viewing and managing a node's backups."),
427                        (
428                            "tunnel",
429                            "Allows viewing and managing a node's private network membership.",
430                        ),
431                        ("power", "Allows executing mass-power actions on nodes."),
432                        (
433                            "transfers",
434                            "Allows viewing and managing mass-server transfers between nodes.",
435                        ),
436                    ]),
437                },
438            ),
439            (
440                "servers",
441                PermissionGroup {
442                    description: "Permissions that control the ability to manage servers for the panel.",
443                    permissions: IndexMap::from([
444                        ("create", "Allows creating new servers."),
445                        ("read", "Allows viewing servers."),
446                        ("update", "Allows modifying servers."),
447                        ("delete", "Allows deleting servers."),
448                        (
449                            "transfer",
450                            "Allows transferring servers to other nodes or canceling ongoing transfers.",
451                        ),
452                        (
453                            "allocations",
454                            "Allows viewing and managing a server's allocations.",
455                        ),
456                        (
457                            "variables",
458                            "Allows viewing and managing a server's variables.",
459                        ),
460                        ("mounts", "Allows viewing and managing a server's mounts."),
461                        ("devices", "Allows viewing and managing a server's devices."),
462                    ]),
463                },
464            ),
465            (
466                "nests",
467                PermissionGroup {
468                    description: "Permissions that control the ability to manage nests for the panel.",
469                    permissions: IndexMap::from([
470                        ("create", "Allows creating new nests."),
471                        ("read", "Allows viewing nests."),
472                        ("update", "Allows modifying nests."),
473                        ("delete", "Allows deleting nests."),
474                    ]),
475                },
476            ),
477            (
478                "eggs",
479                PermissionGroup {
480                    description: "Permissions that control the ability to manage eggs for the panel.",
481                    permissions: IndexMap::from([
482                        ("create", "Allows creating and importing new eggs."),
483                        ("read", "Allows viewing eggs."),
484                        ("update", "Allows modifying eggs."),
485                        ("delete", "Allows deleting eggs."),
486                        ("mounts", "Allows viewing and managing an egg's mounts."),
487                        ("devices", "Allows viewing and managing an egg's devices."),
488                    ]),
489                },
490            ),
491            (
492                "egg-configurations",
493                PermissionGroup {
494                    description: "Permissions that control the ability to manage egg configurations for the panel.",
495                    permissions: IndexMap::from([
496                        ("create", "Allows creating new egg configurations."),
497                        ("read", "Allows viewing egg configurations."),
498                        ("update", "Allows modifying egg configurations."),
499                        ("delete", "Allows deleting egg configurations."),
500                    ]),
501                },
502            ),
503            (
504                "egg-repositories",
505                PermissionGroup {
506                    description: "Permissions that control the ability to manage egg repositories for the panel.",
507                    permissions: IndexMap::from([
508                        ("create", "Allows creating new egg repositories."),
509                        ("read", "Allows viewing egg repositories."),
510                        ("update", "Allows modifying egg repositories."),
511                        ("delete", "Allows deleting egg repositories."),
512                        (
513                            "sync",
514                            "Allows synchronizing egg repositories with their remote sources.",
515                        ),
516                    ]),
517                },
518            ),
519            (
520                "database-hosts",
521                PermissionGroup {
522                    description: "Permissions that control the ability to manage database hosts for the panel.",
523                    permissions: IndexMap::from([
524                        ("create", "Allows creating new database hosts."),
525                        ("read", "Allows viewing database hosts."),
526                        ("update", "Allows modifying database hosts."),
527                        ("delete", "Allows deleting database hosts."),
528                        ("test", "Allows testing database host connections."),
529                    ]),
530                },
531            ),
532            (
533                "database-agent-hosts",
534                PermissionGroup {
535                    description: "Permissions that control the ability to manage database agent hosts for the panel.",
536                    permissions: IndexMap::from([
537                        ("create", "Allows creating new database agent hosts."),
538                        ("read", "Allows viewing database agent hosts."),
539                        ("update", "Allows modifying database agent hosts."),
540                        ("delete", "Allows deleting database agent hosts."),
541                        (
542                            "read-token",
543                            "Allows viewing a database agent host's token.",
544                        ),
545                        (
546                            "reset-token",
547                            "Allows resetting database agent host tokens.",
548                        ),
549                        ("test", "Allows testing database agent host connections."),
550                        (
551                            "backups",
552                            "Allows viewing backups associated with a database agent host.",
553                        ),
554                    ]),
555                },
556            ),
557            (
558                "database-agent-templates",
559                PermissionGroup {
560                    description: "Permissions that control the ability to manage database agent templates for the panel.",
561                    permissions: IndexMap::from([
562                        ("create", "Allows creating new database agent templates."),
563                        ("read", "Allows viewing database agent templates."),
564                        ("update", "Allows modifying database agent templates."),
565                        ("delete", "Allows deleting database agent templates."),
566                    ]),
567                },
568            ),
569            (
570                "oauth-providers",
571                PermissionGroup {
572                    description: "Permissions that control the ability to manage OAuth providers for the panel.",
573                    permissions: IndexMap::from([
574                        ("create", "Allows creating new OAuth providers."),
575                        ("read", "Allows viewing OAuth providers."),
576                        ("update", "Allows modifying OAuth providers."),
577                        ("delete", "Allows deleting OAuth providers."),
578                    ]),
579                },
580            ),
581            (
582                "mounts",
583                PermissionGroup {
584                    description: "Permissions that control the ability to manage mounts for the panel.",
585                    permissions: IndexMap::from([
586                        ("create", "Allows creating new mounts."),
587                        ("read", "Allows viewing mounts."),
588                        ("update", "Allows modifying mounts."),
589                        ("delete", "Allows deleting mounts."),
590                    ]),
591                },
592            ),
593            (
594                "devices",
595                PermissionGroup {
596                    description: "Permissions that control the ability to manage devices for the panel.",
597                    permissions: IndexMap::from([
598                        ("create", "Allows creating new devices."),
599                        ("read", "Allows viewing devices."),
600                        ("update", "Allows modifying devices."),
601                        ("delete", "Allows deleting devices."),
602                    ]),
603                },
604            ),
605            (
606                "activity",
607                PermissionGroup {
608                    description: "Permissions that control the ability to view the activity log for all admin operations.",
609                    permissions: IndexMap::from([(
610                        "read",
611                        "Allows viewing the activity logs for all admin operations.",
612                    )]),
613                },
614            ),
615        ])
616    });
617
618pub(crate) static ADMIN_PERMISSIONS: LazyLock<parking_lot::RwLock<PermissionMap>> =
619    LazyLock::new(|| parking_lot::RwLock::new(PermissionMap::new()));
620
621#[inline]
622pub fn get_admin_permissions() -> parking_lot::RwLockReadGuard<'static, PermissionMap> {
623    ADMIN_PERMISSIONS.read()
624}
625
626#[inline]
627pub fn validate_admin_permissions(
628    permissions: &[compact_str::CompactString],
629    _context: &(),
630) -> Result<(), garde::Error> {
631    get_admin_permissions().validate_permissions(permissions)
632}
633
634pub(crate) static BASE_SERVER_PERMISSIONS: LazyLock<IndexMap<&'static str, PermissionGroup>> =
635    LazyLock::new(|| {
636        IndexMap::from([
637            (
638                "control",
639                PermissionGroup {
640                    description: "Permissions that control the ability to control the power state of a server, read the console, or send commands.",
641                    permissions: IndexMap::from([
642                        ("read-console", "Allows reading the server console logs."),
643                        (
644                            "console",
645                            "Allows sending commands to the server instance via the console.",
646                        ),
647                        ("start", "Allows starting the server if it is stopped."),
648                        ("stop", "Allows stopping the server if it is running."),
649                        (
650                            "restart",
651                            "Allows restarting the server. This permits starting the server if it is offline, but not placing it in a completely stopped state.",
652                        ),
653                    ]),
654                },
655            ),
656            (
657                "subusers",
658                PermissionGroup {
659                    description: "Permissions that control the ability to manage subusers of a server. Users can never edit their own account or assign permissions they do not have.",
660                    permissions: IndexMap::from([
661                        ("create", "Allows creating new subusers for the server."),
662                        ("read", "Allows viewing subusers and their permissions."),
663                        ("update", "Allows modifying other subusers."),
664                        ("delete", "Allows deleting subusers from the server."),
665                    ]),
666                },
667            ),
668            (
669                "files",
670                PermissionGroup {
671                    description: "Permissions that control the ability to modify the filesystem for this server.",
672                    permissions: IndexMap::from([
673                        (
674                            "create",
675                            "Allows creating additional files and folders via the panel or direct upload.",
676                        ),
677                        (
678                            "read",
679                            "Allows viewing the contents of a directory, but not reading or downloading individual files.",
680                        ),
681                        (
682                            "read-content",
683                            "Allows viewing the contents of a specific file. This also permits downloading files.",
684                        ),
685                        (
686                            "update",
687                            "Allows updating the contents of an existing file or directory.",
688                        ),
689                        (
690                            "delete",
691                            "Allows deleting files or directories, restoring them from the trash and emptying the trash.",
692                        ),
693                        (
694                            "archive",
695                            "Allows archiving the contents of a directory and decompressing files.",
696                        ),
697                        ("sftp", "Allows connecting via SFTP to manage files."),
698                        (
699                            "query-raw",
700                            "Allows running arbitrary SQL against a SQLite database file on this server. This grants full read and write access to that file's contents, equivalent to reading and updating it directly.",
701                        ),
702                    ]),
703                },
704            ),
705            (
706                "backups",
707                PermissionGroup {
708                    description: "Permissions that control the ability to manage server backups.",
709                    permissions: IndexMap::from([
710                        ("create", "Allows creating new backups for the server."),
711                        ("read", "Allows viewing existing backups."),
712                        ("download", "Allows downloading backups."),
713                        ("restore", "Allows restoring backups."),
714                        ("update", "Allows updating existing backups."),
715                        ("delete", "Allows deleting backups."),
716                    ]),
717                },
718            ),
719            (
720                "backup-groups",
721                PermissionGroup {
722                    description: "Permissions that control the ability to manage server backup groups (retention policies).",
723                    permissions: IndexMap::from([
724                        ("create", "Allows creating new backup groups."),
725                        ("read", "Allows viewing existing backup groups."),
726                        ("update", "Allows updating existing backup groups."),
727                        ("delete", "Allows deleting backup groups."),
728                    ]),
729                },
730            ),
731            (
732                "schedules",
733                PermissionGroup {
734                    description: "Permissions that control the ability to manage server schedules.",
735                    permissions: IndexMap::from([
736                        ("create", "Allows creating new schedules."),
737                        ("read", "Allows viewing existing schedules."),
738                        ("update", "Allows updating existing schedules."),
739                        ("delete", "Allows deleting schedules."),
740                    ]),
741                },
742            ),
743            (
744                "allocations",
745                PermissionGroup {
746                    description: "Permissions that control the ability to modify the port allocations for this server.",
747                    permissions: IndexMap::from([
748                        (
749                            "read",
750                            "Allows viewing all allocations currently assigned to this server. Users with any level of access can always view the primary allocation.",
751                        ),
752                        (
753                            "create",
754                            "Allows assigning additional allocations to the server.",
755                        ),
756                        (
757                            "update",
758                            "Allows changing the primary server allocation and attaching notes to allocations.",
759                        ),
760                        ("delete", "Allows deleting allocations from the server."),
761                    ]),
762                },
763            ),
764            (
765                "firewall",
766                PermissionGroup {
767                    description: "Permissions that control the ability to restrict which sources may reach this server's allocations.",
768                    permissions: IndexMap::from([
769                        ("read", "Allows viewing the firewall rules of the server."),
770                        (
771                            "update",
772                            "Allows adding, reordering, modifying and removing firewall rules.",
773                        ),
774                    ]),
775                },
776            ),
777            (
778                "connections",
779                PermissionGroup {
780                    description: "Permissions that control the ability to connect this server privately to other servers, bypassing the public network.",
781                    permissions: IndexMap::from([
782                        (
783                            "create",
784                            "Allows putting the server on the private network and connecting it to another server.",
785                        ),
786                        (
787                            "read",
788                            "Allows viewing the server's private network membership, its connections and the ports it offers them.",
789                        ),
790                        (
791                            "update",
792                            "Allows changing the server's hostname and which ports it offers to the servers connected to it.",
793                        ),
794                        (
795                            "delete",
796                            "Allows removing one of the server's connections, and taking the server off the private network.",
797                        ),
798                    ]),
799                },
800            ),
801            (
802                "startup",
803                PermissionGroup {
804                    description: "Permissions that control the ability to view and modify this server's startup parameters.",
805                    permissions: IndexMap::from([
806                        (
807                            "read",
808                            "Allows viewing the startup variables for the server.",
809                        ),
810                        ("update", "Allows modifying the startup variables."),
811                        (
812                            "command",
813                            "Allows modifying the command used to start the server.",
814                        ),
815                        (
816                            "docker-image",
817                            "Allows modifying the Docker image used when running the server.",
818                        ),
819                    ]),
820                },
821            ),
822            (
823                "databases",
824                PermissionGroup {
825                    description: "Permissions that control the ability to manage databases on this server.",
826                    permissions: IndexMap::from([
827                        ("create", "Allows creating new databases."),
828                        (
829                            "read",
830                            "Allows viewing databases associated with this server.",
831                        ),
832                        (
833                            "read-password",
834                            "Allows viewing the password associated with a database instance.",
835                        ),
836                        (
837                            "update",
838                            "Allows rotating the password on a database instance. Users without the read-password permission will not see the updated password.",
839                        ),
840                        (
841                            "recreate",
842                            "Allows deleting and recreating a database, in the process wiping all data.",
843                        ),
844                        (
845                            "delete",
846                            "Allows removing database instances from this server.",
847                        ),
848                        (
849                            "query",
850                            "Allows browsing a database's tables and reading their rows through the panel.",
851                        ),
852                        (
853                            "query-raw",
854                            "Allows running arbitrary SQL against a database. This grants full read and write access to its contents and structure, equivalent to the database's own credentials.",
855                        ),
856                        (
857                            "edit-rows",
858                            "Allows inserting, updating and deleting individual table rows through the panel. Statements are built by the panel, so this cannot alter a database's structure.",
859                        ),
860                        (
861                            "edit-structure",
862                            "Allows creating and renaming tables and columns through the panel. Statements are built by the panel from validated names and types, so this cannot read or destroy stored data.",
863                        ),
864                        (
865                            "delete-structure",
866                            "Allows deleting tables and columns through the panel, permanently destroying any data they contain.",
867                        ),
868                    ]),
869                },
870            ),
871            (
872                "database-instances",
873                PermissionGroup {
874                    description: "Permissions that control the ability to manage agent-managed database instances on this server.",
875                    permissions: IndexMap::from([
876                        ("create", "Allows creating new database instances."),
877                        (
878                            "read",
879                            "Allows viewing database instances associated with this server.",
880                        ),
881                        (
882                            "update",
883                            "Allows updating database instances, such as locking them.",
884                        ),
885                        (
886                            "apply-update",
887                            "Allows applying database agent template updates to database instances.",
888                        ),
889                        (
890                            "delete",
891                            "Allows removing database instances from this server.",
892                        ),
893                        (
894                            "power",
895                            "Allows starting, stopping and restarting database instances.",
896                        ),
897                        ("logs", "Allows viewing the logs of database instances."),
898                        (
899                            "databases",
900                            "Allows managing the databases inside database instances.",
901                        ),
902                        (
903                            "recreate",
904                            "Allows deleting and recreating databases inside database instances, in the process wiping all data.",
905                        ),
906                        (
907                            "users",
908                            "Allows managing the users inside database instances, including viewing their credentials.",
909                        ),
910                        ("import", "Allows importing data into database instances."),
911                        ("export", "Allows exporting data from database instances."),
912                        (
913                            "query",
914                            "Allows browsing an instance database's tables and reading their rows through the panel.",
915                        ),
916                        (
917                            "query-raw",
918                            "Allows running arbitrary SQL against an instance database. The agent connects as the instance administrator, so this grants full access to every database of the instance.",
919                        ),
920                        (
921                            "edit-rows",
922                            "Allows inserting, updating and deleting individual table rows through the panel. Statements are built by the panel, so this cannot alter a database's structure.",
923                        ),
924                        (
925                            "edit-structure",
926                            "Allows creating and renaming tables and columns through the panel. Statements are built by the panel from validated names and types, so this cannot read or destroy stored data.",
927                        ),
928                        (
929                            "delete-structure",
930                            "Allows deleting tables and columns through the panel, permanently destroying any data they contain.",
931                        ),
932                    ]),
933                },
934            ),
935            (
936                "mounts",
937                PermissionGroup {
938                    description: "Permissions that control the ability to manage server mounts.",
939                    permissions: IndexMap::from([
940                        ("attach", "Allows attaching new mounts to the server."),
941                        ("read", "Allows viewing existing mounts."),
942                        ("detach", "Allows detaching mounts from the server."),
943                    ]),
944                },
945            ),
946            (
947                "devices",
948                PermissionGroup {
949                    description: "Permissions that control the ability to manage server devices.",
950                    permissions: IndexMap::from([
951                        ("attach", "Allows attaching new devices to the server."),
952                        ("read", "Allows viewing existing devices."),
953                        ("detach", "Allows detaching devices from the server."),
954                    ]),
955                },
956            ),
957            (
958                "settings",
959                PermissionGroup {
960                    description: "Permissions that control the ability to manage settings on this server.",
961                    permissions: IndexMap::from([
962                        (
963                            "rename",
964                            "Allows renaming the server and changing its description.",
965                        ),
966                        ("timezone", "Allows changing the server's timezone."),
967                        (
968                            "auto-kill",
969                            "Allows changing the server's auto-kill settings.",
970                        ),
971                        (
972                            "auto-start",
973                            "Allows changing the server's auto-start settings.",
974                        ),
975                        ("trash", "Allows changing the server's trash settings."),
976                        ("install", "Allows triggering a reinstall of the server."),
977                        (
978                            "cancel-install",
979                            "Allows canceling the server's installation process.",
980                        ),
981                    ]),
982                },
983            ),
984            (
985                "activity",
986                PermissionGroup {
987                    description: "Permissions that control the ability to view the activity log on this server.",
988                    permissions: IndexMap::from([
989                        ("read", "Allows viewing the server's activity logs."),
990                        (
991                            "read-ip",
992                            "Allows viewing IP addresses associated with activity logs.",
993                        ),
994                    ]),
995                },
996            ),
997        ])
998    });
999
1000pub(crate) static SERVER_PERMISSIONS: LazyLock<parking_lot::RwLock<PermissionMap>> =
1001    LazyLock::new(|| parking_lot::RwLock::new(PermissionMap::new()));
1002
1003pub fn base_server_permission_keys() -> HashSet<String> {
1004    BASE_SERVER_PERMISSIONS
1005        .iter()
1006        .flat_map(|(group, permissions)| {
1007            permissions
1008                .permissions
1009                .keys()
1010                .map(move |permission| format!("{group}.{permission}"))
1011        })
1012        .collect()
1013}
1014
1015#[inline]
1016pub fn get_server_permissions() -> parking_lot::RwLockReadGuard<'static, PermissionMap> {
1017    SERVER_PERMISSIONS.read()
1018}
1019
1020#[inline]
1021pub fn validate_server_permissions(
1022    permissions: &[compact_str::CompactString],
1023    _context: &(),
1024) -> Result<(), garde::Error> {
1025    get_server_permissions().validate_permissions(permissions)
1026}