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.
Files changed (99) hide show
  1. package/README.md +89 -11
  2. package/dist/adapters/cluster.d.ts +1 -26
  3. package/dist/adapters/cluster.js +50 -103
  4. package/dist/api/account.js +407 -354
  5. package/dist/api/admin.js +82 -61
  6. package/dist/api/appservice.js +37 -25
  7. package/dist/api/backup.js +73 -62
  8. package/dist/api/federation.js +172 -138
  9. package/dist/api/filters.js +4 -3
  10. package/dist/api/legacy.js +91 -78
  11. package/dist/api/media.js +71 -55
  12. package/dist/api/misc.js +46 -37
  13. package/dist/api/preview.js +37 -73
  14. package/dist/api/profile.js +108 -97
  15. package/dist/api/push.js +114 -99
  16. package/dist/api/relationships.js +64 -58
  17. package/dist/api/rooms.js +703 -580
  18. package/dist/api/rtc.d.ts +0 -1
  19. package/dist/api/rtc.js +48 -34
  20. package/dist/api/search.js +133 -127
  21. package/dist/api/slidingsync.js +41 -31
  22. package/dist/api/spaces.js +82 -77
  23. package/dist/api/sync.js +325 -135
  24. package/dist/api/threadsubs.js +72 -61
  25. package/dist/api/threepid.js +99 -66
  26. package/dist/api/uia.js +17 -16
  27. package/dist/api/user.js +221 -178
  28. package/dist/core/admin.d.ts +0 -1
  29. package/dist/core/admin.js +6 -5
  30. package/dist/core/adminroom.js +9 -8
  31. package/dist/core/appservices.d.ts +2 -1
  32. package/dist/core/appservices.js +5 -4
  33. package/dist/core/audit.d.ts +0 -1
  34. package/dist/core/authrules.js +26 -25
  35. package/dist/core/cluster.d.ts +12 -5
  36. package/dist/core/cluster.js +46 -29
  37. package/dist/core/delayed.js +2 -1
  38. package/dist/core/events.js +11 -10
  39. package/dist/core/html.js +13 -0
  40. package/dist/core/identity.js +1 -1
  41. package/dist/core/invitefilter.js +2 -1
  42. package/dist/core/json.js +10 -1
  43. package/dist/core/keys.d.ts +10 -1
  44. package/dist/core/keys.js +62 -42
  45. package/dist/core/m.d.ts +209 -0
  46. package/dist/core/m.js +182 -0
  47. package/dist/core/outbound.d.ts +16 -0
  48. package/dist/core/outbound.js +172 -0
  49. package/dist/core/partialstate.js +2 -1
  50. package/dist/core/policy.js +4 -3
  51. package/dist/core/push.d.ts +0 -1
  52. package/dist/core/push.js +41 -28
  53. package/dist/core/pushrules.js +36 -35
  54. package/dist/core/ratelimit.d.ts +1 -1
  55. package/dist/core/rooms.d.ts +10 -1
  56. package/dist/core/rooms.js +101 -74
  57. package/dist/core/semaphore.js +23 -0
  58. package/dist/core/sso.d.ts +15 -1
  59. package/dist/core/sso.js +38 -2
  60. package/dist/core/stateres.js +7 -6
  61. package/dist/core/threepid.js +1 -9
  62. package/dist/federation/client.js +9 -1
  63. package/dist/federation/index.d.ts +2 -2
  64. package/dist/federation/index.js +43 -35
  65. package/dist/homeserver.d.ts +23 -4
  66. package/dist/homeserver.js +12 -3
  67. package/dist/http/handler.js +2 -23
  68. package/dist/http/input.js +2 -2
  69. package/dist/http/procedure.js +25 -0
  70. package/dist/http/router.d.ts +9 -26
  71. package/dist/http/router.js +10 -30
  72. package/dist/index.d.ts +4 -3
  73. package/dist/index.js +3 -2
  74. package/dist/storage/batch.js +11 -0
  75. package/dist/storage/memory.js +1 -0
  76. package/dist/storage/schema.js +1 -1
  77. package/dist/storage/sql.js +20 -1
  78. package/dist/storage/types.d.ts +16 -0
  79. package/dist/vendor/zod/LICENSE +21 -0
  80. package/dist/vendor/zod/v4/classic/errors.js +54 -0
  81. package/dist/vendor/zod/v4/classic/parse.js +17 -0
  82. package/dist/vendor/zod/v4/classic/schemas.js +865 -0
  83. package/dist/vendor/zod/v4/core/api.js +512 -0
  84. package/dist/vendor/zod/v4/core/checks.js +300 -0
  85. package/dist/vendor/zod/v4/core/core.js +109 -0
  86. package/dist/vendor/zod/v4/core/doc.js +35 -0
  87. package/dist/vendor/zod/v4/core/errors.js +118 -0
  88. package/dist/vendor/zod/v4/core/json-schema-processors.js +428 -0
  89. package/dist/vendor/zod/v4/core/memoizer.js +255 -0
  90. package/dist/vendor/zod/v4/core/parse.js +206 -0
  91. package/dist/vendor/zod/v4/core/regexes.js +73 -0
  92. package/dist/vendor/zod/v4/core/registries.js +48 -0
  93. package/dist/vendor/zod/v4/core/schemas.js +1378 -0
  94. package/dist/vendor/zod/v4/core/to-json-schema.js +448 -0
  95. package/dist/vendor/zod/v4/core/util.js +537 -0
  96. package/dist/vendor/zod/v4/core/versions.js +8 -0
  97. package/dist/vendor/zod/v4/locales/en.js +110 -0
  98. package/package.json +8 -6
  99. 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 { z } from "zod";
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: z.string(required),
8
- content: z.looseObject({}, required),
9
- type: lenient(z.string())
8
+ user_id: string(required),
9
+ content: looseObject({}, required),
10
+ type: lenient(string())
10
11
  });
