Skip to content

Commit 3f0e765

Browse files
committed
dev: add support to imply shortcut permissions
Permission implicators with the "shortcut" option will be checked prior to concurrent permission scanning. If any of these permissions are granted, then the concurrent phase of permission scanning will not be invoked; instead, the user will only see the shortcut permission. It may be useful to add an option in the future for a full permission scan, which could be useful in such things as a user interface to help with permission management.
1 parent 3f483c5 commit 3f0e765

File tree

3 files changed

+49
-3
lines changed

3 files changed

+49
-3
lines changed

src/backend/src/services/auth/PermissionService.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,14 +77,15 @@ class PermissionRewriter {
7777
* The actor and permission are passed to checker({ actor, permission }) as an object.
7878
*/
7979
class PermissionImplicator {
80-
static create ({ id, matcher, checker }) {
81-
return new PermissionImplicator({ id, matcher, checker });
80+
static create ({ id, matcher, checker, ...options }) {
81+
return new PermissionImplicator({ id, matcher, checker, options });
8282
}
8383

84-
constructor ({ id, matcher, checker }) {
84+
constructor ({ id, matcher, checker, options }) {
8585
this.id = id;
8686
this.matcher = matcher;
8787
this.checker = checker;
88+
this.options = options;
8889
}
8990

9091
matches (permission) {

src/backend/src/structured/sequence/scan-permission.js

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,42 @@ module.exports = new Sequence([
7575
}
7676
a.set('permission_options', permission_options.flat());
7777
},
78+
async function handle_shortcuts (a) {
79+
const reading = a.get('reading');
80+
const { actor, permission_options } = a.values();
81+
82+
const _permission_implicators = a.iget('_permission_implicators');
83+
84+
for ( const permission of permission_options )
85+
for ( const implicator of _permission_implicators ) {
86+
if ( ! implicator.options?.shortcut ) continue;
87+
88+
// TODO: is it possible to DRY this with concurrent implicators in permission-scanners.js?
89+
if ( ! implicator.matches(permission) ) {
90+
continue;
91+
}
92+
const implied = await implicator.check({
93+
actor,
94+
permission,
95+
});
96+
if ( implied ) {
97+
reading.push({
98+
$: 'option',
99+
permission,
100+
source: 'implied',
101+
by: implicator.id,
102+
data: implied,
103+
...((!!actor.type.user)
104+
? { holder_username: actor.type.user.username }
105+
: {}),
106+
});
107+
if ( implicator.options?.shortcut ) {
108+
a.stop();
109+
return;
110+
}
111+
}
112+
}
113+
},
78114
async function run_scanners (a) {
79115
const scanners = PERMISSION_SCANNERS;
80116
const ps = [];

src/backend/src/unstructured/permission-scanners.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ const PERMISSION_SCANNERS = [
6161

6262
for ( const permission of permission_options )
6363
for ( const implicator of _permission_implicators ) {
64+
if ( implicator.options?.shortcut ) continue;
65+
6466
if ( ! implicator.matches(permission) ) {
6567
continue;
6668
}
@@ -75,7 +77,14 @@ const PERMISSION_SCANNERS = [
7577
source: 'implied',
7678
by: implicator.id,
7779
data: implied,
80+
...((!!actor.type.user)
81+
? { holder_username: actor.type.user.username }
82+
: {}),
7883
});
84+
if ( implicator.options?.shortcut ) {
85+
a.stop();
86+
return;
87+
}
7988
}
8089
}
8190
}

0 commit comments

Comments
 (0)