@stevenkellner/team-conduct-api 2.0.6 → 2.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -26,12 +26,12 @@ type ExpectedUserRoles = UserRole | ExpectedUserRoles[] | {
|
|
|
26
26
|
* 5. Ensures the person is signed in (has signInProperties)
|
|
27
27
|
* 6. Verifies the person has the required roles
|
|
28
28
|
*
|
|
29
|
-
* @param
|
|
29
|
+
* @param userAuthId - The raw user authentication ID string from authentication context (null if not authenticated)
|
|
30
30
|
* @param teamId - The ID of the team to check membership and roles for
|
|
31
31
|
* @param roles - The expected role requirements (supports AND/OR logic via ExpectedUserRoles)
|
|
32
32
|
* @returns The validated User.Id if all checks pass
|
|
33
33
|
* @throws {FunctionsError} 'unauthenticated' - If rawUserId is null
|
|
34
34
|
* @throws {FunctionsError} 'permission-denied' - If any validation check fails
|
|
35
35
|
*/
|
|
36
|
-
export declare function checkAuthentication(
|
|
36
|
+
export declare function checkAuthentication(userAuthId: string | null, teamId: Team.Id, roles: ExpectedUserRoles): Promise<User.Id>;
|
|
37
37
|
export {};
|
|
@@ -30,17 +30,20 @@ function hasUserRoles(userRoles, expectedRoles) {
|
|
|
30
30
|
* 5. Ensures the person is signed in (has signInProperties)
|
|
31
31
|
* 6. Verifies the person has the required roles
|
|
32
32
|
*
|
|
33
|
-
* @param
|
|
33
|
+
* @param userAuthId - The raw user authentication ID string from authentication context (null if not authenticated)
|
|
34
34
|
* @param teamId - The ID of the team to check membership and roles for
|
|
35
35
|
* @param roles - The expected role requirements (supports AND/OR logic via ExpectedUserRoles)
|
|
36
36
|
* @returns The validated User.Id if all checks pass
|
|
37
37
|
* @throws {FunctionsError} 'unauthenticated' - If rawUserId is null
|
|
38
38
|
* @throws {FunctionsError} 'permission-denied' - If any validation check fails
|
|
39
39
|
*/
|
|
40
|
-
async function checkAuthentication(
|
|
41
|
-
if (
|
|
40
|
+
async function checkAuthentication(userAuthId, teamId, roles) {
|
|
41
|
+
if (userAuthId === null)
|
|
42
42
|
throw new firebase_function_1.FunctionsError('unauthenticated', 'User is not authenticated');
|
|
43
|
-
const
|
|
43
|
+
const userAuthenticationId = await Firestore_1.Firestore.shared.userAuthentication(userAuthId).snapshot();
|
|
44
|
+
if (!userAuthenticationId.exists)
|
|
45
|
+
throw new firebase_function_1.FunctionsError('permission-denied', 'User authentication does not exist');
|
|
46
|
+
const userId = types_1.User.Id.builder.build(userAuthenticationId.data);
|
|
44
47
|
const userSnapshot = await Firestore_1.Firestore.shared.user(userId).snapshot();
|
|
45
48
|
if (!userSnapshot.exists)
|
|
46
49
|
throw new firebase_function_1.FunctionsError('permission-denied', 'User does not exist');
|
|
@@ -9,6 +9,7 @@ const firebase_utils_1 = require("./firebase-utils");
|
|
|
9
9
|
(0, mocha_1.describe)('checkAuthentication', () => {
|
|
10
10
|
const teamId = index_1.Team.Id.builder.build('11111111-1111-4111-1111-111111111111');
|
|
11
11
|
const personId = index_1.Person.Id.builder.build('22222222-2222-4222-2222-222222222222');
|
|
12
|
+
const userAuthId = 'auth-123';
|
|
12
13
|
const userId = index_1.User.Id.builder.build('user123');
|
|
13
14
|
(0, mocha_1.describe)('checkAuthentication - basic validation', () => {
|
|
14
15
|
(0, mocha_1.it)('should throw "unauthenticated" error if rawUserId is null', async () => {
|
|
@@ -16,25 +17,41 @@ const firebase_utils_1 = require("./firebase-utils");
|
|
|
16
17
|
await (0, checkAuthentication_1.checkAuthentication)(null, teamId, 'team-manager');
|
|
17
18
|
}, 'unauthenticated', 'User is not authenticated');
|
|
18
19
|
});
|
|
20
|
+
(0, mocha_1.it)('should throw "permission-denied" if user authentication does not exist', async () => {
|
|
21
|
+
(0, firebase_utils_1.configureFirebase)({
|
|
22
|
+
userAuthentications: firebase_utils_1.Collection.docs({
|
|
23
|
+
[userAuthId]: firebase_utils_1.Document.empty()
|
|
24
|
+
})
|
|
25
|
+
});
|
|
26
|
+
await (0, firebase_utils_1.expectThrowsFunctionsError)(async () => {
|
|
27
|
+
await (0, checkAuthentication_1.checkAuthentication)(userAuthId, teamId, 'team-manager');
|
|
28
|
+
}, 'permission-denied', 'User authentication does not exist');
|
|
29
|
+
});
|
|
19
30
|
(0, mocha_1.it)('should throw "permission-denied" if user does not exist', async () => {
|
|
20
31
|
(0, firebase_utils_1.configureFirebase)({
|
|
32
|
+
userAuthentications: firebase_utils_1.Collection.docs({
|
|
33
|
+
[userAuthId]: firebase_utils_1.Document.data(userId.value)
|
|
34
|
+
}),
|
|
21
35
|
users: firebase_utils_1.Collection.docs({
|
|
22
36
|
[userId.value]: firebase_utils_1.Document.empty()
|
|
23
37
|
})
|
|
24
38
|
});
|
|
25
39
|
await (0, firebase_utils_1.expectThrowsFunctionsError)(async () => {
|
|
26
|
-
await (0, checkAuthentication_1.checkAuthentication)(
|
|
40
|
+
await (0, checkAuthentication_1.checkAuthentication)(userAuthId, teamId, 'team-manager');
|
|
27
41
|
}, 'permission-denied', 'User does not exist');
|
|
28
42
|
});
|
|
29
43
|
(0, mocha_1.it)('should throw "permission-denied" if user is not a member of the team', async () => {
|
|
30
44
|
const emptyTeams = new typescript_common_functionality_1.Dictionary(index_1.Team.Id.builder);
|
|
31
45
|
(0, firebase_utils_1.configureFirebase)({
|
|
46
|
+
userAuthentications: firebase_utils_1.Collection.docs({
|
|
47
|
+
[userAuthId]: firebase_utils_1.Document.data(userId.value)
|
|
48
|
+
}),
|
|
32
49
|
users: firebase_utils_1.Collection.docs({
|
|
33
50
|
[userId.value]: firebase_utils_1.Document.user(userId, emptyTeams)
|
|
34
51
|
})
|
|
35
52
|
});
|
|
36
53
|
await (0, firebase_utils_1.expectThrowsFunctionsError)(async () => {
|
|
37
|
-
await (0, checkAuthentication_1.checkAuthentication)(
|
|
54
|
+
await (0, checkAuthentication_1.checkAuthentication)(userAuthId, teamId, 'team-manager');
|
|
38
55
|
}, 'permission-denied', 'User is not a member of the team');
|
|
39
56
|
});
|
|
40
57
|
(0, mocha_1.it)('should throw "permission-denied" if person does not exist', async () => {
|
|
@@ -45,6 +62,9 @@ const firebase_utils_1 = require("./firebase-utils");
|
|
|
45
62
|
personId: personId.guidString
|
|
46
63
|
}));
|
|
47
64
|
(0, firebase_utils_1.configureFirebase)({
|
|
65
|
+
userAuthentications: firebase_utils_1.Collection.docs({
|
|
66
|
+
[userAuthId]: firebase_utils_1.Document.data(userId.value)
|
|
67
|
+
}),
|
|
48
68
|
users: firebase_utils_1.Collection.docs({
|
|
49
69
|
[userId.value]: firebase_utils_1.Document.user(userId, teams)
|
|
50
70
|
}),
|
|
@@ -57,7 +77,7 @@ const firebase_utils_1 = require("./firebase-utils");
|
|
|
57
77
|
})
|
|
58
78
|
});
|
|
59
79
|
await (0, firebase_utils_1.expectThrowsFunctionsError)(async () => {
|
|
60
|
-
await (0, checkAuthentication_1.checkAuthentication)(
|
|
80
|
+
await (0, checkAuthentication_1.checkAuthentication)(userAuthId, teamId, 'team-manager');
|
|
61
81
|
}, 'permission-denied', 'Person does not exist');
|
|
62
82
|
});
|
|
63
83
|
(0, mocha_1.it)('should throw "permission-denied" if person is not signed in', async () => {
|
|
@@ -68,6 +88,9 @@ const firebase_utils_1 = require("./firebase-utils");
|
|
|
68
88
|
personId: personId.guidString
|
|
69
89
|
}));
|
|
70
90
|
(0, firebase_utils_1.configureFirebase)({
|
|
91
|
+
userAuthentications: firebase_utils_1.Collection.docs({
|
|
92
|
+
[userAuthId]: firebase_utils_1.Document.data(userId.value)
|
|
93
|
+
}),
|
|
71
94
|
users: firebase_utils_1.Collection.docs({
|
|
72
95
|
[userId.value]: firebase_utils_1.Document.user(userId, teams)
|
|
73
96
|
}),
|
|
@@ -80,7 +103,7 @@ const firebase_utils_1 = require("./firebase-utils");
|
|
|
80
103
|
})
|
|
81
104
|
});
|
|
82
105
|
await (0, firebase_utils_1.expectThrowsFunctionsError)(async () => {
|
|
83
|
-
await (0, checkAuthentication_1.checkAuthentication)(
|
|
106
|
+
await (0, checkAuthentication_1.checkAuthentication)(userAuthId, teamId, 'team-manager');
|
|
84
107
|
}, 'permission-denied', 'Person is not signed in');
|
|
85
108
|
});
|
|
86
109
|
});
|
|
@@ -93,6 +116,9 @@ const firebase_utils_1 = require("./firebase-utils");
|
|
|
93
116
|
personId: personId.guidString
|
|
94
117
|
}));
|
|
95
118
|
(0, firebase_utils_1.configureFirebase)({
|
|
119
|
+
userAuthentications: firebase_utils_1.Collection.docs({
|
|
120
|
+
[userAuthId]: firebase_utils_1.Document.data(userId.value)
|
|
121
|
+
}),
|
|
96
122
|
users: firebase_utils_1.Collection.docs({
|
|
97
123
|
[userId.value]: firebase_utils_1.Document.user(userId, teams)
|
|
98
124
|
}),
|
|
@@ -105,7 +131,7 @@ const firebase_utils_1 = require("./firebase-utils");
|
|
|
105
131
|
})
|
|
106
132
|
});
|
|
107
133
|
await (0, firebase_utils_1.expectThrowsFunctionsError)(async () => {
|
|
108
|
-
await (0, checkAuthentication_1.checkAuthentication)(
|
|
134
|
+
await (0, checkAuthentication_1.checkAuthentication)(userAuthId, teamId, 'team-manager');
|
|
109
135
|
}, 'permission-denied', 'User does not have the required roles');
|
|
110
136
|
});
|
|
111
137
|
(0, mocha_1.it)('should return userId if user has required single role', async () => {
|
|
@@ -116,6 +142,9 @@ const firebase_utils_1 = require("./firebase-utils");
|
|
|
116
142
|
personId: personId.guidString
|
|
117
143
|
}));
|
|
118
144
|
(0, firebase_utils_1.configureFirebase)({
|
|
145
|
+
userAuthentications: firebase_utils_1.Collection.docs({
|
|
146
|
+
[userAuthId]: firebase_utils_1.Document.data(userId.value)
|
|
147
|
+
}),
|
|
119
148
|
users: firebase_utils_1.Collection.docs({
|
|
120
149
|
[userId.value]: firebase_utils_1.Document.user(userId, teams)
|
|
121
150
|
}),
|
|
@@ -127,7 +156,7 @@ const firebase_utils_1 = require("./firebase-utils");
|
|
|
127
156
|
})
|
|
128
157
|
})
|
|
129
158
|
});
|
|
130
|
-
const result = await (0, checkAuthentication_1.checkAuthentication)(
|
|
159
|
+
const result = await (0, checkAuthentication_1.checkAuthentication)(userAuthId, teamId, 'team-manager');
|
|
131
160
|
(0, core_1.expect)(result).toBeEqual(userId);
|
|
132
161
|
});
|
|
133
162
|
(0, mocha_1.it)('should throw "permission-denied" if user does not have all required roles (AND logic)', async () => {
|
|
@@ -138,6 +167,9 @@ const firebase_utils_1 = require("./firebase-utils");
|
|
|
138
167
|
personId: personId.guidString
|
|
139
168
|
}));
|
|
140
169
|
(0, firebase_utils_1.configureFirebase)({
|
|
170
|
+
userAuthentications: firebase_utils_1.Collection.docs({
|
|
171
|
+
[userAuthId]: firebase_utils_1.Document.data(userId.value)
|
|
172
|
+
}),
|
|
141
173
|
users: firebase_utils_1.Collection.docs({
|
|
142
174
|
[userId.value]: firebase_utils_1.Document.user(userId, teams)
|
|
143
175
|
}),
|
|
@@ -150,7 +182,7 @@ const firebase_utils_1 = require("./firebase-utils");
|
|
|
150
182
|
})
|
|
151
183
|
});
|
|
152
184
|
await (0, firebase_utils_1.expectThrowsFunctionsError)(async () => {
|
|
153
|
-
await (0, checkAuthentication_1.checkAuthentication)(
|
|
185
|
+
await (0, checkAuthentication_1.checkAuthentication)(userAuthId, teamId, ['person-manager', 'team-manager']);
|
|
154
186
|
}, 'permission-denied', 'User does not have the required roles');
|
|
155
187
|
});
|
|
156
188
|
(0, mocha_1.it)('should return userId if user has all required roles (AND logic)', async () => {
|
|
@@ -161,6 +193,9 @@ const firebase_utils_1 = require("./firebase-utils");
|
|
|
161
193
|
personId: personId.guidString
|
|
162
194
|
}));
|
|
163
195
|
(0, firebase_utils_1.configureFirebase)({
|
|
196
|
+
userAuthentications: firebase_utils_1.Collection.docs({
|
|
197
|
+
[userAuthId]: firebase_utils_1.Document.data(userId.value)
|
|
198
|
+
}),
|
|
164
199
|
users: firebase_utils_1.Collection.docs({
|
|
165
200
|
[userId.value]: firebase_utils_1.Document.user(userId, teams)
|
|
166
201
|
}),
|
|
@@ -172,7 +207,7 @@ const firebase_utils_1 = require("./firebase-utils");
|
|
|
172
207
|
})
|
|
173
208
|
})
|
|
174
209
|
});
|
|
175
|
-
const result = await (0, checkAuthentication_1.checkAuthentication)(
|
|
210
|
+
const result = await (0, checkAuthentication_1.checkAuthentication)(userAuthId, teamId, ['person-manager', 'team-manager']);
|
|
176
211
|
(0, core_1.expect)(result).toBeEqual(userId);
|
|
177
212
|
});
|
|
178
213
|
(0, mocha_1.it)('should return userId if user has at least one required role (OR logic)', async () => {
|
|
@@ -183,6 +218,9 @@ const firebase_utils_1 = require("./firebase-utils");
|
|
|
183
218
|
personId: personId.guidString
|
|
184
219
|
}));
|
|
185
220
|
(0, firebase_utils_1.configureFirebase)({
|
|
221
|
+
userAuthentications: firebase_utils_1.Collection.docs({
|
|
222
|
+
[userAuthId]: firebase_utils_1.Document.data(userId.value)
|
|
223
|
+
}),
|
|
186
224
|
users: firebase_utils_1.Collection.docs({
|
|
187
225
|
[userId.value]: firebase_utils_1.Document.user(userId, teams)
|
|
188
226
|
}),
|
|
@@ -194,7 +232,7 @@ const firebase_utils_1 = require("./firebase-utils");
|
|
|
194
232
|
})
|
|
195
233
|
})
|
|
196
234
|
});
|
|
197
|
-
const result = await (0, checkAuthentication_1.checkAuthentication)(
|
|
235
|
+
const result = await (0, checkAuthentication_1.checkAuthentication)(userAuthId, teamId, { anyOf: ['person-manager', 'team-manager'] });
|
|
198
236
|
(0, core_1.expect)(result).toBeEqual(userId);
|
|
199
237
|
});
|
|
200
238
|
(0, mocha_1.it)('should throw "permission-denied" if user does not have any required role (OR logic)', async () => {
|
|
@@ -205,6 +243,9 @@ const firebase_utils_1 = require("./firebase-utils");
|
|
|
205
243
|
personId: personId.guidString
|
|
206
244
|
}));
|
|
207
245
|
(0, firebase_utils_1.configureFirebase)({
|
|
246
|
+
userAuthentications: firebase_utils_1.Collection.docs({
|
|
247
|
+
[userAuthId]: firebase_utils_1.Document.data(userId.value)
|
|
248
|
+
}),
|
|
208
249
|
users: firebase_utils_1.Collection.docs({
|
|
209
250
|
[userId.value]: firebase_utils_1.Document.user(userId, teams)
|
|
210
251
|
}),
|
|
@@ -217,7 +258,7 @@ const firebase_utils_1 = require("./firebase-utils");
|
|
|
217
258
|
})
|
|
218
259
|
});
|
|
219
260
|
await (0, firebase_utils_1.expectThrowsFunctionsError)(async () => {
|
|
220
|
-
await (0, checkAuthentication_1.checkAuthentication)(
|
|
261
|
+
await (0, checkAuthentication_1.checkAuthentication)(userAuthId, teamId, { anyOf: ['person-manager', 'team-manager'] });
|
|
221
262
|
}, 'permission-denied', 'User does not have the required roles');
|
|
222
263
|
});
|
|
223
264
|
(0, mocha_1.it)('should handle complex nested role requirements (AND with OR)', async () => {
|
|
@@ -228,6 +269,9 @@ const firebase_utils_1 = require("./firebase-utils");
|
|
|
228
269
|
personId: personId.guidString
|
|
229
270
|
}));
|
|
230
271
|
(0, firebase_utils_1.configureFirebase)({
|
|
272
|
+
userAuthentications: firebase_utils_1.Collection.docs({
|
|
273
|
+
[userAuthId]: firebase_utils_1.Document.data(userId.value)
|
|
274
|
+
}),
|
|
231
275
|
users: firebase_utils_1.Collection.docs({
|
|
232
276
|
[userId.value]: firebase_utils_1.Document.user(userId, teams)
|
|
233
277
|
}),
|
|
@@ -239,7 +283,7 @@ const firebase_utils_1 = require("./firebase-utils");
|
|
|
239
283
|
})
|
|
240
284
|
})
|
|
241
285
|
});
|
|
242
|
-
const result = await (0, checkAuthentication_1.checkAuthentication)(
|
|
286
|
+
const result = await (0, checkAuthentication_1.checkAuthentication)(userAuthId, teamId, [
|
|
243
287
|
'person-manager',
|
|
244
288
|
{ anyOf: ['fine-manager', 'team-manager'] }
|
|
245
289
|
]);
|
|
@@ -253,6 +297,9 @@ const firebase_utils_1 = require("./firebase-utils");
|
|
|
253
297
|
personId: personId.guidString
|
|
254
298
|
}));
|
|
255
299
|
(0, firebase_utils_1.configureFirebase)({
|
|
300
|
+
userAuthentications: firebase_utils_1.Collection.docs({
|
|
301
|
+
[userAuthId]: firebase_utils_1.Document.data(userId.value)
|
|
302
|
+
}),
|
|
256
303
|
users: firebase_utils_1.Collection.docs({
|
|
257
304
|
[userId.value]: firebase_utils_1.Document.user(userId, teams)
|
|
258
305
|
}),
|
|
@@ -265,7 +312,7 @@ const firebase_utils_1 = require("./firebase-utils");
|
|
|
265
312
|
})
|
|
266
313
|
});
|
|
267
314
|
await (0, firebase_utils_1.expectThrowsFunctionsError)(async () => {
|
|
268
|
-
await (0, checkAuthentication_1.checkAuthentication)(
|
|
315
|
+
await (0, checkAuthentication_1.checkAuthentication)(userAuthId, teamId, [
|
|
269
316
|
'person-manager',
|
|
270
317
|
{ anyOf: ['fine-manager', 'team-manager'] }
|
|
271
318
|
]);
|
|
@@ -281,6 +328,9 @@ const firebase_utils_1 = require("./firebase-utils");
|
|
|
281
328
|
personId: personId.guidString
|
|
282
329
|
}));
|
|
283
330
|
(0, firebase_utils_1.configureFirebase)({
|
|
331
|
+
userAuthentications: firebase_utils_1.Collection.docs({
|
|
332
|
+
[userAuthId]: firebase_utils_1.Document.data(userId.value)
|
|
333
|
+
}),
|
|
284
334
|
users: firebase_utils_1.Collection.docs({
|
|
285
335
|
[userId.value]: firebase_utils_1.Document.user(userId, teams)
|
|
286
336
|
}),
|
|
@@ -298,7 +348,7 @@ const firebase_utils_1 = require("./firebase-utils");
|
|
|
298
348
|
})
|
|
299
349
|
})
|
|
300
350
|
});
|
|
301
|
-
const result = await (0, checkAuthentication_1.checkAuthentication)(
|
|
351
|
+
const result = await (0, checkAuthentication_1.checkAuthentication)(userAuthId, teamId, 'fine-can-add');
|
|
302
352
|
(0, core_1.expect)(result).toBeEqual(userId);
|
|
303
353
|
});
|
|
304
354
|
});
|
package/package.json
CHANGED
|
@@ -50,17 +50,21 @@ function hasUserRoles(userRoles: UserRole[], expectedRoles: ExpectedUserRoles):
|
|
|
50
50
|
* 5. Ensures the person is signed in (has signInProperties)
|
|
51
51
|
* 6. Verifies the person has the required roles
|
|
52
52
|
*
|
|
53
|
-
* @param
|
|
53
|
+
* @param userAuthId - The raw user authentication ID string from authentication context (null if not authenticated)
|
|
54
54
|
* @param teamId - The ID of the team to check membership and roles for
|
|
55
55
|
* @param roles - The expected role requirements (supports AND/OR logic via ExpectedUserRoles)
|
|
56
56
|
* @returns The validated User.Id if all checks pass
|
|
57
57
|
* @throws {FunctionsError} 'unauthenticated' - If rawUserId is null
|
|
58
58
|
* @throws {FunctionsError} 'permission-denied' - If any validation check fails
|
|
59
59
|
*/
|
|
60
|
-
export async function checkAuthentication(
|
|
61
|
-
if (
|
|
60
|
+
export async function checkAuthentication(userAuthId: string | null, teamId: Team.Id, roles: ExpectedUserRoles): Promise<User.Id> {
|
|
61
|
+
if (userAuthId === null)
|
|
62
62
|
throw new FunctionsError('unauthenticated', 'User is not authenticated');
|
|
63
|
-
|
|
63
|
+
|
|
64
|
+
const userAuthenticationId = await Firestore.shared.userAuthentication(userAuthId).snapshot();
|
|
65
|
+
if (!userAuthenticationId.exists)
|
|
66
|
+
throw new FunctionsError('permission-denied', 'User authentication does not exist');
|
|
67
|
+
const userId = User.Id.builder.build(userAuthenticationId.data);
|
|
64
68
|
|
|
65
69
|
const userSnapshot = await Firestore.shared.user(userId).snapshot();
|
|
66
70
|
if (!userSnapshot.exists)
|