shared/
permissions.rs

1use indexmap::IndexMap;
2use serde::Serialize;
3use std::{
4    collections::HashSet,
5    sync::{LazyLock, RwLock, RwLockReadGuard},
6};
7use utoipa::ToSchema;
8
9#[derive(ToSchema, Serialize, Clone)]
10pub struct PermissionGroup {
11    description: &'static str,
12    permissions: IndexMap<&'static str, &'static str>,
13}
14
15#[derive(ToSchema, Serialize)]
16pub struct PermissionMap {
17    #[serde(skip)]
18    list: HashSet<String>,
19    #[serde(flatten)]
20    map: IndexMap<&'static str, PermissionGroup>,
21}
22
23impl PermissionMap {
24    pub(crate) fn new() -> Self {
25        Self {
26            list: HashSet::new(),
27            map: IndexMap::new(),
28        }
29    }
30
31    pub(crate) fn replace(&mut self, map: IndexMap<&'static str, PermissionGroup>) {
32        self.list = map
33            .iter()
34            .flat_map(|(key, group)| {
35                group
36                    .permissions
37                    .keys()
38                    .map(|permission| format!("{key}.{permission}"))
39                    .collect::<HashSet<_>>()
40            })
41            .collect();
42        self.map = map;
43    }
44
45    #[inline]
46    pub fn list(&self) -> &HashSet<String> {
47        &self.list
48    }
49
50    pub fn validate_permissions(
51        &self,
52        permissions: &[compact_str::CompactString],
53    ) -> Result<(), garde::Error> {
54        for permission in permissions {
55            if !self.list().contains(&**permission) {
56                return Err(garde::Error::new(compact_str::format_compact!(
57                    "invalid permission: {permission}"
58                )));
59            }
60        }
61
62        Ok(())
63    }
64}
65
66pub(crate) static BASE_USER_PERMISSIONS: LazyLock<IndexMap<&'static str, PermissionGroup>> =
67    LazyLock::new(|| {
68        IndexMap::from([
69            (
70                "account",
71                PermissionGroup {
72                    description: "Permissions that control the ability to change account settings.",
73                    permissions: IndexMap::from([
74                        ("email", "Allows changing the account's email address."),
75                        ("password", "Allows changing the account's password."),
76                        (
77                            "two-factor",
78                            "Allows adding and removing two-factor authentication.",
79                        ),
80                        (
81                            "avatar",
82                            "Allows updating and removing the account's avatar.",
83                        ),
84                    ]),
85                },
86            ),
87            (
88                "servers",
89                PermissionGroup {
90                    description: "Permissions that control the ability to list servers and manage server groups.",
91                    permissions: IndexMap::from([
92                        ("create", "Allows creating new server groups."),
93                        ("read", "Allows viewing servers and server groups."),
94                        ("update", "Allows modifying server groups."),
95                        ("delete", "Allows deleting server groups."),
96                    ]),
97                },
98            ),
99            (
100                "api-keys",
101                PermissionGroup {
102                    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.",
103                    permissions: IndexMap::from([
104                        ("create", "Allows creating new API keys."),
105                        ("read", "Allows viewing API keys and their permissions."),
106                        ("update", "Allows modifying other API keys."),
107                        ("delete", "Allows deleting API keys."),
108                    ]),
109                },
110            ),
111            (
112                "security-keys",
113                PermissionGroup {
114                    description: "Permissions that control the ability to manage security keys on an account.",
115                    permissions: IndexMap::from([
116                        ("create", "Allows creating new security keys."),
117                        ("read", "Allows viewing security keys."),
118                        ("update", "Allows modifying security keys."),
119                        ("delete", "Allows deleting security keys."),
120                    ]),
121                },
122            ),
123            (
124                "ssh-keys",
125                PermissionGroup {
126                    description: "Permissions that control the ability to manage SSH keys on an account.",
127                    permissions: IndexMap::from([
128                        ("create", "Allows creating or importing new SSH keys."),
129                        ("read", "Allows viewing SSH keys."),
130                        ("update", "Allows modifying other SSH keys."),
131                        ("delete", "Allows deleting SSH keys."),
132                    ]),
133                },
134            ),
135            (
136                "oauth-links",
137                PermissionGroup {
138                    description: "Permissions that control the ability to manage OAuth links on an account.",
139                    permissions: IndexMap::from([
140                        ("create", "Allows creating new OAuth links."),
141                        ("read", "Allows viewing OAuth links."),
142                        ("delete", "Allows deleting OAuth links."),
143                    ]),
144                },
145            ),
146            (
147                "command-snippets",
148                PermissionGroup {
149                    description: "Permissions that control the ability to manage command snippets on an account.",
150                    permissions: IndexMap::from([
151                        ("create", "Allows creating new command snippets."),
152                        ("read", "Allows viewing command snippets."),
153                        ("update", "Allows modifying command snippets."),
154                        ("delete", "Allows deleting command snippets."),
155                    ]),
156                },
157            ),
158            (
159                "sessions",
160                PermissionGroup {
161                    description: "Permissions that control the ability to manage sessions on an account.",
162                    permissions: IndexMap::from([
163                        ("read", "Allows viewing sessions and their IP addresses."),
164                        ("delete", "Allows deleting sessions."),
165                    ]),
166                },
167            ),
168            (
169                "activity",
170                PermissionGroup {
171                    description: "Permissions that control the ability to view the activity log on an account.",
172                    permissions: IndexMap::from([(
173                        "read",
174                        "Allows viewing the account's activity logs.",
175                    )]),
176                },
177            ),
178        ])
179    });
180
181pub(crate) static USER_PERMISSIONS: LazyLock<RwLock<PermissionMap>> =
182    LazyLock::new(|| RwLock::new(PermissionMap::new()));
183
184#[inline]
185pub fn get_user_permissions() -> RwLockReadGuard<'static, PermissionMap> {
186    USER_PERMISSIONS.read().unwrap()
187}
188
189#[inline]
190pub fn validate_user_permissions(
191    permissions: &[compact_str::CompactString],
192    _context: &(),
193) -> Result<(), garde::Error> {
194    get_user_permissions().validate_permissions(permissions)
195}
196
197pub(crate) static BASE_ADMIN_PERMISSIONS: LazyLock<IndexMap<&'static str, PermissionGroup>> =
198    LazyLock::new(|| {
199        IndexMap::from([
200            (
201                "stats",
202                PermissionGroup {
203                    description: "Permissions that control the ability to view stats for the panel.",
204                    permissions: IndexMap::from([("read", "Allows viewing panel statistics.")]),
205                },
206            ),
207            (
208                "settings",
209                PermissionGroup {
210                    description: "Permissions that control the ability to manage settings for the panel.",
211                    permissions: IndexMap::from([
212                        ("read", "Allows viewing panel settings and secrets."),
213                        ("update", "Allows modifying panel settings and secrets."),
214                    ]),
215                },
216            ),
217            (
218                "extensions",
219                PermissionGroup {
220                    description: "Permissions that control the ability to manage extensions for the panel.",
221                    permissions: IndexMap::from([
222                        ("read", "Allows viewing panel extensions."),
223                        (
224                            "manage",
225                            "Allows installing, updating, and removing panel extensions.",
226                        ),
227                    ]),
228                },
229            ),
230            (
231                "assets",
232                PermissionGroup {
233                    description: "Permissions that control the ability to manage assets for the panel.",
234                    permissions: IndexMap::from([
235                        ("read", "Allows viewing panel assets."),
236                        ("upload", "Allows creating and modifying assets."),
237                        ("delete", "Allows deleting panel assets."),
238                    ]),
239                },
240            ),
241            (
242                "users",
243                PermissionGroup {
244                    description: "Permissions that control the ability to manage users for the panel.",
245                    permissions: IndexMap::from([
246                        ("create", "Allows creating new users."),
247                        ("read", "Allows viewing users."),
248                        ("update", "Allows modifying users."),
249                        (
250                            "disable-two-factor",
251                            "Allows removing two-factor authentication from users.",
252                        ),
253                        ("delete", "Allows deleting users."),
254                        ("activity", "Allows viewing a user's activity log."),
255                        (
256                            "oauth-links",
257                            "Allows viewing and managing a user's OAuth links.",
258                        ),
259                        ("impersonate", "Allows impersonating other users."),
260                    ]),
261                },
262            ),
263            (
264                "roles",
265                PermissionGroup {
266                    description: "Permissions that control the ability to manage roles for the panel.",
267                    permissions: IndexMap::from([
268                        ("create", "Allows creating new roles."),
269                        ("read", "Allows viewing roles."),
270                        ("update", "Allows modifying roles."),
271                        ("delete", "Allows deleting roles."),
272                    ]),
273                },
274            ),
275            (
276                "locations",
277                PermissionGroup {
278                    description: "Permissions that control the ability to manage locations for the panel.",
279                    permissions: IndexMap::from([
280                        ("create", "Allows creating new locations."),
281                        ("read", "Allows viewing locations."),
282                        ("update", "Allows modifying locations."),
283                        ("delete", "Allows deleting locations."),
284                        (
285                            "database-hosts",
286                            "Allows viewing and managing a location's database hosts.",
287                        ),
288                    ]),
289                },
290            ),
291            (
292                "backup-configurations",
293                PermissionGroup {
294                    description: "Permissions that control the ability to manage backup configurations for the panel.",
295                    permissions: IndexMap::from([
296                        ("create", "Allows creating new backup configurations."),
297                        (
298                            "read",
299                            "Allows viewing backup configurations and their passwords.",
300                        ),
301                        (
302                            "update",
303                            "Allows modifying backup configurations and their passwords.",
304                        ),
305                        ("delete", "Allows deleting backup configurations."),
306                        (
307                            "backups",
308                            "Allows viewing backups associated with a backup configuration.",
309                        ),
310                    ]),
311                },
312            ),
313            (
314                "nodes",
315                PermissionGroup {
316                    description: "Permissions that control the ability to manage nodes for the panel.",
317                    permissions: IndexMap::from([
318                        ("create", "Allows creating new nodes."),
319                        ("read", "Allows viewing nodes and their tokens."),
320                        ("update", "Allows modifying nodes."),
321                        ("delete", "Allows deleting nodes."),
322                        ("reset-token", "Allows resetting a node's token."),
323                        (
324                            "allocations",
325                            "Allows viewing and managing a node's allocations.",
326                        ),
327                        ("mounts", "Allows viewing and managing a node's mounts."),
328                        ("backups", "Allows viewing and managing a node's backups."),
329                        ("power", "Allows executing mass-power actions on nodes."),
330                        (
331                            "transfers",
332                            "Allows viewing and managing mass-server transfers between nodes.",
333                        ),
334                    ]),
335                },
336            ),
337            (
338                "servers",
339                PermissionGroup {
340                    description: "Permissions that control the ability to manage servers for the panel.",
341                    permissions: IndexMap::from([
342                        ("create", "Allows creating new servers."),
343                        ("read", "Allows viewing servers."),
344                        ("update", "Allows modifying servers."),
345                        ("delete", "Allows deleting servers."),
346                        ("transfer", "Allows transferring servers to other nodes."),
347                        (
348                            "allocations",
349                            "Allows viewing and managing a server's allocations.",
350                        ),
351                        (
352                            "variables",
353                            "Allows viewing and managing a server's variables.",
354                        ),
355                        ("mounts", "Allows viewing and managing a server's mounts."),
356                    ]),
357                },
358            ),
359            (
360                "nests",
361                PermissionGroup {
362                    description: "Permissions that control the ability to manage nests for the panel.",
363                    permissions: IndexMap::from([
364                        ("create", "Allows creating new nests."),
365                        ("read", "Allows viewing nests."),
366                        ("update", "Allows modifying nests."),
367                        ("delete", "Allows deleting nests."),
368                    ]),
369                },
370            ),
371            (
372                "eggs",
373                PermissionGroup {
374                    description: "Permissions that control the ability to manage eggs for the panel.",
375                    permissions: IndexMap::from([
376                        ("create", "Allows creating and importing new eggs."),
377                        ("read", "Allows viewing eggs."),
378                        ("update", "Allows modifying eggs."),
379                        ("delete", "Allows deleting eggs."),
380                        ("mounts", "Allows viewing and managing an egg's mounts."),
381                    ]),
382                },
383            ),
384            (
385                "egg-repositories",
386                PermissionGroup {
387                    description: "Permissions that control the ability to manage egg repositories for the panel.",
388                    permissions: IndexMap::from([
389                        ("create", "Allows creating new egg repositories."),
390                        ("read", "Allows viewing egg repositories."),
391                        ("update", "Allows modifying egg repositories."),
392                        ("delete", "Allows deleting egg repositories."),
393                        (
394                            "sync",
395                            "Allows synchronizing egg repositories with their remote sources.",
396                        ),
397                    ]),
398                },
399            ),
400            (
401                "database-hosts",
402                PermissionGroup {
403                    description: "Permissions that control the ability to manage database hosts for the panel.",
404                    permissions: IndexMap::from([
405                        ("create", "Allows creating new database hosts."),
406                        ("read", "Allows viewing database hosts."),
407                        ("update", "Allows modifying database hosts."),
408                        ("delete", "Allows deleting database hosts."),
409                    ]),
410                },
411            ),
412            (
413                "oauth-providers",
414                PermissionGroup {
415                    description: "Permissions that control the ability to manage OAuth providers for the panel.",
416                    permissions: IndexMap::from([
417                        ("create", "Allows creating new OAuth providers."),
418                        ("read", "Allows viewing OAuth providers."),
419                        ("update", "Allows modifying OAuth providers."),
420                        ("delete", "Allows deleting OAuth providers."),
421                    ]),
422                },
423            ),
424            (
425                "mounts",
426                PermissionGroup {
427                    description: "Permissions that control the ability to manage mounts for the panel.",
428                    permissions: IndexMap::from([
429                        ("create", "Allows creating new mounts."),
430                        ("read", "Allows viewing mounts."),
431                        ("update", "Allows modifying mounts."),
432                        ("delete", "Allows deleting mounts."),
433                    ]),
434                },
435            ),
436            (
437                "activity",
438                PermissionGroup {
439                    description: "Permissions that control the ability to view the activity log for all admin operations.",
440                    permissions: IndexMap::from([(
441                        "read",
442                        "Allows viewing the activity logs for all admin operations.",
443                    )]),
444                },
445            ),
446        ])
447    });
448
449pub(crate) static ADMIN_PERMISSIONS: LazyLock<RwLock<PermissionMap>> =
450    LazyLock::new(|| RwLock::new(PermissionMap::new()));
451
452#[inline]
453pub fn get_admin_permissions() -> RwLockReadGuard<'static, PermissionMap> {
454    ADMIN_PERMISSIONS.read().unwrap()
455}
456
457#[inline]
458pub fn validate_admin_permissions(
459    permissions: &[compact_str::CompactString],
460    _context: &(),
461) -> Result<(), garde::Error> {
462    get_admin_permissions().validate_permissions(permissions)
463}
464
465pub(crate) static BASE_SERVER_PERMISSIONS: LazyLock<IndexMap<&'static str, PermissionGroup>> =
466    LazyLock::new(|| {
467        IndexMap::from([
468            (
469                "control",
470                PermissionGroup {
471                    description: "Permissions that control the ability to control the power state of a server, read the console, or send commands.",
472                    permissions: IndexMap::from([
473                        ("read-console", "Allows reading the server console logs."),
474                        (
475                            "console",
476                            "Allows sending commands to the server instance via the console.",
477                        ),
478                        ("start", "Allows starting the server if it is stopped."),
479                        ("stop", "Allows stopping the server if it is running."),
480                        (
481                            "restart",
482                            "Allows restarting the server. This permits starting the server if it is offline, but not placing it in a completely stopped state.",
483                        ),
484                    ]),
485                },
486            ),
487            (
488                "subusers",
489                PermissionGroup {
490                    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.",
491                    permissions: IndexMap::from([
492                        ("create", "Allows creating new subusers for the server."),
493                        ("read", "Allows viewing subusers and their permissions."),
494                        ("update", "Allows modifying other subusers."),
495                        ("delete", "Allows deleting subusers from the server."),
496                    ]),
497                },
498            ),
499            (
500                "files",
501                PermissionGroup {
502                    description: "Permissions that control the ability to modify the filesystem for this server.",
503                    permissions: IndexMap::from([
504                        (
505                            "create",
506                            "Allows creating additional files and folders via the panel or direct upload.",
507                        ),
508                        (
509                            "read",
510                            "Allows viewing the contents of a directory, but not reading or downloading individual files.",
511                        ),
512                        (
513                            "read-content",
514                            "Allows viewing the contents of a specific file. This also permits downloading files.",
515                        ),
516                        (
517                            "update",
518                            "Allows updating the contents of an existing file or directory.",
519                        ),
520                        ("delete", "Allows deleting files or directories."),
521                        ("archive", "Allows archiving the contents of a directory."),
522                        ("sftp", "Allows connecting via SFTP to manage files."),
523                    ]),
524                },
525            ),
526            (
527                "backups",
528                PermissionGroup {
529                    description: "Permissions that control the ability to manage server backups.",
530                    permissions: IndexMap::from([
531                        ("create", "Allows creating new backups for the server."),
532                        ("read", "Allows viewing existing backups."),
533                        ("download", "Allows downloading backups."),
534                        ("restore", "Allows restoring backups."),
535                        ("update", "Allows updating existing backups."),
536                        ("delete", "Allows deleting backups."),
537                    ]),
538                },
539            ),
540            (
541                "schedules",
542                PermissionGroup {
543                    description: "Permissions that control the ability to manage server schedules.",
544                    permissions: IndexMap::from([
545                        ("create", "Allows creating new schedules."),
546                        ("read", "Allows viewing existing schedules."),
547                        ("update", "Allows updating existing schedules."),
548                        ("delete", "Allows deleting schedules."),
549                    ]),
550                },
551            ),
552            (
553                "allocations",
554                PermissionGroup {
555                    description: "Permissions that control the ability to modify the port allocations for this server.",
556                    permissions: IndexMap::from([
557                        (
558                            "read",
559                            "Allows viewing all allocations currently assigned to this server. Users with any level of access can always view the primary allocation.",
560                        ),
561                        (
562                            "create",
563                            "Allows assigning additional allocations to the server.",
564                        ),
565                        (
566                            "update",
567                            "Allows changing the primary server allocation and attaching notes to allocations.",
568                        ),
569                        ("delete", "Allows deleting allocations from the server."),
570                    ]),
571                },
572            ),
573            (
574                "startup",
575                PermissionGroup {
576                    description: "Permissions that control the ability to view and modify this server's startup parameters.",
577                    permissions: IndexMap::from([
578                        (
579                            "read",
580                            "Allows viewing the startup variables for the server.",
581                        ),
582                        ("update", "Allows modifying the startup variables."),
583                        (
584                            "command",
585                            "Allows modifying the command used to start the server.",
586                        ),
587                        (
588                            "docker-image",
589                            "Allows modifying the Docker image used when running the server.",
590                        ),
591                    ]),
592                },
593            ),
594            (
595                "databases",
596                PermissionGroup {
597                    description: "Permissions that control the ability to manage databases on this server.",
598                    permissions: IndexMap::from([
599                        ("create", "Allows creating new databases."),
600                        (
601                            "read",
602                            "Allows viewing databases associated with this server.",
603                        ),
604                        (
605                            "read-password",
606                            "Allows viewing the password associated with a database instance.",
607                        ),
608                        (
609                            "update",
610                            "Allows rotating the password on a database instance. Users without the read-password permission will not see the updated password.",
611                        ),
612                        (
613                            "delete",
614                            "Allows removing database instances from this server.",
615                        ),
616                    ]),
617                },
618            ),
619            (
620                "mounts",
621                PermissionGroup {
622                    description: "Permissions that control the ability to manage server mounts.",
623                    permissions: IndexMap::from([
624                        ("attach", "Allows attaching new mounts to the server."),
625                        ("read", "Allows viewing existing mounts."),
626                        ("detach", "Allows detaching mounts from the server."),
627                    ]),
628                },
629            ),
630            (
631                "settings",
632                PermissionGroup {
633                    description: "Permissions that control the ability to manage settings on this server.",
634                    permissions: IndexMap::from([
635                        (
636                            "rename",
637                            "Allows renaming the server and changing its description.",
638                        ),
639                        ("timezone", "Allows changing the server's timezone."),
640                        (
641                            "auto-kill",
642                            "Allows changing the server's auto-kill settings.",
643                        ),
644                        (
645                            "auto-start",
646                            "Allows changing the server's auto-start settings.",
647                        ),
648                        ("install", "Allows triggering a reinstall of the server."),
649                        (
650                            "cancel-install",
651                            "Allows canceling the server's installation process.",
652                        ),
653                    ]),
654                },
655            ),
656            (
657                "activity",
658                PermissionGroup {
659                    description: "Permissions that control the ability to view the activity log on this server.",
660                    permissions: IndexMap::from([(
661                        "read",
662                        "Allows viewing the server's activity logs.",
663                    )]),
664                },
665            ),
666        ])
667    });
668
669pub(crate) static SERVER_PERMISSIONS: LazyLock<RwLock<PermissionMap>> =
670    LazyLock::new(|| RwLock::new(PermissionMap::new()));
671
672#[inline]
673pub fn get_server_permissions() -> RwLockReadGuard<'static, PermissionMap> {
674    SERVER_PERMISSIONS.read().unwrap()
675}
676
677#[inline]
678pub fn validate_server_permissions(
679    permissions: &[compact_str::CompactString],
680    _context: &(),
681) -> Result<(), garde::Error> {
682    get_server_permissions().validate_permissions(permissions)
683}