matrix-nodejs-homeserver 0.2.0 → 0.3.2
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 +89 -11
- package/dist/adapters/cluster.d.ts +1 -26
- package/dist/adapters/cluster.js +50 -103
- package/dist/api/account.js +407 -354
- package/dist/api/admin.js +82 -61
- package/dist/api/appservice.js +37 -25
- package/dist/api/backup.js +73 -62
- package/dist/api/federation.js +172 -138
- package/dist/api/filters.js +4 -3
- package/dist/api/legacy.js +91 -78
- package/dist/api/media.js +71 -55
- package/dist/api/misc.js +46 -37
- package/dist/api/preview.js +37 -73
- package/dist/api/profile.js +108 -97
- package/dist/api/push.js +114 -99
- package/dist/api/relationships.js +64 -58
- package/dist/api/rooms.js +703 -580
- package/dist/api/rtc.d.ts +0 -1
- package/dist/api/rtc.js +48 -34
- package/dist/api/search.js +133 -127
- package/dist/api/slidingsync.js +41 -31
- package/dist/api/spaces.js +82 -77
- package/dist/api/sync.js +325 -135
- package/dist/api/threadsubs.js +72 -61
- package/dist/api/threepid.js +99 -66
- package/dist/api/uia.js +17 -16
- package/dist/api/user.js +221 -178
- package/dist/core/admin.d.ts +0 -1
- package/dist/core/admin.js +6 -5
- package/dist/core/adminroom.js +9 -8
- package/dist/core/appservices.d.ts +2 -1
- package/dist/core/appservices.js +5 -4
- package/dist/core/audit.d.ts +0 -1
- package/dist/core/authrules.js +26 -25
- package/dist/core/cluster.d.ts +12 -5
- package/dist/core/cluster.js +46 -29
- package/dist/core/delayed.js +2 -1
- package/dist/core/events.js +11 -10
- package/dist/core/html.js +13 -0
- package/dist/core/identity.js +1 -1
- package/dist/core/invitefilter.js +2 -1
- package/dist/core/json.js +10 -1
- package/dist/core/keys.d.ts +10 -1
- package/dist/core/keys.js +62 -42
- package/dist/core/m.d.ts +209 -0
- package/dist/core/m.js +182 -0
- package/dist/core/outbound.d.ts +16 -0
- package/dist/core/outbound.js +172 -0
- package/dist/core/partialstate.js +2 -1
- package/dist/core/policy.js +4 -3
- package/dist/core/push.d.ts +0 -1
- package/dist/core/push.js +41 -28
- package/dist/core/pushrules.js +36 -35
- package/dist/core/ratelimit.d.ts +1 -1
- package/dist/core/rooms.d.ts +10 -1
- package/dist/core/rooms.js +101 -74
- package/dist/core/semaphore.js +23 -0
- package/dist/core/sso.d.ts +15 -1
- package/dist/core/sso.js +38 -2
- package/dist/core/stateres.js +7 -6
- package/dist/core/threepid.js +1 -9
- package/dist/federation/client.js +9 -1
- package/dist/federation/index.d.ts +2 -2
- package/dist/federation/index.js +43 -35
- package/dist/homeserver.d.ts +23 -4
- package/dist/homeserver.js +12 -3
- package/dist/http/handler.js +2 -23
- package/dist/http/input.js +2 -2
- package/dist/http/procedure.js +25 -0
- package/dist/http/router.d.ts +9 -26
- package/dist/http/router.js +10 -30
- package/dist/index.d.ts +4 -3
- package/dist/index.js +3 -2
- package/dist/storage/batch.js +11 -0
- package/dist/storage/memory.js +1 -0
- package/dist/storage/schema.js +1 -1
- package/dist/storage/sql.js +20 -1
- package/dist/storage/types.d.ts +16 -0
- package/dist/vendor/zod/LICENSE +21 -0
- package/dist/vendor/zod/v4/classic/errors.js +54 -0
- package/dist/vendor/zod/v4/classic/parse.js +17 -0
- package/dist/vendor/zod/v4/classic/schemas.js +865 -0
- package/dist/vendor/zod/v4/core/api.js +512 -0
- package/dist/vendor/zod/v4/core/checks.js +300 -0
- package/dist/vendor/zod/v4/core/core.js +109 -0
- package/dist/vendor/zod/v4/core/doc.js +35 -0
- package/dist/vendor/zod/v4/core/errors.js +118 -0
- package/dist/vendor/zod/v4/core/json-schema-processors.js +428 -0
- package/dist/vendor/zod/v4/core/memoizer.js +255 -0
- package/dist/vendor/zod/v4/core/parse.js +206 -0
- package/dist/vendor/zod/v4/core/regexes.js +73 -0
- package/dist/vendor/zod/v4/core/registries.js +48 -0
- package/dist/vendor/zod/v4/core/schemas.js +1378 -0
- package/dist/vendor/zod/v4/core/to-json-schema.js +448 -0
- package/dist/vendor/zod/v4/core/util.js +537 -0
- package/dist/vendor/zod/v4/core/versions.js +8 -0
- package/dist/vendor/zod/v4/locales/en.js +110 -0
- package/package.json +8 -6
- package/dist/core/pushrules.d.ts +0 -1
package/dist/api/admin.js
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import { errors } from "../core/errors.js";
|
|
2
|
+
import { boolean, looseObject, number, string } from "../vendor/zod/v4/classic/schemas.js";
|
|
2
3
|
import { body, fail, lenient } from "../http/input.js";
|
|
3
|
-
import {
|
|
4
|
+
import { procedure } from "../http/procedure.js";
|
|
4
5
|
//#region src/api/admin.ts
|
|
5
6
|
const required = fail("M_BAD_JSON", "user_id and content are required");
|
|
6
7
|
const noticeBody = body({
|
|
7
|
-
user_id:
|
|
8
|
-
content:
|
|
9
|
-
type: lenient(
|
|
8
|
+
user_id: string(required),
|
|
9
|
+
content: looseObject({}, required),
|
|
10
|
+
type: lenient(string())
|
|
10
11
|
});
|
|
11
|
-
const optionalInt = (name) =>
|
|
12
|
+
const optionalInt = (name) => number(fail("M_INVALID_PARAM", `${name} must be an integer`)).int(`M_INVALID_PARAM: ${name} must be an integer`);
|
|
12
13
|
const registrationTokenBody = body({
|
|
13
|
-
token:
|
|
14
|
+
token: string(fail("M_INVALID_PARAM", "Invalid token")).optional(),
|
|
14
15
|
uses_allowed: optionalInt("uses_allowed").nullable().optional(),
|
|
15
16
|
expiry_time: optionalInt("expiry_time").nullable().optional(),
|
|
16
17
|
length: optionalInt("length").optional()
|
|
@@ -29,10 +30,13 @@ async function requireAdmin(ctx) {
|
|
|
29
30
|
});
|
|
30
31
|
return s;
|
|
31
32
|
}
|
|
33
|
+
const adminGuard = async (ctx) => {
|
|
34
|
+
await requireAdmin(ctx);
|
|
35
|
+
return {};
|
|
36
|
+
};
|
|
32
37
|
/** Admin HTTP API using Synapse-compatible paths, so existing tooling keeps working. */
|
|
33
38
|
function registerAdminRoutes(r) {
|
|
34
39
|
const notice = async (ctx) => {
|
|
35
|
-
await requireAdmin(ctx);
|
|
36
40
|
const body = ctx.input;
|
|
37
41
|
return { event_id: await ctx.hs.admin.sendServerNotice(body.user_id, body.content, {
|
|
38
42
|
type: body.type,
|
|
@@ -65,13 +69,21 @@ function registerAdminRoutes(r) {
|
|
|
65
69
|
};
|
|
66
70
|
};
|
|
67
71
|
const lock = moderation("locked"), suspend = moderation("suspended");
|
|
68
|
-
r.get("/_matrix/client/v1/admin/lock/:userId", lock.get);
|
|
69
|
-
r.put("/_matrix/client/v1/admin/lock/:userId", lock.put);
|
|
70
|
-
r.get("/_matrix/client/v1/admin/suspend/:userId", suspend.get);
|
|
71
|
-
r.put("/_matrix/client/v1/admin/suspend/:userId", suspend.put);
|
|
72
|
-
r.post("/_synapse/admin/v1/send_server_notice", {
|
|
73
|
-
|
|
74
|
-
|
|
72
|
+
r.get("/_matrix/client/v1/admin/lock/:userId", procedure({ handler: lock.get }));
|
|
73
|
+
r.put("/_matrix/client/v1/admin/lock/:userId", procedure({ handler: lock.put }));
|
|
74
|
+
r.get("/_matrix/client/v1/admin/suspend/:userId", procedure({ handler: suspend.get }));
|
|
75
|
+
r.put("/_matrix/client/v1/admin/suspend/:userId", procedure({ handler: suspend.put }));
|
|
76
|
+
r.post("/_synapse/admin/v1/send_server_notice", procedure({
|
|
77
|
+
guard: adminGuard,
|
|
78
|
+
input: noticeBody,
|
|
79
|
+
handler: notice
|
|
80
|
+
}));
|
|
81
|
+
r.put("/_synapse/admin/v1/send_server_notice/:txnId", procedure({
|
|
82
|
+
guard: adminGuard,
|
|
83
|
+
input: noticeBody,
|
|
84
|
+
handler: notice
|
|
85
|
+
}));
|
|
86
|
+
r.get("/_synapse/admin/v2/users", procedure({ handler: async (ctx) => {
|
|
75
87
|
await requireAdmin(ctx);
|
|
76
88
|
const from = Number(ctx.query.get("from") ?? 0) || 0;
|
|
77
89
|
const res = await ctx.hs.admin.listUsers({
|
|
@@ -85,14 +97,14 @@ function registerAdminRoutes(r) {
|
|
|
85
97
|
total: res.total,
|
|
86
98
|
...res.next !== null ? { next_token: String(res.next) } : {}
|
|
87
99
|
};
|
|
88
|
-
});
|
|
89
|
-
r.get("/_synapse/admin/v2/users/:userId", async (ctx) => {
|
|
100
|
+
} }));
|
|
101
|
+
r.get("/_synapse/admin/v2/users/:userId", procedure({ handler: async (ctx) => {
|
|
90
102
|
await requireAdmin(ctx);
|
|
91
103
|
const user = await ctx.hs.admin.getUser(ctx.params.userId);
|
|
92
104
|
if (!user) throw errors.notFound("Unknown user");
|
|
93
105
|
return user;
|
|
94
|
-
});
|
|
95
|
-
r.put("/_synapse/admin/v2/users/:userId", async (ctx) => {
|
|
106
|
+
} }));
|
|
107
|
+
r.put("/_synapse/admin/v2/users/:userId", procedure({ handler: async (ctx) => {
|
|
96
108
|
await requireAdmin(ctx);
|
|
97
109
|
const body = await ctx.json();
|
|
98
110
|
const userId = ctx.params.userId;
|
|
@@ -119,43 +131,52 @@ function registerAdminRoutes(r) {
|
|
|
119
131
|
}
|
|
120
132
|
if (body.deactivated === true) await ctx.hs.admin.deactivateUser(userId);
|
|
121
133
|
return ctx.hs.admin.getUser(userId);
|
|
122
|
-
});
|
|
123
|
-
r.post("/_synapse/admin/v1/deactivate/:userId",
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
134
|
+
} }));
|
|
135
|
+
r.post("/_synapse/admin/v1/deactivate/:userId", procedure({
|
|
136
|
+
guard: adminGuard,
|
|
137
|
+
input: body({ erase: lenient(boolean()) }),
|
|
138
|
+
handler: async (ctx) => {
|
|
139
|
+
const body = ctx.input;
|
|
140
|
+
await ctx.hs.admin.deactivateUser(ctx.params.userId, { erase: body.erase === true });
|
|
141
|
+
return { id_server_unbind_result: "no-support" };
|
|
142
|
+
}
|
|
143
|
+
}));
|
|
129
144
|
const resetPasswordBody = body({
|
|
130
|
-
new_password:
|
|
131
|
-
logout_devices: lenient(
|
|
145
|
+
new_password: string(fail("M_MISSING_PARAM", "Missing new_password")),
|
|
146
|
+
logout_devices: lenient(boolean())
|
|
132
147
|
});
|
|
133
|
-
r.post("/_synapse/admin/v1/reset_password/:userId",
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
148
|
+
r.post("/_synapse/admin/v1/reset_password/:userId", procedure({
|
|
149
|
+
guard: adminGuard,
|
|
150
|
+
input: resetPasswordBody,
|
|
151
|
+
handler: async (ctx) => {
|
|
152
|
+
const body = ctx.input;
|
|
153
|
+
await ctx.hs.admin.resetPassword(ctx.params.userId, body.new_password, body.logout_devices !== false);
|
|
154
|
+
return {};
|
|
155
|
+
}
|
|
156
|
+
}));
|
|
157
|
+
r.get("/_synapse/admin/v1/registration_tokens", procedure({ handler: async (ctx) => {
|
|
140
158
|
await requireAdmin(ctx);
|
|
141
159
|
return { registration_tokens: await ctx.hs.admin.listRegistrationTokens() };
|
|
142
|
-
});
|
|
143
|
-
r.post("/_synapse/admin/v1/registration_tokens/new",
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
160
|
+
} }));
|
|
161
|
+
r.post("/_synapse/admin/v1/registration_tokens/new", procedure({
|
|
162
|
+
guard: adminGuard,
|
|
163
|
+
input: registrationTokenBody,
|
|
164
|
+
handler: async (ctx) => {
|
|
165
|
+
const body = ctx.input;
|
|
166
|
+
return ctx.hs.admin.createRegistrationToken({
|
|
167
|
+
token: body.token,
|
|
168
|
+
usesAllowed: body.uses_allowed,
|
|
169
|
+
expiryTime: body.expiry_time,
|
|
170
|
+
length: body.length
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
}));
|
|
174
|
+
r.delete("/_synapse/admin/v1/registration_tokens/:token", procedure({ handler: async (ctx) => {
|
|
154
175
|
await requireAdmin(ctx);
|
|
155
176
|
await ctx.hs.admin.deleteRegistrationToken(ctx.params.token);
|
|
156
177
|
return {};
|
|
157
|
-
});
|
|
158
|
-
r.get("/_synapse/admin/v1/audit_log", async (ctx) => {
|
|
178
|
+
} }));
|
|
179
|
+
r.get("/_synapse/admin/v1/audit_log", procedure({ handler: async (ctx) => {
|
|
159
180
|
await requireAdmin(ctx);
|
|
160
181
|
if (!ctx.hs.audit.enabled) throw errors.unrecognized("The audit log is disabled");
|
|
161
182
|
const rows = await ctx.hs.audit.query({
|
|
@@ -169,8 +190,8 @@ function registerAdminRoutes(r) {
|
|
|
169
190
|
const out = { entries: rows };
|
|
170
191
|
if (rows.length) out.next_token = String(rows[rows.length - 1].id);
|
|
171
192
|
return out;
|
|
172
|
-
});
|
|
173
|
-
r.get("/_synapse/admin/v1/event_reports", async (ctx) => {
|
|
193
|
+
} }));
|
|
194
|
+
r.get("/_synapse/admin/v1/event_reports", procedure({ handler: async (ctx) => {
|
|
174
195
|
await requireAdmin(ctx);
|
|
175
196
|
const rows = await ctx.hs.db.findMany("event_reports", {
|
|
176
197
|
sortBy: {
|
|
@@ -192,16 +213,16 @@ function registerAdminRoutes(r) {
|
|
|
192
213
|
})),
|
|
193
214
|
total: rows.length
|
|
194
215
|
};
|
|
195
|
-
});
|
|
196
|
-
r.post("/_synapse/admin/v1/event_reports/:id/resolve", async (ctx) => {
|
|
216
|
+
} }));
|
|
217
|
+
r.post("/_synapse/admin/v1/event_reports/:id/resolve", procedure({ handler: async (ctx) => {
|
|
197
218
|
await requireAdmin(ctx);
|
|
198
219
|
if (!await ctx.hs.db.update("event_reports", [{
|
|
199
220
|
field: "id",
|
|
200
221
|
value: Number(ctx.params.id)
|
|
201
222
|
}], { resolved: true })) throw errors.notFound("Unknown report");
|
|
202
223
|
return {};
|
|
203
|
-
});
|
|
204
|
-
r.get("/_synapse/admin/v1/rooms", async (ctx) => {
|
|
224
|
+
} }));
|
|
225
|
+
r.get("/_synapse/admin/v1/rooms", procedure({ handler: async (ctx) => {
|
|
205
226
|
await requireAdmin(ctx);
|
|
206
227
|
const res = await ctx.hs.admin.listRooms({
|
|
207
228
|
from: Number(ctx.query.get("from") ?? 0) || 0,
|
|
@@ -211,8 +232,8 @@ function registerAdminRoutes(r) {
|
|
|
211
232
|
rooms: res.rooms,
|
|
212
233
|
total_rooms: res.total
|
|
213
234
|
};
|
|
214
|
-
});
|
|
215
|
-
r.delete("/_synapse/admin/v1/rooms/:roomId", async (ctx) => {
|
|
235
|
+
} }));
|
|
236
|
+
r.delete("/_synapse/admin/v1/rooms/:roomId", procedure({ handler: async (ctx) => {
|
|
216
237
|
const s = await requireAdmin(ctx);
|
|
217
238
|
const body = await ctx.json();
|
|
218
239
|
const { kicked } = await ctx.hs.admin.deleteRoom(ctx.params.roomId, {
|
|
@@ -226,8 +247,8 @@ function registerAdminRoutes(r) {
|
|
|
226
247
|
local_aliases: [],
|
|
227
248
|
new_room_id: null
|
|
228
249
|
};
|
|
229
|
-
});
|
|
230
|
-
r.delete("/_synapse/admin/v1/media/:serverName/:mediaId", async (ctx) => {
|
|
250
|
+
} }));
|
|
251
|
+
r.delete("/_synapse/admin/v1/media/:serverName/:mediaId", procedure({ handler: async (ctx) => {
|
|
231
252
|
await requireAdmin(ctx);
|
|
232
253
|
if (ctx.params.serverName !== ctx.hs.serverName) throw errors.notFound("Remote media");
|
|
233
254
|
await ctx.hs.admin.deleteMedia(ctx.params.mediaId);
|
|
@@ -235,8 +256,8 @@ function registerAdminRoutes(r) {
|
|
|
235
256
|
deleted_media: [ctx.params.mediaId],
|
|
236
257
|
total: 1
|
|
237
258
|
};
|
|
238
|
-
});
|
|
239
|
-
r.post("/_synapse/admin/v1/media/delete", async (ctx) => {
|
|
259
|
+
} }));
|
|
260
|
+
r.post("/_synapse/admin/v1/media/delete", procedure({ handler: async (ctx) => {
|
|
240
261
|
await requireAdmin(ctx);
|
|
241
262
|
const before = Number(ctx.query.get("before_ts"));
|
|
242
263
|
if (!Number.isFinite(before)) throw errors.missingParam("Missing before_ts");
|
|
@@ -245,7 +266,7 @@ function registerAdminRoutes(r) {
|
|
|
245
266
|
deleted_media: deleted,
|
|
246
267
|
total: deleted.length
|
|
247
268
|
};
|
|
248
|
-
});
|
|
269
|
+
} }));
|
|
249
270
|
}
|
|
250
271
|
//#endregion
|
|
251
272
|
export { registerAdminRoutes };
|
package/dist/api/appservice.js
CHANGED
|
@@ -1,32 +1,44 @@
|
|
|
1
1
|
import { errors } from "../core/errors.js";
|
|
2
|
+
import { procedure } from "../http/procedure.js";
|
|
2
3
|
//#region src/api/appservice.ts
|
|
3
4
|
function registerAppServiceRoutes(r) {
|
|
4
|
-
r.client("POST", "/appservice/:appserviceId/ping",
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
5
|
+
r.client("POST", "/appservice/:appserviceId/ping", procedure({
|
|
6
|
+
auth: "user",
|
|
7
|
+
handler: async (ctx) => {
|
|
8
|
+
const s = ctx.session;
|
|
9
|
+
if (!s.appservice) throw errors.forbidden("An application service token is required");
|
|
10
|
+
if (s.appservice.id !== ctx.params.appserviceId) throw errors.forbidden("Token does not belong to this application service");
|
|
11
|
+
const body = await ctx.json();
|
|
12
|
+
return { duration_ms: await ctx.hs.appservices.ping(s.appservice, typeof body.transaction_id === "string" ? body.transaction_id : void 0) };
|
|
13
|
+
}
|
|
14
|
+
}), ["v1"]);
|
|
15
|
+
r.client("GET", "/thirdparty/protocols", procedure({
|
|
16
|
+
auth: "user",
|
|
17
|
+
handler: async (ctx) => {
|
|
18
|
+
return ctx.hs.appservices.protocols();
|
|
19
|
+
}
|
|
20
|
+
}));
|
|
21
|
+
r.client("GET", "/thirdparty/protocol/:protocol", procedure({
|
|
22
|
+
auth: "user",
|
|
23
|
+
handler: async (ctx) => {
|
|
24
|
+
const p = (await ctx.hs.appservices.protocols())[ctx.params.protocol];
|
|
25
|
+
if (!p) throw errors.notFound("Unknown protocol");
|
|
26
|
+
return p;
|
|
27
|
+
}
|
|
28
|
+
}));
|
|
21
29
|
for (const kind of ["location", "user"]) {
|
|
22
|
-
r.client("GET", `/thirdparty/${kind}/:protocol`,
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
+
r.client("GET", `/thirdparty/${kind}/:protocol`, procedure({
|
|
31
|
+
auth: "user",
|
|
32
|
+
handler: async (ctx) => {
|
|
33
|
+
return ctx.hs.appservices.thirdParty(`${kind}/${encodeURIComponent(ctx.params.protocol)}`, ctx.query);
|
|
34
|
+
}
|
|
35
|
+
}));
|
|
36
|
+
r.client("GET", `/thirdparty/${kind}`, procedure({
|
|
37
|
+
auth: "user",
|
|
38
|
+
handler: async (ctx) => {
|
|
39
|
+
return ctx.hs.appservices.thirdParty(kind, ctx.query);
|
|
40
|
+
}
|
|
41
|
+
}));
|
|
30
42
|
}
|
|
31
43
|
}
|
|
32
44
|
//#endregion
|
package/dist/api/backup.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { isObject } from "../core/json.js";
|
|
2
2
|
import { MatrixError, errors } from "../core/errors.js";
|
|
3
|
+
import { looseObject, string } from "../vendor/zod/v4/classic/schemas.js";
|
|
3
4
|
import { body, fail } from "../http/input.js";
|
|
4
|
-
import {
|
|
5
|
+
import { procedure } from "../http/procedure.js";
|
|
5
6
|
//#region src/api/backup.ts
|
|
6
7
|
const required = fail("M_BAD_JSON", "algorithm and auth_data are required");
|
|
7
8
|
const createVersionBody = body({
|
|
8
|
-
algorithm:
|
|
9
|
-
auth_data:
|
|
9
|
+
algorithm: string(required),
|
|
10
|
+
auth_data: looseObject({}, required)
|
|
10
11
|
});
|
|
11
12
|
/** Server-side room key backups (`/room_keys`). */
|
|
12
13
|
async function latestVersion(hs, userId) {
|
|
@@ -74,68 +75,78 @@ async function requireCurrentVersion(ctx, userId) {
|
|
|
74
75
|
};
|
|
75
76
|
}
|
|
76
77
|
function registerBackupRoutes(r) {
|
|
77
|
-
r.client("POST", "/room_keys/version",
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
78
|
+
r.client("POST", "/room_keys/version", procedure({
|
|
79
|
+
auth: "user",
|
|
80
|
+
input: createVersionBody,
|
|
81
|
+
handler: async (ctx) => {
|
|
82
|
+
const s = ctx.session;
|
|
83
|
+
const body = ctx.input;
|
|
84
|
+
const max = (await ctx.hs.db.findMany("backup_versions", { where: [{
|
|
85
|
+
field: "user_id",
|
|
86
|
+
value: s.userId
|
|
87
|
+
}] })).reduce((m, v) => Math.max(m, v.version), 0);
|
|
88
|
+
await ctx.hs.db.create("backup_versions", {
|
|
89
|
+
user_id: s.userId,
|
|
90
|
+
version: max + 1,
|
|
91
|
+
algorithm: body.algorithm,
|
|
92
|
+
auth_data: body.auth_data,
|
|
93
|
+
etag: 0,
|
|
94
|
+
deleted: false
|
|
95
|
+
});
|
|
96
|
+
return { version: String(max + 1) };
|
|
97
|
+
}
|
|
98
|
+
}));
|
|
94
99
|
const getVersionHandler = async (ctx) => {
|
|
95
100
|
const s = await ctx.auth();
|
|
96
101
|
const row = await getVersion(ctx.hs, s.userId, ctx.params.version ?? null);
|
|
97
102
|
if (!row) throw errors.notFound("No backup found");
|
|
98
103
|
return describe(ctx.hs, row);
|
|
99
104
|
};
|
|
100
|
-
r.client("GET", "/room_keys/version", getVersionHandler);
|
|
101
|
-
r.client("GET", "/room_keys/version/:version", getVersionHandler);
|
|
102
|
-
r.client("PUT", "/room_keys/version/:version",
|
|
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
|
-
|
|
105
|
+
r.client("GET", "/room_keys/version", procedure({ handler: getVersionHandler }));
|
|
106
|
+
r.client("GET", "/room_keys/version/:version", procedure({ handler: getVersionHandler }));
|
|
107
|
+
r.client("PUT", "/room_keys/version/:version", procedure({
|
|
108
|
+
auth: "user",
|
|
109
|
+
handler: async (ctx) => {
|
|
110
|
+
const s = ctx.session;
|
|
111
|
+
const body = await ctx.json();
|
|
112
|
+
const row = await getVersion(ctx.hs, s.userId, ctx.params.version);
|
|
113
|
+
if (!row) throw errors.notFound("Unknown backup version");
|
|
114
|
+
if (body.version !== void 0 && String(body.version) !== ctx.params.version) throw errors.invalidParam("Version mismatch");
|
|
115
|
+
if (body.algorithm !== row.algorithm) throw errors.invalidParam("Algorithm cannot be changed");
|
|
116
|
+
if (!isObject(body.auth_data)) throw errors.badJson("auth_data is required");
|
|
117
|
+
await ctx.hs.db.update("backup_versions", [{
|
|
118
|
+
field: "user_id",
|
|
119
|
+
value: s.userId
|
|
120
|
+
}, {
|
|
121
|
+
field: "version",
|
|
122
|
+
value: row.version
|
|
123
|
+
}], { auth_data: body.auth_data });
|
|
124
|
+
return {};
|
|
125
|
+
}
|
|
126
|
+
}));
|
|
127
|
+
r.client("DELETE", "/room_keys/version/:version", procedure({
|
|
128
|
+
auth: "user",
|
|
129
|
+
handler: async (ctx) => {
|
|
130
|
+
const s = ctx.session;
|
|
131
|
+
const row = await getVersion(ctx.hs, s.userId, ctx.params.version);
|
|
132
|
+
if (!row) throw errors.notFound("Unknown backup version");
|
|
133
|
+
await ctx.hs.db.update("backup_versions", [{
|
|
134
|
+
field: "user_id",
|
|
135
|
+
value: s.userId
|
|
136
|
+
}, {
|
|
137
|
+
field: "version",
|
|
138
|
+
value: row.version
|
|
139
|
+
}], { deleted: true });
|
|
140
|
+
await ctx.hs.db.delete("backup_keys", [{
|
|
141
|
+
field: "user_id",
|
|
142
|
+
value: s.userId
|
|
143
|
+
}, {
|
|
144
|
+
field: "version",
|
|
145
|
+
value: row.version
|
|
146
|
+
}]);
|
|
147
|
+
return {};
|
|
148
|
+
}
|
|
149
|
+
}));
|
|
139
150
|
const putKeys = async (ctx) => {
|
|
140
151
|
const s = await ctx.auth();
|
|
141
152
|
const hs = ctx.hs;
|
|
@@ -260,9 +271,9 @@ function registerBackupRoutes(r) {
|
|
|
260
271
|
"/room_keys/keys/:roomId",
|
|
261
272
|
"/room_keys/keys/:roomId/:sessionId"
|
|
262
273
|
]) {
|
|
263
|
-
r.client("PUT", path, putKeys);
|
|
264
|
-
r.client("GET", path, getKeys);
|
|
265
|
-
r.client("DELETE", path, deleteKeys);
|
|
274
|
+
r.client("PUT", path, procedure({ handler: putKeys }));
|
|
275
|
+
r.client("GET", path, procedure({ handler: getKeys }));
|
|
276
|
+
r.client("DELETE", path, procedure({ handler: deleteKeys }));
|
|
266
277
|
}
|
|
267
278
|
}
|
|
268
279
|
//#endregion
|