forked from turt2live/matrix-bot-sdk
-
Notifications
You must be signed in to change notification settings - Fork 1
/
SynapseAdminApis.ts
463 lines (413 loc) · 15 KB
/
SynapseAdminApis.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
import { MatrixClient } from "./MatrixClient";
import { MatrixError } from "./models/MatrixError";
/**
* Information about a user on Synapse.
* @category Admin APIs
*/
export interface SynapseUser {
/***
* The display name of the user, if set.
*/
displayname?: string;
/**
* A set of 3PIDs for the user.
*/
threepids?: {
medium: string;
address: string;
}[];
/**
* The avatar URL (usually MXC URI) for the user, if set.
*/
avatar_url?: string;
/**
* Whether or not the user is a Synapse administrator.
*/
admin?: boolean;
/**
* Whether or not the user is deactivated.
*/
deactivated?: boolean;
}
/**
* Added information to include when updating/creating a user.
* @category Admin APIs
*/
export interface SynapseUserProperties extends SynapseUser {
/**
* The password for the user. Leave undefined to leave unchanged.
*/
password?: string;
}
/**
* Information about a user on Synapse.
* @category Admin APIs
*/
export interface SynapseUserListing {
/**
* User ID.
*/
name: string;
/**
* Whether or not the user is a guest. 1 is true, 0 is false.
*/
is_guest: number;
/**
* Whether or not the user is an admin. 1 is true, 0 is false.
*/
admin: number;
/**
* Whether or not the user is deactivated. 1 is true, 0 is false.
*/
deactivated: number;
/**
* The type of user, if relevant.
*/
user_type: string | null;
/**
* The hash of the user's password, if relevant.
*/
password_hash: string | null;
/**
* The display name of the user, if set.
*/
displayname: string | null;
/**
* The avatar for the user, if set.
*/
avatar_url: string | null;
}
/**
* A resulting list of users on Synapse.
* @category Admin APIs
*/
export interface SynapseUserList {
/**
* A set of users matching the criteria.
*/
users: SynapseUserListing[];
/**
* The token to use to get the next set of users.
*/
next_token: string;
/**
* The total number of users on the Synapse instance.
*/
total: number;
}
/**
* A registration token on Synapse
* @category Admin APIs
*/
export interface SynapseRegistrationToken {
token: string;
uses_allowed: null | number;
pending: number;
completed: number;
expiry_time: null | number;
}
export interface SynapseRegistrationTokenUpdateOptions {
/**
* The integer number of times the token can be used to complete a registration before it becomes invalid.
* If null the token will have an unlimited number of uses.
* Default: unlimited uses.
*/
uses_allowed?: number | null;
/**
* The latest time the token is valid. Given as the number of milliseconds since 1970-01-01 00:00:00 UTC (the start of the Unix epoch).
* If null the token will not expire.
* Default: token does not expire.
*/
expiry_time?: number | null;
}
export interface SynapseRegistrationTokenOptions extends SynapseRegistrationTokenUpdateOptions {
/**
* The registration token. A string of no more than 64 characters that consists only of characters matched by the regex [A-Za-z0-9._~-].
* Default: randomly generated.
*/
token?: string;
/**
* The length of the token randomly generated if token is not specified. Must be between 1 and 64 inclusive.
* Default: 16.
*/
length?: number;
}
/**
* Information about a room on Synapse.
* @category Admin APIs
*/
export interface SynapseRoomListing {
room_id: string;
name: string;
canonical_alias: string;
joined_members: number;
joined_local_members: number;
version: string;
creator: string;
encryption: string; // algorithm
federatable: boolean;
public: boolean;
join_rules: string;
guest_access: string;
history_visibility: string;
state_events: number;
}
/**
* A resulting list of rooms on Synapse.
* @category Admin APIs
*/
export interface SynapseRoomList {
rooms: SynapseRoomListing[];
offset: string;
total_rooms: number;
next_batch: string;
prev_batch: string;
}
/**
* Available properties on a Synapse room listing to order by.
* @category Admin APIs
*/
export enum SynapseRoomProperty {
Name = "name",
CanonicalAlias = "canonical_alias",
JoinedMembers = "joined_members",
JoinedLocalMembers = "joined_local_members",
Version = "version",
Creator = "creator",
Encryption = "encryption",
CanFederate = "federatable",
IsPublic = "public",
JoinRules = "join_rules",
GuestAccess = "guest_access",
HistoryVisibility = "history_visibility",
NumStateEvents = "state_events",
}
export interface SynapseListUserOptions {
/**
* Filters to only return users with user IDs that contain this value. This parameter is ignored when using the name parameter.
*/
user_id?: string;
/**
* Filters to only return users with user ID localparts or displaynames that contain this value.
*/
name?: string;
/**
* If false will exclude guest users. Defaults to true to include guest users.
*/
guests?: boolean;
/**
* If true will include deactivated users. Defaults to false to exclude deactivated users.
*/
deactivated?: boolean;
/**
* The method by which to sort the returned list of users. If the ordered field has duplicates, the
* second order is always by ascending name, which guarantees a stable ordering.
* **Caution**: The database only has indexes on the columns `name` and `creation_ts`. This means
* that if a different sort order is used, it can cause a large load on the database.
*/
order_by?: "name" | "is_guest" | "admin" | "user_type" | "deactivated" | "shadow_banned" | "displayname" | "avatar_url" | "creation_ts";
/**
* The number of results to return at a time.
*/
limit?: number;
}
/**
* Access to various administrative APIs specifically available in Synapse.
* @category Admin APIs
*/
export class SynapseAdminApis {
constructor(private client: MatrixClient) {
}
/**
* Get information about a user. The client making the request must be an admin user.
* @param {string} userId The user ID to check.
* @returns {Promise<SynapseUser>} The resulting Synapse user record
*/
public async getUser(userId: string): Promise<SynapseUser> {
return this.client.doRequest(
"GET", "/_synapse/admin/v2/users/" + encodeURIComponent(userId),
);
}
/**
* Create or update a given user on a Synapse server. The
* client making the request must be an admin user.
* @param {string} userId The user ID to check.
* @param {SynapseUserProperties} opts Options to set when creating or updating the user.
* @returns {Promise<SynapseUser>} The resulting Synapse user record
*/
public async upsertUser(userId: string, opts: SynapseUserProperties = {}): Promise<SynapseUser> {
return this.client.doRequest(
"PUT", "/_synapse/admin/v2/users/" + encodeURIComponent(userId), undefined, opts,
);
}
/**
* Get a list of users registered with Synapse, optionally filtered by some criteria. The
* client making the request must be an admin user.
* @param {string} from The token to continue listing users from.
* @param {number} limit The maximum number of users to request.
* @param {string} name Optional localpart or display name filter for results.
* @param {boolean} guests Whether or not to include guest accounts. Default true.
* @param {boolean} deactivated Whether or not to include deactivated accounts. Default false.
* @returns {Promise<SynapseUserList>} A batch of user results.
*/
public async listUsers(from?: string, limit?: number, name?: string, guests = true, deactivated = false): Promise<SynapseUserList> {
const qs = { guests, deactivated };
if (from) qs['from'] = from;
if (limit) qs['limit'] = limit;
if (name) qs['name'] = name;
return this.client.doRequest("GET", "/_synapse/admin/v2/users", qs);
}
/**
* Get a list of all users registered with Synapse, optionally filtered by some criteria. The
* client making the request must be an admin user.
*
* This method returns an async generator that can be used to filter results.
* @param options Options to pass to the user listing function
* @example
* for await (const user of synapseAdminApis.listAllUsers()) {
* if (user.name === '@alice:example.com') {
* return user;
* }
* }
*/
public async* listAllUsers(options: SynapseListUserOptions = {}): AsyncGenerator<SynapseUserListing> {
let from: string | undefined = undefined;
let response: SynapseUserList;
do {
const qs = {
...options,
...(from && { from }),
};
response = await this.client.doRequest("GET", "/_synapse/admin/v2/users", qs);
for (const user of response.users) {
yield user;
}
from = response.next_token;
} while (from);
}
/**
* Determines if the given user is a Synapse server administrator for this homeserver. The
* client making the request must be an admin user themselves (check with `isSelfAdmin`)
* @param {string} userId The user ID to check.
* @returns {Promise<boolean>} Resolves to true if the user is an admin, false otherwise.
* Throws if there's an error.
*/
public async isAdmin(userId: string): Promise<boolean> {
const response = await this.client.doRequest("GET", `/_synapse/admin/v1/users/${encodeURIComponent(userId)}/admin`);
return response['admin'] || false;
}
/**
* Determines if the current user is an admin for the Synapse homeserver.
* @returns {Promise<boolean>} Resolve to true if the user is an admin, false otherwise.
* Throws if there's an error.
*/
public async isSelfAdmin(): Promise<boolean> {
try {
return await this.isAdmin(await this.client.getUserId());
} catch (err) {
if (err instanceof MatrixError && err.errcode === 'M_FORBIDDEN') {
return false;
}
throw err;
}
}
/**
* Lists the rooms on the server.
* @param {string} searchTerm A term to search for in the room names
* @param {string} from A previous batch token to search from
* @param {number} limit The maximum number of rooms to return
* @param {SynapseRoomProperty} orderBy A property of rooms to order by
* @param {boolean} reverseOrder True to reverse the orderBy direction.
* @returns {Promise<SynapseRoomList>} Resolves to the server's rooms, ordered and filtered.
*/
public async listRooms(searchTerm?: string, from?: string, limit?: number, orderBy?: SynapseRoomProperty, reverseOrder = false): Promise<SynapseRoomList> {
const params = {};
if (from) params['from'] = from;
if (limit) params['limit'] = limit;
if (searchTerm) params['search_term'] = searchTerm;
if (orderBy) params['order_by'] = orderBy;
if (reverseOrder) {
params['dir'] = 'b';
} else {
params['dir'] = 'f';
}
return this.client.doRequest("GET", "/_synapse/admin/v1/rooms", params);
}
/**
* Gets a list of state events in a room.
* @param {string} roomId The room ID to get state for.
* @returns {Promise<any[]>} Resolves to the room's state events.
*/
public async getRoomState(roomId: string): Promise<any[]> {
const r = await this.client.doRequest("GET", `/_synapse/admin/v1/rooms/${encodeURIComponent(roomId)}/state`);
return r?.['state'] || [];
}
/**
* Deletes a room from the server, purging all record of it.
* @param {string} roomId The room to delete.
* @returns {Promise} Resolves when complete.
*/
public async deleteRoom(roomId: string): Promise<void> {
return this.client.doRequest("DELETE", `/_synapse/admin/v2/rooms/${encodeURIComponent(roomId)}`, {}, { purge: true });
}
/**
* Gets the status of all active deletion tasks, and all those completed in the last 24h, for the given room_id.
* @param {string} roomId The room ID to get deletion state for.
* @returns {Promise<any[]>} Resolves to the room's deletion status results.
*/
public async getDeleteRoomState(roomId: string): Promise<any[]> {
const r = await this.client.doRequest("GET", `/_synapse/admin/v2/rooms/${encodeURIComponent(roomId)}/delete_status`);
return r?.['results'] || [];
}
/**
* List all registration tokens on the homeserver.
* @param valid If true, only valid tokens are returned.
* If false, only tokens that have expired or have had all uses exhausted are returned.
* If omitted, all tokens are returned regardless of validity.
* @returns An array of registration tokens.
*/
public async listRegistrationTokens(valid?: boolean): Promise<SynapseRegistrationToken[]> {
const res = await this.client.doRequest("GET", `/_synapse/admin/v1/registration_tokens`, { valid });
return res.registration_tokens;
}
/**
* Get details about a single token.
* @param token The token to fetch.
* @returns A registration tokens, or null if not found.
*/
public async getRegistrationToken(token: string): Promise<SynapseRegistrationToken | null> {
try {
return await this.client.doRequest("GET", `/_synapse/admin/v1/registration_tokens/${encodeURIComponent(token)}`);
} catch (e) {
if (e?.statusCode === 404) {
return null;
}
throw e;
}
}
/**
* Create a new registration token.
* @param options Options to pass to the request.
* @returns The newly created token.
*/
public async createRegistrationToken(options: SynapseRegistrationTokenOptions = {}): Promise<SynapseRegistrationToken> {
return this.client.doRequest("POST", `/_synapse/admin/v1/registration_tokens/new`, undefined, options);
}
/**
* Update an existing registration token.
* @param token The token to update.
* @param options Options to pass to the request.
* @returns The newly created token.
*/
public async updateRegistrationToken(token: string, options: SynapseRegistrationTokenUpdateOptions): Promise<SynapseRegistrationToken> {
return this.client.doRequest("PUT", `/_synapse/admin/v1/registration_tokens/${encodeURIComponent(token)}`, undefined, options);
}
/**
* Delete a registration token
* @param token The token to update.
* @returns A promise that resolves upon success.
*/
public async deleteRegistrationToken(token: string): Promise<void> {
return this.client.doRequest("DELETE", `/_synapse/admin/v1/registration_tokens/${encodeURIComponent(token)}`, undefined, {});
}
}