@sasjs/api 0.6.0 → 0.7.0
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.
- package/README.md +3 -2
- package/build/browser.js +2231 -118
- package/build/cjs/corpus/records.js +1222 -0
- package/build/cjs/corpus/runner.js +15 -6
- package/build/cjs/drive/deploy.js +49 -10
- package/build/cjs/host/dispatch.js +190 -2
- package/build/cjs/identity/memory-store.js +196 -11
- package/build/cjs/identity/records.js +398 -0
- package/build/cjs/index.js +8 -1
- package/build/cjs/routes/generated.js +184 -4
- package/build/cjs/routes/overlay.js +53 -58
- package/build/esm/corpus/records.d.ts +25 -0
- package/build/esm/corpus/records.d.ts.map +1 -0
- package/build/esm/corpus/records.js +1219 -0
- package/build/esm/corpus/runner.d.ts.map +1 -1
- package/build/esm/corpus/runner.js +15 -6
- package/build/esm/drive/deploy.d.ts +10 -0
- package/build/esm/drive/deploy.d.ts.map +1 -1
- package/build/esm/drive/deploy.js +48 -9
- package/build/esm/host/dispatch.d.ts +9 -0
- package/build/esm/host/dispatch.d.ts.map +1 -1
- package/build/esm/host/dispatch.js +190 -2
- package/build/esm/identity/fixture.d.ts +6 -0
- package/build/esm/identity/fixture.d.ts.map +1 -1
- package/build/esm/identity/memory-store.d.ts +29 -5
- package/build/esm/identity/memory-store.d.ts.map +1 -1
- package/build/esm/identity/memory-store.js +196 -11
- package/build/esm/identity/records.d.ts +102 -0
- package/build/esm/identity/records.d.ts.map +1 -0
- package/build/esm/identity/records.js +393 -0
- package/build/esm/identity/types.d.ts +102 -2
- package/build/esm/identity/types.d.ts.map +1 -1
- package/build/esm/index.d.ts +4 -1
- package/build/esm/index.d.ts.map +1 -1
- package/build/esm/index.js +2 -0
- package/build/esm/routes/generated.d.ts.map +1 -1
- package/build/esm/routes/generated.js +184 -4
- package/build/esm/routes/overlay.d.ts.map +1 -1
- package/build/esm/routes/overlay.js +53 -58
- package/package.json +1 -1
|
@@ -39,9 +39,12 @@ const live = (issued, now) => issued && (issued.expiresAt === undefined || issue
|
|
|
39
39
|
*/
|
|
40
40
|
export class MemoryIdentityStore {
|
|
41
41
|
constructor(fixture = DEFAULT_IDENTITY) {
|
|
42
|
-
this.
|
|
42
|
+
this.userList = [];
|
|
43
43
|
this.passwords = new Map();
|
|
44
|
-
this.
|
|
44
|
+
this.groupList = new Map();
|
|
45
|
+
this.permissionList = new Map();
|
|
46
|
+
this.clientRecords = new Map();
|
|
47
|
+
this.clientMap = new Map();
|
|
45
48
|
this.pairs = new Map();
|
|
46
49
|
this.access = new Map();
|
|
47
50
|
this.refresh = new Map();
|
|
@@ -50,24 +53,60 @@ export class MemoryIdentityStore {
|
|
|
50
53
|
if (fixture.format !== IDENTITY_FORMAT)
|
|
51
54
|
throw new ApiError(500, `The identity fixture states format ${String(fixture.format)}; this store reads ${IDENTITY_FORMAT}.`);
|
|
52
55
|
for (const user of fixture.users) {
|
|
53
|
-
this.
|
|
56
|
+
this.userList.push({
|
|
54
57
|
uid: user.uid,
|
|
55
58
|
username: user.username,
|
|
56
59
|
displayName: user.displayName,
|
|
57
60
|
isAdmin: user.isAdmin,
|
|
58
61
|
isActive: user.isActive,
|
|
59
|
-
needsToUpdatePassword: user.needsToUpdatePassword
|
|
62
|
+
needsToUpdatePassword: user.needsToUpdatePassword,
|
|
63
|
+
authProvider: user.authProvider,
|
|
64
|
+
autoExec: user.autoExec
|
|
60
65
|
});
|
|
61
66
|
this.passwords.set(user.uid, user.password);
|
|
62
67
|
}
|
|
63
|
-
for (const client of fixture.clients)
|
|
64
|
-
this.
|
|
68
|
+
for (const client of fixture.clients) {
|
|
69
|
+
this.clientMap.set(client.clientId, {
|
|
65
70
|
clientId: client.clientId,
|
|
66
71
|
accessTokenExpiration: client.accessTokenExpiration,
|
|
67
72
|
refreshTokenExpiration: client.refreshTokenExpiration
|
|
68
73
|
});
|
|
74
|
+
this.clientRecords.set(client.clientId, {
|
|
75
|
+
clientId: client.clientId,
|
|
76
|
+
clientSecret: client.clientSecret,
|
|
77
|
+
accessTokenExpiration: client.accessTokenExpiration,
|
|
78
|
+
refreshTokenExpiration: client.refreshTokenExpiration
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
for (const group of fixture.groups) {
|
|
82
|
+
const uid = group.uid;
|
|
83
|
+
this.groupList.set(uid, {
|
|
84
|
+
uid,
|
|
85
|
+
name: group.name,
|
|
86
|
+
description: group.description,
|
|
87
|
+
isActive: group.isActive,
|
|
88
|
+
authProvider: group.authProvider,
|
|
89
|
+
users: group.users
|
|
90
|
+
.map((username) => this.userList.find((user) => user.username === username)?.uid)
|
|
91
|
+
.filter((member) => member !== undefined)
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
for (const permission of fixture.permissions) {
|
|
95
|
+
this.permissionList.set(permission.uid, {
|
|
96
|
+
uid: permission.uid,
|
|
97
|
+
path: permission.path,
|
|
98
|
+
type: permission.type,
|
|
99
|
+
setting: permission.setting,
|
|
100
|
+
user: permission.user
|
|
101
|
+
? this.userList.find((user) => user.uid === permission.user)?.uid
|
|
102
|
+
: undefined,
|
|
103
|
+
group: permission.group
|
|
104
|
+
? this.groupList.get(permission.group)?.uid
|
|
105
|
+
: undefined
|
|
106
|
+
});
|
|
107
|
+
}
|
|
69
108
|
for (const token of fixture.tokens || []) {
|
|
70
|
-
const user = this.
|
|
109
|
+
const user = this.userList.find((candidate) => candidate.username === token.username);
|
|
71
110
|
if (!user)
|
|
72
111
|
continue;
|
|
73
112
|
const subject = { userId: user.uid, clientId: token.clientId };
|
|
@@ -84,7 +123,7 @@ export class MemoryIdentityStore {
|
|
|
84
123
|
});
|
|
85
124
|
}
|
|
86
125
|
for (const code of fixture.codes || []) {
|
|
87
|
-
const user = this.
|
|
126
|
+
const user = this.userList.find((candidate) => candidate.username === code.username);
|
|
88
127
|
if (!user)
|
|
89
128
|
continue;
|
|
90
129
|
this.codes.set(code.code, {
|
|
@@ -93,17 +132,19 @@ export class MemoryIdentityStore {
|
|
|
93
132
|
}
|
|
94
133
|
}
|
|
95
134
|
async userByName(username) {
|
|
96
|
-
|
|
135
|
+
const user = this.userList.find((candidate) => candidate.username === username);
|
|
136
|
+
return user ? this.recordOf(user) : undefined;
|
|
97
137
|
}
|
|
98
138
|
async userById(uid) {
|
|
99
|
-
|
|
139
|
+
const user = this.userList.find((candidate) => candidate.uid === uid);
|
|
140
|
+
return user ? this.recordOf(user) : undefined;
|
|
100
141
|
}
|
|
101
142
|
/** A fixture holds the password in clear, so the check is an equality. */
|
|
102
143
|
async passwordMatches(user, password) {
|
|
103
144
|
return this.passwords.get(user.uid) === password;
|
|
104
145
|
}
|
|
105
146
|
async client(clientId) {
|
|
106
|
-
return this.
|
|
147
|
+
return this.clientMap.get(clientId);
|
|
107
148
|
}
|
|
108
149
|
async issue(subject, client) {
|
|
109
150
|
// The lifetimes are the client's, recorded against the instant of issue: a
|
|
@@ -188,4 +229,148 @@ export class MemoryIdentityStore {
|
|
|
188
229
|
this.claimed.add(code);
|
|
189
230
|
return true;
|
|
190
231
|
}
|
|
232
|
+
// ---------------------------------------------------------------- records
|
|
233
|
+
async users() {
|
|
234
|
+
return this.userList.map((user) => this.recordOf(user));
|
|
235
|
+
}
|
|
236
|
+
/** A user as the administration routes report one: groups derived, not stored. */
|
|
237
|
+
recordOf(user) {
|
|
238
|
+
return {
|
|
239
|
+
...user,
|
|
240
|
+
groups: [...this.groupList.values()]
|
|
241
|
+
.filter((group) => group.users.includes(user.uid))
|
|
242
|
+
.map((group) => group.uid)
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
async createUser(input) {
|
|
246
|
+
const user = {
|
|
247
|
+
uid: `user-${randomHex(6)}`,
|
|
248
|
+
username: input.username,
|
|
249
|
+
displayName: input.displayName,
|
|
250
|
+
isAdmin: input.isAdmin,
|
|
251
|
+
isActive: input.isActive,
|
|
252
|
+
needsToUpdatePassword: false,
|
|
253
|
+
autoExec: input.autoExec,
|
|
254
|
+
authProvider: input.authProvider
|
|
255
|
+
};
|
|
256
|
+
this.userList.push(user);
|
|
257
|
+
return this.recordOf(user);
|
|
258
|
+
}
|
|
259
|
+
async updateUser(uid, change) {
|
|
260
|
+
const user = this.userList.find((candidate) => candidate.uid === uid);
|
|
261
|
+
if (!user)
|
|
262
|
+
return undefined;
|
|
263
|
+
if (change.username !== undefined)
|
|
264
|
+
user.username = change.username;
|
|
265
|
+
if (change.displayName !== undefined)
|
|
266
|
+
user.displayName = change.displayName;
|
|
267
|
+
if (change.isAdmin !== undefined)
|
|
268
|
+
user.isAdmin = change.isAdmin;
|
|
269
|
+
if (change.isActive !== undefined)
|
|
270
|
+
user.isActive = change.isActive;
|
|
271
|
+
if (change.needsToUpdatePassword !== undefined)
|
|
272
|
+
user.needsToUpdatePassword = change.needsToUpdatePassword;
|
|
273
|
+
if (change.autoExec !== undefined)
|
|
274
|
+
user.autoExec = change.autoExec;
|
|
275
|
+
return this.recordOf(user);
|
|
276
|
+
}
|
|
277
|
+
async deleteUser(uid) {
|
|
278
|
+
const index = this.userList.findIndex((user) => user.uid === uid);
|
|
279
|
+
if (index === -1)
|
|
280
|
+
return;
|
|
281
|
+
this.userList.splice(index, 1);
|
|
282
|
+
this.passwords.delete(uid);
|
|
283
|
+
for (const group of this.groupList.values())
|
|
284
|
+
group.users = group.users.filter((member) => member !== uid);
|
|
285
|
+
for (const [key, permission] of this.permissionList)
|
|
286
|
+
if (permission.user === uid)
|
|
287
|
+
this.permissionList.delete(key);
|
|
288
|
+
for (const key of this.pairs.keys())
|
|
289
|
+
if (key.startsWith(`${uid}|`))
|
|
290
|
+
this.pairs.delete(key);
|
|
291
|
+
}
|
|
292
|
+
async setPassword(uid, password) {
|
|
293
|
+
this.passwords.set(uid, password);
|
|
294
|
+
}
|
|
295
|
+
async groups() {
|
|
296
|
+
return [...this.groupList.values()];
|
|
297
|
+
}
|
|
298
|
+
async groupById(uid) {
|
|
299
|
+
return this.groupList.get(uid);
|
|
300
|
+
}
|
|
301
|
+
async groupByName(name) {
|
|
302
|
+
return [...this.groupList.values()].find((group) => group.name === name);
|
|
303
|
+
}
|
|
304
|
+
async createGroup(input) {
|
|
305
|
+
const group = {
|
|
306
|
+
uid: `group-${randomHex(6)}`,
|
|
307
|
+
name: input.name,
|
|
308
|
+
description: input.description,
|
|
309
|
+
isActive: input.isActive,
|
|
310
|
+
users: []
|
|
311
|
+
};
|
|
312
|
+
this.groupList.set(group.uid, group);
|
|
313
|
+
return group;
|
|
314
|
+
}
|
|
315
|
+
async deleteGroup(uid) {
|
|
316
|
+
this.groupList.delete(uid);
|
|
317
|
+
for (const [key, permission] of this.permissionList)
|
|
318
|
+
if (permission.group === uid)
|
|
319
|
+
this.permissionList.delete(key);
|
|
320
|
+
}
|
|
321
|
+
async addToGroup(groupUid, userUid) {
|
|
322
|
+
const group = this.groupList.get(groupUid);
|
|
323
|
+
if (!group)
|
|
324
|
+
return undefined;
|
|
325
|
+
if (!group.users.includes(userUid))
|
|
326
|
+
group.users.push(userUid);
|
|
327
|
+
return group;
|
|
328
|
+
}
|
|
329
|
+
async removeFromGroup(groupUid, userUid) {
|
|
330
|
+
const group = this.groupList.get(groupUid);
|
|
331
|
+
if (!group)
|
|
332
|
+
return undefined;
|
|
333
|
+
group.users = group.users.filter((member) => member !== userUid);
|
|
334
|
+
return group;
|
|
335
|
+
}
|
|
336
|
+
async permissions() {
|
|
337
|
+
return [...this.permissionList.values()];
|
|
338
|
+
}
|
|
339
|
+
async permissionById(uid) {
|
|
340
|
+
return this.permissionList.get(uid);
|
|
341
|
+
}
|
|
342
|
+
async createPermission(input) {
|
|
343
|
+
const permission = {
|
|
344
|
+
uid: `rule-${randomHex(6)}`,
|
|
345
|
+
path: input.path,
|
|
346
|
+
type: input.type,
|
|
347
|
+
setting: input.setting,
|
|
348
|
+
user: input.user,
|
|
349
|
+
group: input.group
|
|
350
|
+
};
|
|
351
|
+
this.permissionList.set(permission.uid, permission);
|
|
352
|
+
return permission;
|
|
353
|
+
}
|
|
354
|
+
async setPermissionSetting(uid, setting) {
|
|
355
|
+
const permission = this.permissionList.get(uid);
|
|
356
|
+
if (!permission)
|
|
357
|
+
return undefined;
|
|
358
|
+
permission.setting = setting;
|
|
359
|
+
return permission;
|
|
360
|
+
}
|
|
361
|
+
async deletePermission(uid) {
|
|
362
|
+
this.permissionList.delete(uid);
|
|
363
|
+
}
|
|
364
|
+
async clients() {
|
|
365
|
+
return [...this.clientRecords.values()];
|
|
366
|
+
}
|
|
367
|
+
async createClient(input) {
|
|
368
|
+
this.clientRecords.set(input.clientId, input);
|
|
369
|
+
this.clientMap.set(input.clientId, {
|
|
370
|
+
clientId: input.clientId,
|
|
371
|
+
accessTokenExpiration: input.accessTokenExpiration,
|
|
372
|
+
refreshTokenExpiration: input.refreshTokenExpiration
|
|
373
|
+
});
|
|
374
|
+
return input;
|
|
375
|
+
}
|
|
191
376
|
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import type { IdentityClientRecord, IdentityStore, Subject } from './types.js';
|
|
2
|
+
/** The body a client reads for a user, as the server's controllers return it. */
|
|
3
|
+
export interface UserResponse {
|
|
4
|
+
uid: string;
|
|
5
|
+
username: string;
|
|
6
|
+
displayName: string;
|
|
7
|
+
isAdmin: boolean;
|
|
8
|
+
}
|
|
9
|
+
export interface UserDetailsResponse extends UserResponse {
|
|
10
|
+
isActive: boolean;
|
|
11
|
+
needsToUpdatePassword: boolean;
|
|
12
|
+
autoExec?: string;
|
|
13
|
+
groups?: {
|
|
14
|
+
uid: string;
|
|
15
|
+
name: string;
|
|
16
|
+
description: string;
|
|
17
|
+
}[];
|
|
18
|
+
}
|
|
19
|
+
export interface GroupResponse {
|
|
20
|
+
uid: string;
|
|
21
|
+
name: string;
|
|
22
|
+
description: string;
|
|
23
|
+
}
|
|
24
|
+
export interface GroupDetailsResponse extends GroupResponse {
|
|
25
|
+
isActive: boolean;
|
|
26
|
+
users: UserResponse[];
|
|
27
|
+
}
|
|
28
|
+
export interface PermissionResponse {
|
|
29
|
+
uid: string;
|
|
30
|
+
path: string;
|
|
31
|
+
type: string;
|
|
32
|
+
setting: string;
|
|
33
|
+
user?: UserResponse;
|
|
34
|
+
group?: GroupDetailsResponse;
|
|
35
|
+
}
|
|
36
|
+
export interface RecordService {
|
|
37
|
+
listUsers(caller: Subject | undefined): Promise<UserResponse[]>;
|
|
38
|
+
getUser(caller: Subject | undefined, by: {
|
|
39
|
+
uid?: string;
|
|
40
|
+
username?: string;
|
|
41
|
+
}): Promise<UserDetailsResponse>;
|
|
42
|
+
createUser(caller: Subject | undefined, body: {
|
|
43
|
+
username: string;
|
|
44
|
+
displayName: string;
|
|
45
|
+
password: string;
|
|
46
|
+
isAdmin?: boolean;
|
|
47
|
+
isActive?: boolean;
|
|
48
|
+
autoExec?: string;
|
|
49
|
+
}): Promise<UserDetailsResponse>;
|
|
50
|
+
updateUser(caller: Subject | undefined, by: {
|
|
51
|
+
uid?: string;
|
|
52
|
+
username?: string;
|
|
53
|
+
}, body: {
|
|
54
|
+
username?: string;
|
|
55
|
+
displayName?: string;
|
|
56
|
+
password?: string;
|
|
57
|
+
isAdmin?: boolean;
|
|
58
|
+
isActive?: boolean;
|
|
59
|
+
autoExec?: string;
|
|
60
|
+
}): Promise<UserDetailsResponse>;
|
|
61
|
+
deleteUser(caller: Subject | undefined, by: {
|
|
62
|
+
uid?: string;
|
|
63
|
+
username?: string;
|
|
64
|
+
}, body: {
|
|
65
|
+
password?: string;
|
|
66
|
+
}): Promise<void>;
|
|
67
|
+
listGroups(caller: Subject | undefined): Promise<GroupResponse[]>;
|
|
68
|
+
getGroup(caller: Subject | undefined, by: {
|
|
69
|
+
uid?: string;
|
|
70
|
+
name?: string;
|
|
71
|
+
}): Promise<GroupDetailsResponse>;
|
|
72
|
+
createGroup(caller: Subject | undefined, body: {
|
|
73
|
+
name: string;
|
|
74
|
+
description: string;
|
|
75
|
+
isActive?: boolean;
|
|
76
|
+
}): Promise<GroupDetailsResponse>;
|
|
77
|
+
deleteGroup(caller: Subject | undefined, uid: string): Promise<void>;
|
|
78
|
+
addUserToGroup(caller: Subject | undefined, groupUid: string, userUid: string): Promise<GroupDetailsResponse>;
|
|
79
|
+
removeUserFromGroup(caller: Subject | undefined, groupUid: string, userUid: string): Promise<GroupDetailsResponse>;
|
|
80
|
+
listPermissions(caller: Subject | undefined): Promise<PermissionResponse[]>;
|
|
81
|
+
createPermission(caller: Subject | undefined, body: {
|
|
82
|
+
path: string;
|
|
83
|
+
type: string;
|
|
84
|
+
setting: string;
|
|
85
|
+
principalType: string;
|
|
86
|
+
principalId: string;
|
|
87
|
+
}): Promise<PermissionResponse>;
|
|
88
|
+
updatePermission(caller: Subject | undefined, uid: string, body: {
|
|
89
|
+
setting: string;
|
|
90
|
+
}): Promise<PermissionResponse>;
|
|
91
|
+
deletePermission(caller: Subject | undefined, uid: string): Promise<void>;
|
|
92
|
+
listClients(caller: Subject | undefined): Promise<IdentityClientRecord[]>;
|
|
93
|
+
createClient(caller: Subject | undefined, body: IdentityClientRecord): Promise<IdentityClientRecord>;
|
|
94
|
+
/** `PATCH /SASjsApi/auth/updatePassword`, the caller's own password. */
|
|
95
|
+
updatePassword(caller: Subject | undefined, body: {
|
|
96
|
+
currentPassword: string;
|
|
97
|
+
newPassword: string;
|
|
98
|
+
}): Promise<void>;
|
|
99
|
+
}
|
|
100
|
+
export declare const sanitiseDisplayName: (value: unknown) => string;
|
|
101
|
+
export declare const createRecordService: (store: IdentityStore) => RecordService;
|
|
102
|
+
//# sourceMappingURL=records.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"records.d.ts","sourceRoot":"","sources":["../../../src/identity/records.ts"],"names":[],"mappings":"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"}
|