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
@@ -1,5 +1,7 @@
1
1
  import { isObject } from "../core/json.js";
2
+ import { M } from "../core/m.js";
2
3
  import { MatrixError, errors } from "../core/errors.js";
4
+ import { procedure } from "../http/procedure.js";
3
5
  //#region src/api/threadsubs.ts
4
6
  const VERSIONS = ["unstable/io.element.msc4306"];
5
7
  const notInThread = () => new MatrixError(400, "IO.ELEMENT.MSC4306.M_NOT_IN_THREAD", "Event is not in this thread");
@@ -38,68 +40,77 @@ async function threadRoot(ctx, userId) {
38
40
  }
39
41
  function registerThreadSubscriptionRoutes(r) {
40
42
  const path = "/rooms/:roomId/thread/:threadId/subscription";
41
- r.client("GET", path, async (ctx) => {
42
- const s = await ctx.auth();
43
- await threadRoot(ctx, s.userId);
44
- const row = await ctx.hs.db.findOne("thread_subscriptions", key(s.userId, ctx.params.roomId, ctx.params.threadId));
45
- if (!row?.subscribed) throw errors.notFound("Not subscribed to this thread");
46
- return { automatic: !!row.automatic };
47
- }, VERSIONS);
48
- r.client("PUT", path, async (ctx) => {
49
- const s = await ctx.auth();
50
- const hs = ctx.hs;
51
- const { roomId, threadId } = ctx.params;
52
- await threadRoot(ctx, s.userId);
53
- const body = await ctx.json();
54
- const cause = isObject(body) ? body.automatic : void 0;
55
- if (cause !== void 0 && typeof cause !== "string") throw errors.badJson("automatic must be an event ID");
56
- let causeStream = null;
57
- if (typeof cause === "string") {
58
- const ev = await visibleEvent(ctx, s.userId, roomId, cause);
59
- const rel = ev?.pdu.content?.["m.relates_to"];
60
- if (!ev || !isObject(rel) || rel.rel_type !== "m.thread" || rel.event_id !== threadId) throw notInThread();
61
- causeStream = ev.stream;
43
+ r.client("GET", path, procedure({
44
+ auth: "user",
45
+ handler: async (ctx) => {
46
+ const s = ctx.session;
47
+ await threadRoot(ctx, s.userId);
48
+ const row = await ctx.hs.db.findOne("thread_subscriptions", key(s.userId, ctx.params.roomId, ctx.params.threadId));
49
+ if (!row?.subscribed) throw errors.notFound("Not subscribed to this thread");
50
+ return { automatic: !!row.automatic };
62
51
  }
63
- await hs.cluster.lock(`threadsub:${s.userId}:${roomId}:${threadId}`, async () => {
64
- const row = await hs.db.findOne("thread_subscriptions", key(s.userId, roomId, threadId));
65
- if (causeStream !== null) {
66
- if (row && row.unsubscribed_after !== null && causeStream <= row.unsubscribed_after) throw conflicting();
67
- if (row?.subscribed) return;
68
- } else if (row?.subscribed && !row.automatic) return;
69
- await hs.streams.write((stream) => hs.db.upsert("thread_subscriptions", {
70
- user_id: s.userId,
71
- room_id: roomId,
72
- thread_id: threadId,
73
- subscribed: true,
74
- automatic: causeStream !== null,
75
- unsubscribed_after: row?.unsubscribed_after ?? null,
76
- stream
77
- }));
78
- });
79
- hs.notifier.notify([s.userId]);
80
- return {};
81
- }, VERSIONS);
82
- r.client("DELETE", path, async (ctx) => {
83
- const s = await ctx.auth();
84
- const hs = ctx.hs;
85
- const { roomId, threadId } = ctx.params;
86
- await threadRoot(ctx, s.userId);
87
- await hs.cluster.lock(`threadsub:${s.userId}:${roomId}:${threadId}`, async () => {
88
- if (!(await hs.db.findOne("thread_subscriptions", key(s.userId, roomId, threadId)))?.subscribed) return;
89
- const position = await hs.streams.position();
90
- await hs.streams.write((stream) => hs.db.upsert("thread_subscriptions", {
91
- user_id: s.userId,
92
- room_id: roomId,
93
- thread_id: threadId,
94
- subscribed: false,
95
- automatic: false,
96
- unsubscribed_after: position,
97
- stream
98
- }));
99
- });
100
- hs.notifier.notify([s.userId]);
101
- return {};
102
- }, VERSIONS);
52
+ }), VERSIONS);
53
+ r.client("PUT", path, procedure({
54
+ auth: "user",
55
+ handler: async (ctx) => {
56
+ const s = ctx.session;
57
+ const hs = ctx.hs;
58
+ const { roomId, threadId } = ctx.params;
59
+ await threadRoot(ctx, s.userId);
60
+ const body = await ctx.json();
61
+ const cause = isObject(body) ? body.automatic : void 0;
62
+ if (cause !== void 0 && typeof cause !== "string") throw errors.badJson("automatic must be an event ID");
63
+ let causeStream = null;
64
+ if (typeof cause === "string") {
65
+ const ev = await visibleEvent(ctx, s.userId, roomId, cause);
66
+ const rel = ev?.pdu.content?.[M.RELATES_TO];
67
+ if (!ev || !isObject(rel) || rel.rel_type !== M.THREAD || rel.event_id !== threadId) throw notInThread();
68
+ causeStream = ev.stream;
69
+ }
70
+ await hs.cluster.lock(`threadsub:${s.userId}:${roomId}:${threadId}`, async () => {
71
+ const row = await hs.db.findOne("thread_subscriptions", key(s.userId, roomId, threadId));
72
+ if (causeStream !== null) {
73
+ if (row && row.unsubscribed_after !== null && causeStream <= row.unsubscribed_after) throw conflicting();
74
+ if (row?.subscribed) return;
75
+ } else if (row?.subscribed && !row.automatic) return;
76
+ await hs.streams.write((stream) => hs.db.upsert("thread_subscriptions", {
77
+ user_id: s.userId,
78
+ room_id: roomId,
79
+ thread_id: threadId,
80
+ subscribed: true,
81
+ automatic: causeStream !== null,
82
+ unsubscribed_after: row?.unsubscribed_after ?? null,
83
+ stream
84
+ }));
85
+ });
86
+ hs.notifier.notify([s.userId]);
87
+ return {};
88
+ }
89
+ }), VERSIONS);
90
+ r.client("DELETE", path, procedure({
91
+ auth: "user",
92
+ handler: async (ctx) => {
93
+ const s = ctx.session;
94
+ const hs = ctx.hs;
95
+ const { roomId, threadId } = ctx.params;
96
+ await threadRoot(ctx, s.userId);
97
+ await hs.cluster.lock(`threadsub:${s.userId}:${roomId}:${threadId}`, async () => {
98
+ if (!(await hs.db.findOne("thread_subscriptions", key(s.userId, roomId, threadId)))?.subscribed) return;
99
+ const position = await hs.streams.position();
100
+ await hs.streams.write((stream) => hs.db.upsert("thread_subscriptions", {
101
+ user_id: s.userId,
102
+ room_id: roomId,
103
+ thread_id: threadId,
104
+ subscribed: false,
105
+ automatic: false,
106
+ unsubscribed_after: position,
107
+ stream
108
+ }));
109
+ });
110
+ hs.notifier.notify([s.userId]);
111
+ return {};
112
+ }
113
+ }), VERSIONS);
103
114
  }
104
115
  /** MSC4308 sliding sync extension: subscription changes in (since, to]. */
105
116
  async function threadSubscriptionsExtension(hs, userId, ext, since, to) {
@@ -1,16 +1,18 @@
1
+ import { M } from "../core/m.js";
1
2
  import { MatrixError, errors } from "../core/errors.js";
2
3
  import { canonicalAddress, isMedium } from "../core/threepid.js";
3
- import { requireUia } from "./uia.js";
4
+ import { enum as _enum, string } from "../vendor/zod/v4/classic/schemas.js";
4
5
  import { body, fail, lenient } from "../http/input.js";
5
- import { z } from "zod";
6
+ import { procedure } from "../http/procedure.js";
7
+ import { requireUia } from "./uia.js";
6
8
  //#region src/api/threepid.ts
7
- const submitField = z.string(fail("M_MISSING_PARAM", "sid, client_secret and token are required"));
9
+ const submitField = string(fail("M_MISSING_PARAM", "sid, client_secret and token are required"));
8
10
  const submitBody = body({
9
11
  sid: submitField,
10
12
  client_secret: submitField,
11
13
  token: submitField
12
14
  });
13
- const bindField = (name) => z.string(fail("M_MISSING_PARAM", `Missing ${name}`));
15
+ const bindField = (name) => string(fail("M_MISSING_PARAM", `Missing ${name}`));
14
16
  const bindBody = body({
15
17
  client_secret: bindField("client_secret"),
16
18
  id_access_token: bindField("id_access_token"),
@@ -18,9 +20,9 @@ const bindBody = body({
18
20
  sid: bindField("sid")
19
21
  });
20
22
  const threepidBody = body({
21
- medium: z.enum(["email", "msisdn"], fail("M_INVALID_PARAM", "Unsupported medium")),
22
- address: z.string(fail("M_INVALID_PARAM", "Invalid address")),
23
- id_server: z.string(fail("M_INVALID_PARAM", "id_server must be a string")).optional()
23
+ medium: _enum(["email", "msisdn"], fail("M_INVALID_PARAM", "Unsupported medium")),
24
+ address: string(fail("M_INVALID_PARAM", "Invalid address")),
25
+ id_server: string(fail("M_INVALID_PARAM", "id_server must be a string")).optional()
24
26
  });
25
27
  function notDelegated(ctx) {
26
28
  if (ctx.hs.oauth) throw errors.unrecognized("Managed by the OAuth provider");
@@ -32,12 +34,21 @@ function registerThreepidRoutes(r) {
32
34
  return ctx.hs.threepids.requestToken(purpose, medium, ctx.input);
33
35
  };
34
36
  for (const medium of ["email", "msisdn"]) {
35
- r.client("POST", `/register/${medium}/requestToken`, { input: body({}) }, requestToken("register", medium));
36
- r.client("POST", `/account/password/${medium}/requestToken`, { input: body({}) }, requestToken("password_reset", medium));
37
- r.client("POST", `/account/3pid/${medium}/requestToken`, { input: body({}) }, requestToken("add_threepid", medium));
37
+ r.client("POST", `/register/${medium}/requestToken`, procedure({
38
+ input: body({}),
39
+ handler: requestToken("register", medium)
40
+ }));
41
+ r.client("POST", `/account/password/${medium}/requestToken`, procedure({
42
+ input: body({}),
43
+ handler: requestToken("password_reset", medium)
44
+ }));
45
+ r.client("POST", `/account/3pid/${medium}/requestToken`, procedure({
46
+ input: body({}),
47
+ handler: requestToken("add_threepid", medium)
48
+ }));
38
49
  }
39
50
  const submitPath = "/_matrix/client/unstable/threepid/submit_token";
40
- r.get(submitPath, async (ctx) => {
51
+ r.get(submitPath, procedure({ handler: async (ctx) => {
41
52
  const q = ctx.query;
42
53
  let nextLink = null;
43
54
  let message = "Your address has been validated. You can return to your Matrix client.";
@@ -53,44 +64,57 @@ function registerThreepidRoutes(r) {
53
64
  status,
54
65
  headers: { "content-type": "text/html; charset=utf-8" }
55
66
  });
56
- });
57
- r.post(submitPath, { input: submitBody }, async (ctx) => {
58
- const body = ctx.input;
59
- await ctx.hs.threepids.submitToken(body.sid, body.client_secret, body.token);
60
- return { success: true };
61
- });
62
- r.client("GET", "/account/3pid", async (ctx) => {
63
- const s = await ctx.auth();
64
- return { threepids: await ctx.hs.threepids.list(s.userId) };
65
- });
66
- r.client("POST", "/account/3pid/add", { input: body({
67
- sid: lenient(z.string()),
68
- client_secret: lenient(z.string())
69
- }) }, async (ctx) => {
70
- notDelegated(ctx);
71
- const s = await ctx.auth();
72
- const body = ctx.input;
73
- await requireUia(ctx.hs, body, [["m.login.password"]], s.userId);
74
- const validated = await ctx.hs.threepids.validated({
75
- sid: body.sid,
76
- client_secret: body.client_secret
77
- });
78
- if (!validated) throw new MatrixError(400, "M_THREEPID_AUTH_FAILED", "The address has not been validated");
79
- await ctx.hs.threepids.add(s.userId, validated);
80
- return {};
81
- });
82
- r.client("POST", "/account/3pid/bind", { input: bindBody }, async (ctx) => {
83
- const s = await ctx.auth();
84
- const body = ctx.input;
85
- const res = await ctx.hs.identityServers.bind(body.id_server, body.id_access_token, body.sid, body.client_secret, s.userId);
86
- if (res && isMedium(res.medium) && typeof res.address === "string") await ctx.hs.db.upsert("threepid_bindings", {
87
- user_id: s.userId,
88
- medium: res.medium,
89
- address: res.address,
90
- id_server: body.id_server
91
- });
92
- return {};
93
- });
67
+ } }));
68
+ r.post(submitPath, procedure({
69
+ input: submitBody,
70
+ handler: async (ctx) => {
71
+ const body = ctx.input;
72
+ await ctx.hs.threepids.submitToken(body.sid, body.client_secret, body.token);
73
+ return { success: true };
74
+ }
75
+ }));
76
+ r.client("GET", "/account/3pid", procedure({
77
+ auth: "user",
78
+ handler: async (ctx) => {
79
+ const s = ctx.session;
80
+ return { threepids: await ctx.hs.threepids.list(s.userId) };
81
+ }
82
+ }));
83
+ r.client("POST", "/account/3pid/add", procedure({
84
+ input: body({
85
+ sid: lenient(string()),
86
+ client_secret: lenient(string())
87
+ }),
88
+ handler: async (ctx) => {
89
+ notDelegated(ctx);
90
+ const s = await ctx.auth();
91
+ const body = ctx.input;
92
+ await requireUia(ctx.hs, body, [[M.LOGIN.PASSWORD]], s.userId);
93
+ const validated = await ctx.hs.threepids.validated({
94
+ sid: body.sid,
95
+ client_secret: body.client_secret
96
+ });
97
+ if (!validated) throw new MatrixError(400, "M_THREEPID_AUTH_FAILED", "The address has not been validated");
98
+ await ctx.hs.threepids.add(s.userId, validated);
99
+ return {};
100
+ }
101
+ }));
102
+ r.client("POST", "/account/3pid/bind", procedure({
103
+ auth: "user",
104
+ input: bindBody,
105
+ handler: async (ctx) => {
106
+ const s = ctx.session;
107
+ const body = ctx.input;
108
+ const res = await ctx.hs.identityServers.bind(body.id_server, body.id_access_token, body.sid, body.client_secret, s.userId);
109
+ if (res && isMedium(res.medium) && typeof res.address === "string") await ctx.hs.db.upsert("threepid_bindings", {
110
+ user_id: s.userId,
111
+ medium: res.medium,
112
+ address: res.address,
113
+ id_server: body.id_server
114
+ });
115
+ return {};
116
+ }
117
+ }));
94
118
  const parseThreepid = (body) => {
95
119
  const address = canonicalAddress(body.medium, body.address);
96
120
  if (!address) throw errors.invalidParam("Invalid address");
@@ -100,23 +124,32 @@ function registerThreepidRoutes(r) {
100
124
  idServer: body.id_server
101
125
  };
102
126
  };
103
- r.client("POST", "/account/3pid/delete", { input: threepidBody }, async (ctx) => {
104
- notDelegated(ctx);
105
- const s = await ctx.auth();
106
- const { medium, address, idServer } = parseThreepid(ctx.input);
107
- const result = await ctx.hs.threepids.unbindAll(s.userId, medium, address, idServer);
108
- await ctx.hs.threepids.remove(s.userId, medium, address);
109
- return { id_server_unbind_result: result };
110
- });
111
- r.client("POST", "/account/3pid/unbind", { input: threepidBody }, async (ctx) => {
112
- const s = await ctx.auth();
113
- const { medium, address, idServer } = parseThreepid(ctx.input);
114
- return { id_server_unbind_result: await ctx.hs.threepids.unbindAll(s.userId, medium, address, idServer) };
115
- });
116
- r.client("POST", "/account/3pid", async (ctx) => {
117
- await ctx.auth();
118
- throw errors.threepidDenied();
119
- });
127
+ r.client("POST", "/account/3pid/delete", procedure({
128
+ input: threepidBody,
129
+ handler: async (ctx) => {
130
+ notDelegated(ctx);
131
+ const s = await ctx.auth();
132
+ const { medium, address, idServer } = parseThreepid(ctx.input);
133
+ const result = await ctx.hs.threepids.unbindAll(s.userId, medium, address, idServer);
134
+ await ctx.hs.threepids.remove(s.userId, medium, address);
135
+ return { id_server_unbind_result: result };
136
+ }
137
+ }));
138
+ r.client("POST", "/account/3pid/unbind", procedure({
139
+ auth: "user",
140
+ input: threepidBody,
141
+ handler: async (ctx) => {
142
+ const s = ctx.session;
143
+ const { medium, address, idServer } = parseThreepid(ctx.input);
144
+ return { id_server_unbind_result: await ctx.hs.threepids.unbindAll(s.userId, medium, address, idServer) };
145
+ }
146
+ }));
147
+ r.client("POST", "/account/3pid", procedure({
148
+ auth: "user",
149
+ handler: async () => {
150
+ throw errors.threepidDenied();
151
+ }
152
+ }));
120
153
  }
121
154
  //#endregion
122
155
  export { registerThreepidRoutes };
package/dist/api/uia.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { isObject } from "../core/json.js";
2
2
  import { randomString } from "../core/crypto.js";
3
+ import { M, UNSTABLE } from "../core/m.js";
3
4
  import { MatrixError, errors } from "../core/errors.js";
4
5
  //#region src/api/uia.ts
5
6
  const UIA_TTL_MS = 6e5;
@@ -9,7 +10,7 @@ const UIA_TTL_MS = 6e5;
9
10
  * `userId` binds password stages to an already-authenticated user.
10
11
  */
11
12
  async function requireUia(hs, body, flows, userId) {
12
- if (hs.oauth && flows.some((f) => f.includes("m.login.password"))) flows = [["m.oauth"], ["org.matrix.cross_signing_reset"]];
13
+ if (hs.oauth && flows.some((f) => f.includes(M.LOGIN.PASSWORD))) flows = [[M.OAUTH], [UNSTABLE.ORG.MATRIX.CROSS_SIGNING_RESET]];
13
14
  const auth = isObject(body.auth) ? body.auth : null;
14
15
  let sessionId = typeof auth?.session === "string" ? auth.session : void 0;
15
16
  const stored = sessionId ? await hs.cluster.get(`uia:${sessionId}`) : null;
@@ -26,8 +27,8 @@ async function requireUia(hs, body, flows, userId) {
26
27
  }, UIA_TTL_MS);
27
28
  const oauthUrl = hs.oauth?.options.accountManagementUrl ?? hs.oauth?.options.issuer;
28
29
  const params = hs.oauth ? {
29
- "m.oauth": { url: oauthUrl },
30
- "org.matrix.cross_signing_reset": { url: oauthUrl }
30
+ [M.OAUTH]: { url: oauthUrl },
31
+ [UNSTABLE.ORG.MATRIX.CROSS_SIGNING_RESET]: { url: oauthUrl }
31
32
  } : {};
32
33
  const challenge = (extra = {}) => new MatrixError(401, extra.errcode ? String(extra.errcode) : "M_FORBIDDEN", String(extra.error ?? "Authentication required"), {
33
34
  flows: flows.map((stages) => ({ stages })),
@@ -36,36 +37,36 @@ async function requireUia(hs, body, flows, userId) {
36
37
  completed: [...session.completed],
37
38
  ...extra
38
39
  });
39
- if (auth?.type === "m.login.dummy" && !auth.session && typeof body.username === "string" && !userId) {
40
+ if (auth?.type === M.LOGIN.DUMMY && !auth.session && typeof body.username === "string" && !userId) {
40
41
  if (await hs.cluster.get(`uia-register:${body.username.toLowerCase()}`)) throw challenge({
41
42
  errcode: "M_FORBIDDEN",
42
43
  error: "Missing session"
43
44
  });
44
45
  }
45
46
  if (auth?.type) switch (auth.type) {
46
- case "m.login.dummy":
47
- session.completed.add("m.login.dummy");
47
+ case M.LOGIN.DUMMY:
48
+ session.completed.add(M.LOGIN.DUMMY);
48
49
  break;
49
- case "m.oauth":
50
- case "org.matrix.cross_signing_reset":
50
+ case M.OAUTH:
51
+ case UNSTABLE.ORG.MATRIX.CROSS_SIGNING_RESET:
51
52
  if (!hs.oauth) throw challenge({
52
53
  errcode: "M_UNRECOGNIZED",
53
54
  error: "OAuth is not enabled"
54
55
  });
55
56
  session.completed.add(auth.type);
56
57
  break;
57
- case "m.login.registration_token": {
58
+ case M.LOGIN.REGISTRATION_TOKEN: {
58
59
  const { registrationTokenValid } = await import("./account.js");
59
60
  if (typeof auth.token !== "string" || !await registrationTokenValid(hs, auth.token)) throw challenge({
60
61
  errcode: "M_FORBIDDEN",
61
62
  error: "Invalid registration token"
62
63
  });
63
- session.completed.add("m.login.registration_token");
64
+ session.completed.add(M.LOGIN.REGISTRATION_TOKEN);
64
65
  break;
65
66
  }
66
- case "m.login.password": {
67
+ case M.LOGIN.PASSWORD: {
67
68
  const identifier = isObject(auth.identifier) ? auth.identifier : {
68
- type: "m.id.user",
69
+ type: M.ID.USER,
69
70
  user: auth.user
70
71
  };
71
72
  const user = typeof identifier.user === "string" ? identifier.user : "";
@@ -84,13 +85,13 @@ async function requireUia(hs, body, flows, userId) {
84
85
  errcode: "M_FORBIDDEN",
85
86
  error: "Invalid password"
86
87
  });
87
- session.completed.add("m.login.password");
88
+ session.completed.add(M.LOGIN.PASSWORD);
88
89
  break;
89
90
  }
90
- case "m.login.email.identity":
91
- case "m.login.msisdn": {
91
+ case M.LOGIN.EMAIL.IDENTITY:
92
+ case M.LOGIN.MSISDN: {
92
93
  const validated = await hs.threepids.validated(auth.threepid_creds ?? auth.threepidCreds);
93
- const medium = auth.type === "m.login.email.identity" ? "email" : "msisdn";
94
+ const medium = auth.type === M.LOGIN.EMAIL.IDENTITY ? "email" : "msisdn";
94
95
  if (!validated || validated.medium !== medium) throw challenge({
95
96
  errcode: "M_UNAUTHORIZED",
96
97
  error: "The address has not been validated"