Skip to content

Commit cef319c

Browse files
committed
Refactor owner -> self for the specific user use-case
1 parent 470e845 commit cef319c

File tree

3 files changed

+66
-2
lines changed

3 files changed

+66
-2
lines changed
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { owner, Policy } from '../util';
1+
import { Policy, self } from '../util';
22

3-
@Policy('all', (r) => r.User.when(owner).edit)
3+
@Policy('all', (r) => r.User.when(self).edit)
44
export class UserCanEditSelfPolicy {}

src/components/authorization/policies/conditions/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ export * from './sensitivity.condition';
44
export * from './enum-field.condition';
55
export * from './variant.condition';
66
export * from './role.condition';
7+
export * from './self.condition';
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import { Query } from 'cypher-query-builder';
2+
import { inspect, InspectOptionsStylized } from 'util';
3+
import { User } from '../../../user/dto';
4+
import {
5+
AsCypherParams,
6+
Condition,
7+
IsAllowedParams,
8+
} from '../../policy/conditions';
9+
10+
const CQL_VAR = 'requestingUser';
11+
12+
class SelfCondition<TResourceStatic extends typeof User>
13+
implements Condition<TResourceStatic>
14+
{
15+
isAllowed({ object, session }: IsAllowedParams<TResourceStatic>) {
16+
if (!object) {
17+
throw new Error("Needed user object but wasn't given");
18+
}
19+
return object.id === session.userId;
20+
}
21+
22+
setupCypherContext(
23+
query: Query,
24+
prevApplied: Set<any>,
25+
other: AsCypherParams<TResourceStatic>,
26+
) {
27+
if (prevApplied.has('self')) {
28+
return query;
29+
}
30+
prevApplied.add('self');
31+
32+
const param = query.params.addParam(other.session.userId, CQL_VAR);
33+
Reflect.set(other, CQL_VAR, param);
34+
35+
return query;
36+
}
37+
38+
asCypherCondition(_query: Query, other: AsCypherParams<TResourceStatic>) {
39+
const requester = String(Reflect.get(other, CQL_VAR));
40+
return `node:User AND node.id = ${requester}`;
41+
}
42+
43+
asEdgeQLCondition() {
44+
return '.id ?= global default::currentUserId';
45+
}
46+
47+
union(this: void, conditions: this[]) {
48+
return conditions[0];
49+
}
50+
51+
intersect(this: void, conditions: this[]) {
52+
return conditions[0];
53+
}
54+
55+
[inspect.custom](_depth: number, _options: InspectOptionsStylized) {
56+
return `Self`;
57+
}
58+
}
59+
60+
/**
61+
* The following actions only apply if the requester is this user object.
62+
*/
63+
export const self = new SelfCondition();

0 commit comments

Comments
 (0)