11
- const optionalInt = (name) => z.number(fail("M_INVALID_PARAM", `${name} must be an integer`)).int(`M_INVALID_PARAM: ${name} must be an integer`);
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: z.string(fail("M_INVALID_PARAM", "Invalid token")).optional(),
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", { input: noticeBody }, notice);
73
- r.put("/_synapse/admin/v1/send_server_notice/:txnId", { input: noticeBody }, notice);
74
- r.get("/_synapse/admin/v2/users", async (ctx) => {
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", { input: body({ erase: lenient(z.boolean()) }) }, async (ctx) => {
124
- await requireAdmin(ctx);
125
- const body = ctx.input;
126
- await ctx.hs.admin.deactivateUser(ctx.params.userId, { erase: body.erase === true });
127
- return { id_server_unbind_result: "no-support" };
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: z.string(fail("M_MISSING_PARAM", "Missing new_password")),
131
- logout_devices: lenient(z.boolean())
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", { input: resetPasswordBody }, async (ctx) => {
134
- await requireAdmin(ctx);
135
- const body = ctx.input;
136
- await ctx.hs.admin.resetPassword(ctx.params.userId, body.new_password, body.logout_devices !== false);
137
- return {};
138
- });
139
- r.get("/_synapse/admin/v1/registration_tokens", async (ctx) => {
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", { input: registrationTokenBody }, async (ctx) => {
144
- await requireAdmin(ctx);
145
- const body = ctx.input;
146
- return ctx.hs.admin.createRegistrationToken({
147
- token: body.token,
148
- usesAllowed: body.uses_allowed,
149
- expiryTime: body.expiry_time,
150
- length: body.length
151
- });
152
- });
153
- r.delete("/_synapse/admin/v1/registration_tokens/:token", async (ctx) => {
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 };
@@ -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", async (ctx) => {
5
- const s = await ctx.auth();
6
- if (!s.appservice) throw errors.forbidden("An application service token is required");
7
- if (s.appservice.id !== ctx.params.appserviceId) throw errors.forbidden("Token does not belong to this application service");
8
- const body = await ctx.json();
9
- return { duration_ms: await ctx.hs.appservices.ping(s.appservice, typeof body.transaction_id === "string" ? body.transaction_id : void 0) };
10
- }, ["v1"]);
11
- r.client("GET", "/thirdparty/protocols", async (ctx) => {
12
- await ctx.auth();
13
- return ctx.hs.appservices.protocols();
14
- });
15
- r.client("GET", "/thirdparty/protocol/:protocol", async (ctx) => {
16
- await ctx.auth();
17
- const p = (await ctx.hs.appservices.protocols())[ctx.params.protocol];
18
- if (!p) throw errors.notFound("Unknown protocol");
19
- return p;
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`, async (ctx) => {
23
- await ctx.auth();
24
- return ctx.hs.appservices.thirdParty(`${kind}/${encodeURIComponent(ctx.params.protocol)}`, ctx.query);
25
- });
26
- r.client("GET", `/thirdparty/${kind}`, async (ctx) => {
27
- await ctx.auth();
28
- return ctx.hs.appservices.thirdParty(kind, ctx.query);
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
@@ -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 { z } from "zod";
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: z.string(required),
9
- auth_data: z.looseObject({}, required)
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", { input: createVersionBody }, async (ctx) => {
78
- const s = await ctx.auth();
79
- const body = ctx.input;
80
- const max = (await ctx.hs.db.findMany("backup_versions", { where: [{
81
- field: "user_id",
82
- value: s.userId
83
- }] })).reduce((m, v) => Math.max(m, v.version), 0);
84
- await ctx.hs.db.create("backup_versions", {
85
- user_id: s.userId,
86
- version: max + 1,
87
- algorithm: body.algorithm,
88
- auth_data: body.auth_data,
89
- etag: 0,
90
- deleted: false
91
- });
92
- return { version: String(max + 1) };
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", async (ctx) => {
103
- const s = await ctx.auth();
104
- const body = await ctx.json();
105
- const row = await getVersion(ctx.hs, s.userId, ctx.params.version);
106
- if (!row) throw errors.notFound("Unknown backup version");
107
- if (body.version !== void 0 && String(body.version) !== ctx.params.version) throw errors.invalidParam("Version mismatch");
108
- if (body.algorithm !== row.algorithm) throw errors.invalidParam("Algorithm cannot be changed");
109
- if (!isObject(body.auth_data)) throw errors.badJson("auth_data is required");
110
- await ctx.hs.db.update("backup_versions", [{
111
- field: "user_id",
112
- value: s.userId
113
- }, {
114
- field: "version",
115
- value: row.version
116
- }], { auth_data: body.auth_data });
117
- return {};
118
- });
119
- r.client("DELETE", "/room_keys/version/:version", async (ctx) => {
120
- const s = await ctx.auth();
121
- const row = await getVersion(ctx.hs, s.userId, ctx.params.version);
122
- if (!row) throw errors.notFound("Unknown backup version");
123
- await ctx.hs.db.update("backup_versions", [{
124
- field: "user_id",
125
- value: s.userId
126
- }, {
127
- field: "version",
128
- value: row.version
129
- }], { deleted: true });
130
- await ctx.hs.db.delete("backup_keys", [{
131
- field: "user_id",
132
- value: s.userId
133
- }, {
134
- field: "version",
135
- value: row.version
136
- }]);
137
- return {};
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