permission.spec.ts raw
1 import { Permission, PermissionChecker } from './permission';
2 import { IdentityId } from '../value-objects';
3
4 describe('Permission Entity', () => {
5 const testIdentityId = IdentityId.from('identity-1');
6 const testHost = 'example.com';
7 const testMethod = 'signEvent';
8
9 describe('allow', () => {
10 it('should create an allow permission', () => {
11 const permission = Permission.allow(testIdentityId, testHost, testMethod);
12
13 expect(permission.isAllowed()).toBe(true);
14 });
15
16 it('should create permission with kind for signEvent', () => {
17 const permission = Permission.allow(testIdentityId, testHost, testMethod, 1);
18
19 expect(permission.isAllowed()).toBe(true);
20 });
21 });
22
23 describe('deny', () => {
24 it('should create a deny permission', () => {
25 const permission = Permission.deny(testIdentityId, testHost, testMethod);
26
27 expect(permission.isAllowed()).toBe(false);
28 });
29 });
30
31 describe('matches', () => {
32 it('should match when all parameters are the same', () => {
33 const permission = Permission.allow(testIdentityId, testHost, testMethod);
34
35 expect(permission.matches(testIdentityId, testHost, testMethod)).toBe(true);
36 });
37
38 it('should not match when identity differs', () => {
39 const permission = Permission.allow(testIdentityId, testHost, testMethod);
40 const differentIdentity = IdentityId.from('identity-2');
41
42 expect(permission.matches(differentIdentity, testHost, testMethod)).toBe(false);
43 });
44
45 it('should not match when host differs', () => {
46 const permission = Permission.allow(testIdentityId, testHost, testMethod);
47
48 expect(permission.matches(testIdentityId, 'other.com', testMethod)).toBe(false);
49 });
50
51 it('should not match when method differs', () => {
52 const permission = Permission.allow(testIdentityId, testHost, testMethod);
53
54 expect(permission.matches(testIdentityId, testHost, 'getPublicKey')).toBe(false);
55 });
56
57 it('should match any kind when permission has no kind specified', () => {
58 const permission = Permission.allow(testIdentityId, testHost, testMethod);
59
60 expect(permission.matches(testIdentityId, testHost, testMethod, 1)).toBe(true);
61 expect(permission.matches(testIdentityId, testHost, testMethod, 30023)).toBe(true);
62 });
63
64 it('should only match specific kind when permission has kind', () => {
65 const permission = Permission.allow(testIdentityId, testHost, testMethod, 1);
66
67 expect(permission.matches(testIdentityId, testHost, testMethod, 1)).toBe(true);
68 expect(permission.matches(testIdentityId, testHost, testMethod, 30023)).toBe(false);
69 });
70 });
71
72 describe('fromSnapshot', () => {
73 it('should reconstruct permission from snapshot', () => {
74 const original = Permission.allow(testIdentityId, testHost, testMethod, 1);
75 const snapshot = original.toSnapshot();
76
77 const restored = Permission.fromSnapshot(snapshot);
78
79 expect(restored.isAllowed()).toBe(true);
80 expect(restored.matches(testIdentityId, testHost, testMethod, 1)).toBe(true);
81 });
82 });
83
84 describe('toSnapshot', () => {
85 it('should create valid snapshot', () => {
86 const permission = Permission.allow(testIdentityId, testHost, testMethod, 1);
87 const snapshot = permission.toSnapshot();
88
89 expect(snapshot.identityId).toEqual(testIdentityId.toString());
90 expect(snapshot.host).toEqual(testHost);
91 expect(snapshot.method).toEqual(testMethod);
92 expect(snapshot.methodPolicy).toEqual('allow');
93 expect(snapshot.kind).toBe(1);
94 });
95 });
96 });
97
98 describe('PermissionChecker', () => {
99 const identity1 = IdentityId.from('identity-1');
100 const identity2 = IdentityId.from('identity-2');
101
102 describe('check', () => {
103 it('should return true for allowed permission', () => {
104 const permissions = [
105 Permission.allow(identity1, 'example.com', 'signEvent'),
106 ];
107 const checker = new PermissionChecker(permissions);
108
109 expect(checker.check(identity1, 'example.com', 'signEvent')).toBe(true);
110 });
111
112 it('should return false for denied permission', () => {
113 const permissions = [
114 Permission.deny(identity1, 'example.com', 'signEvent'),
115 ];
116 const checker = new PermissionChecker(permissions);
117
118 expect(checker.check(identity1, 'example.com', 'signEvent')).toBe(false);
119 });
120
121 it('should return undefined when no matching permission exists', () => {
122 const permissions = [
123 Permission.allow(identity1, 'example.com', 'signEvent'),
124 ];
125 const checker = new PermissionChecker(permissions);
126
127 expect(checker.check(identity2, 'example.com', 'signEvent')).toBeUndefined();
128 });
129
130 it('should check kind-specific permissions first', () => {
131 const permissions = [
132 Permission.deny(identity1, 'example.com', 'signEvent', 1), // Deny kind 1
133 Permission.allow(identity1, 'example.com', 'signEvent'), // Allow all others
134 ];
135 const checker = new PermissionChecker(permissions);
136
137 expect(checker.check(identity1, 'example.com', 'signEvent', 1)).toBe(false);
138 expect(checker.check(identity1, 'example.com', 'signEvent', 30023)).toBe(true);
139 });
140
141 it('should handle multiple identities', () => {
142 const permissions = [
143 Permission.allow(identity1, 'example.com', 'signEvent'),
144 Permission.deny(identity2, 'example.com', 'signEvent'),
145 ];
146 const checker = new PermissionChecker(permissions);
147
148 expect(checker.check(identity1, 'example.com', 'signEvent')).toBe(true);
149 expect(checker.check(identity2, 'example.com', 'signEvent')).toBe(false);
150 });
151
152 it('should handle multiple hosts', () => {
153 const permissions = [
154 Permission.allow(identity1, 'allowed.com', 'signEvent'),
155 Permission.deny(identity1, 'denied.com', 'signEvent'),
156 ];
157 const checker = new PermissionChecker(permissions);
158
159 expect(checker.check(identity1, 'allowed.com', 'signEvent')).toBe(true);
160 expect(checker.check(identity1, 'denied.com', 'signEvent')).toBe(false);
161 expect(checker.check(identity1, 'unknown.com', 'signEvent')).toBeUndefined();
162 });
163
164 it('should handle multiple methods', () => {
165 const permissions = [
166 Permission.allow(identity1, 'example.com', 'getPublicKey'),
167 Permission.deny(identity1, 'example.com', 'signEvent'),
168 ];
169 const checker = new PermissionChecker(permissions);
170
171 expect(checker.check(identity1, 'example.com', 'getPublicKey')).toBe(true);
172 expect(checker.check(identity1, 'example.com', 'signEvent')).toBe(false);
173 });
174 });
175 });
176