@kodelyth/matrix 2026.5.42 → 2026.6.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 (205) hide show
  1. package/klaw.plugin.json +891 -3
  2. package/package.json +18 -6
  3. package/CHANGELOG.md +0 -321
  4. package/SPEC-SUPPORT.md +0 -116
  5. package/api.ts +0 -38
  6. package/auth-presence.ts +0 -56
  7. package/channel-plugin-api.ts +0 -3
  8. package/cli-metadata.ts +0 -11
  9. package/contract-api.ts +0 -17
  10. package/doctor-contract-api.ts +0 -1
  11. package/helper-api.ts +0 -3
  12. package/index.ts +0 -55
  13. package/plugin-entry.handlers.runtime.ts +0 -1
  14. package/runtime-api.ts +0 -72
  15. package/runtime-heavy-api.ts +0 -1
  16. package/runtime-setter-api.ts +0 -3
  17. package/secret-contract-api.ts +0 -5
  18. package/setup-entry.ts +0 -17
  19. package/setup-plugin-api.ts +0 -3
  20. package/src/account-selection.ts +0 -223
  21. package/src/actions.ts +0 -346
  22. package/src/approval-auth.ts +0 -25
  23. package/src/approval-handler.runtime.ts +0 -592
  24. package/src/approval-ids.ts +0 -6
  25. package/src/approval-native.ts +0 -345
  26. package/src/approval-reaction-auth.ts +0 -45
  27. package/src/approval-reactions.ts +0 -313
  28. package/src/auth-precedence.ts +0 -61
  29. package/src/channel-account-paths.ts +0 -97
  30. package/src/channel.runtime.ts +0 -17
  31. package/src/channel.setup.ts +0 -48
  32. package/src/channel.ts +0 -667
  33. package/src/cli-metadata.ts +0 -19
  34. package/src/cli.ts +0 -2298
  35. package/src/config-adapter.ts +0 -41
  36. package/src/config-schema.ts +0 -159
  37. package/src/config-ui-hints.ts +0 -56
  38. package/src/directory-live.ts +0 -238
  39. package/src/doctor-contract.ts +0 -287
  40. package/src/doctor.ts +0 -262
  41. package/src/env-vars.ts +0 -92
  42. package/src/exec-approval-resolver.ts +0 -23
  43. package/src/exec-approvals.ts +0 -287
  44. package/src/group-mentions.ts +0 -41
  45. package/src/legacy-crypto-inspector-availability.ts +0 -60
  46. package/src/legacy-crypto.ts +0 -531
  47. package/src/legacy-state.ts +0 -156
  48. package/src/matrix/account-config.ts +0 -175
  49. package/src/matrix/accounts.ts +0 -194
  50. package/src/matrix/actions/client.ts +0 -31
  51. package/src/matrix/actions/devices.ts +0 -34
  52. package/src/matrix/actions/limits.ts +0 -6
  53. package/src/matrix/actions/messages.ts +0 -129
  54. package/src/matrix/actions/pins.ts +0 -63
  55. package/src/matrix/actions/polls.ts +0 -109
  56. package/src/matrix/actions/profile.ts +0 -37
  57. package/src/matrix/actions/reactions.ts +0 -59
  58. package/src/matrix/actions/room.ts +0 -71
  59. package/src/matrix/actions/summary.ts +0 -88
  60. package/src/matrix/actions/types.ts +0 -63
  61. package/src/matrix/actions/verification.ts +0 -589
  62. package/src/matrix/actions.ts +0 -37
  63. package/src/matrix/active-client.ts +0 -26
  64. package/src/matrix/async-lock.ts +0 -18
  65. package/src/matrix/backup-health.ts +0 -124
  66. package/src/matrix/client/config-runtime-api.ts +0 -9
  67. package/src/matrix/client/config-secret-input.runtime.ts +0 -1
  68. package/src/matrix/client/config.ts +0 -853
  69. package/src/matrix/client/create-client.ts +0 -105
  70. package/src/matrix/client/env-auth.ts +0 -95
  71. package/src/matrix/client/file-sync-store.ts +0 -289
  72. package/src/matrix/client/logging.ts +0 -140
  73. package/src/matrix/client/migration-snapshot.runtime.ts +0 -1
  74. package/src/matrix/client/private-network-host.ts +0 -1
  75. package/src/matrix/client/runtime.ts +0 -4
  76. package/src/matrix/client/shared.ts +0 -316
  77. package/src/matrix/client/storage.ts +0 -543
  78. package/src/matrix/client/types.ts +0 -50
  79. package/src/matrix/client/url-validation.ts +0 -73
  80. package/src/matrix/client-bootstrap.ts +0 -173
  81. package/src/matrix/client.ts +0 -23
  82. package/src/matrix/config-paths.ts +0 -31
  83. package/src/matrix/config-update.ts +0 -292
  84. package/src/matrix/credentials-read.ts +0 -208
  85. package/src/matrix/credentials-write.runtime.ts +0 -35
  86. package/src/matrix/credentials.ts +0 -95
  87. package/src/matrix/deps.ts +0 -309
  88. package/src/matrix/device-health.ts +0 -29
  89. package/src/matrix/direct-management.ts +0 -349
  90. package/src/matrix/direct-room.ts +0 -128
  91. package/src/matrix/draft-stream.ts +0 -225
  92. package/src/matrix/encryption-guidance.ts +0 -24
  93. package/src/matrix/errors.ts +0 -21
  94. package/src/matrix/format.ts +0 -426
  95. package/src/matrix/legacy-crypto-inspector.ts +0 -95
  96. package/src/matrix/media-errors.ts +0 -20
  97. package/src/matrix/media-text.ts +0 -162
  98. package/src/matrix/monitor/access-state.ts +0 -145
  99. package/src/matrix/monitor/ack-config.ts +0 -27
  100. package/src/matrix/monitor/allowlist.ts +0 -89
  101. package/src/matrix/monitor/auto-join.ts +0 -86
  102. package/src/matrix/monitor/config.ts +0 -569
  103. package/src/matrix/monitor/context-summary.ts +0 -43
  104. package/src/matrix/monitor/direct.ts +0 -296
  105. package/src/matrix/monitor/events.ts +0 -397
  106. package/src/matrix/monitor/handler.ts +0 -2266
  107. package/src/matrix/monitor/inbound-dedupe.ts +0 -267
  108. package/src/matrix/monitor/index.ts +0 -540
  109. package/src/matrix/monitor/legacy-crypto-restore.ts +0 -139
  110. package/src/matrix/monitor/location.ts +0 -108
  111. package/src/matrix/monitor/media.ts +0 -119
  112. package/src/matrix/monitor/mentions.ts +0 -256
  113. package/src/matrix/monitor/reaction-events.ts +0 -197
  114. package/src/matrix/monitor/recent-invite.ts +0 -30
  115. package/src/matrix/monitor/replies.ts +0 -136
  116. package/src/matrix/monitor/reply-context.ts +0 -92
  117. package/src/matrix/monitor/room-history.ts +0 -301
  118. package/src/matrix/monitor/room-info.ts +0 -126
  119. package/src/matrix/monitor/rooms.ts +0 -52
  120. package/src/matrix/monitor/route.ts +0 -179
  121. package/src/matrix/monitor/runtime-api.ts +0 -28
  122. package/src/matrix/monitor/startup-verification.ts +0 -237
  123. package/src/matrix/monitor/startup.ts +0 -218
  124. package/src/matrix/monitor/status.ts +0 -120
  125. package/src/matrix/monitor/sync-lifecycle.ts +0 -91
  126. package/src/matrix/monitor/task-runner.ts +0 -38
  127. package/src/matrix/monitor/test-events.ts +0 -21
  128. package/src/matrix/monitor/thread-context.ts +0 -108
  129. package/src/matrix/monitor/threads.ts +0 -85
  130. package/src/matrix/monitor/types.ts +0 -30
  131. package/src/matrix/monitor/verification-events.ts +0 -643
  132. package/src/matrix/monitor/verification-utils.ts +0 -46
  133. package/src/matrix/outbound-media-runtime.ts +0 -1
  134. package/src/matrix/poll-summary.ts +0 -110
  135. package/src/matrix/poll-types.ts +0 -429
  136. package/src/matrix/probe.runtime.ts +0 -4
  137. package/src/matrix/probe.ts +0 -97
  138. package/src/matrix/profile.ts +0 -184
  139. package/src/matrix/reaction-common.ts +0 -147
  140. package/src/matrix/sdk/crypto-bootstrap.ts +0 -438
  141. package/src/matrix/sdk/crypto-facade.ts +0 -242
  142. package/src/matrix/sdk/crypto-node.runtime.ts +0 -17
  143. package/src/matrix/sdk/crypto-runtime.ts +0 -14
  144. package/src/matrix/sdk/decrypt-bridge.ts +0 -410
  145. package/src/matrix/sdk/event-helpers.ts +0 -83
  146. package/src/matrix/sdk/http-client.ts +0 -87
  147. package/src/matrix/sdk/idb-persistence-lock.ts +0 -51
  148. package/src/matrix/sdk/idb-persistence.ts +0 -288
  149. package/src/matrix/sdk/logger.ts +0 -108
  150. package/src/matrix/sdk/read-response-with-limit.ts +0 -19
  151. package/src/matrix/sdk/recovery-key-store.ts +0 -453
  152. package/src/matrix/sdk/timeout-abort-signal.ts +0 -1
  153. package/src/matrix/sdk/transport-runtime-api.ts +0 -18
  154. package/src/matrix/sdk/transport.ts +0 -352
  155. package/src/matrix/sdk/types.ts +0 -245
  156. package/src/matrix/sdk/verification-manager.ts +0 -795
  157. package/src/matrix/sdk/verification-status.ts +0 -23
  158. package/src/matrix/sdk.ts +0 -2152
  159. package/src/matrix/send/client.ts +0 -93
  160. package/src/matrix/send/formatting.ts +0 -189
  161. package/src/matrix/send/media.ts +0 -244
  162. package/src/matrix/send/targets.ts +0 -104
  163. package/src/matrix/send/types.ts +0 -131
  164. package/src/matrix/send.ts +0 -660
  165. package/src/matrix/session-store-metadata.ts +0 -108
  166. package/src/matrix/startup-abort.ts +0 -44
  167. package/src/matrix/subagent-hooks.ts +0 -308
  168. package/src/matrix/sync-state.ts +0 -27
  169. package/src/matrix/target-ids.ts +0 -79
  170. package/src/matrix/thread-bindings-shared.ts +0 -206
  171. package/src/matrix/thread-bindings.ts +0 -580
  172. package/src/matrix-migration.runtime.ts +0 -9
  173. package/src/migration-config.ts +0 -243
  174. package/src/migration-snapshot-backup.ts +0 -116
  175. package/src/migration-snapshot.ts +0 -53
  176. package/src/onboarding.ts +0 -775
  177. package/src/outbound.ts +0 -248
  178. package/src/plugin-entry.runtime.js +0 -115
  179. package/src/plugin-entry.runtime.ts +0 -70
  180. package/src/profile-update.ts +0 -71
  181. package/src/record-shared.ts +0 -3
  182. package/src/resolve-targets.ts +0 -175
  183. package/src/resolver.runtime.ts +0 -5
  184. package/src/resolver.ts +0 -21
  185. package/src/runtime-api.ts +0 -106
  186. package/src/runtime.ts +0 -13
  187. package/src/secret-contract.ts +0 -174
  188. package/src/session-route.ts +0 -126
  189. package/src/setup-bootstrap.ts +0 -102
  190. package/src/setup-config.ts +0 -222
  191. package/src/setup-contract.ts +0 -90
  192. package/src/setup-core.ts +0 -146
  193. package/src/setup-dm-policy.ts +0 -15
  194. package/src/setup-surface.ts +0 -4
  195. package/src/startup-maintenance.ts +0 -114
  196. package/src/storage-paths.ts +0 -92
  197. package/src/thread-binding-api.ts +0 -23
  198. package/src/tool-actions.runtime.ts +0 -1
  199. package/src/tool-actions.ts +0 -498
  200. package/src/types.ts +0 -257
  201. package/subagent-hooks-api.ts +0 -31
  202. package/test-api.ts +0 -21
  203. package/thread-binding-api.ts +0 -4
  204. package/thread-bindings-runtime.ts +0 -4
  205. package/tsconfig.json +0 -16
@@ -1,853 +0,0 @@
1
- import { formatErrorMessage } from "klaw/plugin-sdk/error-runtime";
2
- import { requireRuntimeConfig } from "klaw/plugin-sdk/plugin-config-runtime";
3
- import { retryAsync } from "klaw/plugin-sdk/retry-runtime";
4
- import {
5
- coerceSecretRef,
6
- normalizeResolvedSecretInputString,
7
- } from "klaw/plugin-sdk/secret-input-runtime";
8
- import type { PinnedDispatcherPolicy } from "klaw/plugin-sdk/ssrf-dispatcher";
9
- import {
10
- requiresExplicitMatrixDefaultAccount,
11
- resolveMatrixDefaultOrOnlyAccountId,
12
- } from "../../account-selection.js";
13
- import { resolveMatrixAccountStringValues } from "../../auth-precedence.js";
14
- import { getMatrixScopedEnvVarNames } from "../../env-vars.js";
15
- import type { CoreConfig } from "../../types.js";
16
- import {
17
- findMatrixAccountConfig,
18
- resolveMatrixBaseConfig,
19
- listNormalizedMatrixAccountIds,
20
- } from "../account-config.js";
21
- import { resolveMatrixConfigFieldPath } from "../config-paths.js";
22
- import type { MatrixStoredCredentials } from "../credentials-read.js";
23
- import {
24
- DEFAULT_ACCOUNT_ID,
25
- isPrivateNetworkOptInEnabled,
26
- normalizeAccountId,
27
- normalizeOptionalAccountId,
28
- ssrfPolicyFromDangerouslyAllowPrivateNetwork,
29
- } from "./config-runtime-api.js";
30
- import { resolveGlobalMatrixEnvConfig, resolveScopedMatrixEnvConfig } from "./env-auth.js";
31
- import { repairCurrentTokenStorageMetaDeviceId } from "./storage.js";
32
- import type { MatrixAuth, MatrixResolvedConfig } from "./types.js";
33
- import { resolveValidatedMatrixHomeserverUrl } from "./url-validation.js";
34
-
35
- type MatrixAuthClientDeps = {
36
- MatrixClient: typeof import("../sdk.js").MatrixClient;
37
- ensureMatrixSdkLoggingConfigured: typeof import("./logging.js").ensureMatrixSdkLoggingConfigured;
38
- retryMinDelayMs?: number;
39
- };
40
-
41
- type MatrixCredentialsReadDeps = {
42
- loadMatrixCredentials: typeof import("../credentials-read.js").loadMatrixCredentials;
43
- credentialsMatchConfig: typeof import("../credentials-read.js").credentialsMatchConfig;
44
- };
45
-
46
- type MatrixCredentialsWriteRuntime = typeof import("../credentials-write.runtime.js");
47
-
48
- type MatrixSecretInputDeps = {
49
- resolveConfiguredSecretInputString: typeof import("./config-secret-input.runtime.js").resolveConfiguredSecretInputString;
50
- };
51
-
52
- let matrixAuthClientDepsPromise: Promise<MatrixAuthClientDeps> | undefined;
53
- let matrixCredentialsReadDepsPromise: Promise<MatrixCredentialsReadDeps> | undefined;
54
- let matrixCredentialsWriteRuntimePromise: Promise<MatrixCredentialsWriteRuntime> | undefined;
55
- let matrixSecretInputDepsPromise: Promise<MatrixSecretInputDeps> | undefined;
56
- let matrixAuthClientDepsForTest: MatrixAuthClientDeps | undefined;
57
-
58
- const MATRIX_AUTH_REQUEST_RETRY_RE =
59
- /\b(fetch failed|econnreset|econnrefused|enotfound|etimedout|ehostunreach|enetunreach|eai_again|und_err_|socket hang up|network|headers timeout|body timeout|connect timeout)\b/i;
60
-
61
- export function setMatrixAuthClientDepsForTest(deps?: {
62
- MatrixClient: typeof import("../sdk.js").MatrixClient;
63
- ensureMatrixSdkLoggingConfigured: typeof import("./logging.js").ensureMatrixSdkLoggingConfigured;
64
- retryMinDelayMs?: number;
65
- }): void {
66
- matrixAuthClientDepsForTest = deps;
67
- }
68
-
69
- async function loadMatrixAuthClientDeps(): Promise<MatrixAuthClientDeps> {
70
- if (matrixAuthClientDepsForTest) {
71
- return matrixAuthClientDepsForTest;
72
- }
73
- matrixAuthClientDepsPromise ??= Promise.all([import("../sdk.js"), import("./logging.js")]).then(
74
- ([sdkModule, loggingModule]) => ({
75
- MatrixClient: sdkModule.MatrixClient,
76
- ensureMatrixSdkLoggingConfigured: loggingModule.ensureMatrixSdkLoggingConfigured,
77
- }),
78
- );
79
- return await matrixAuthClientDepsPromise;
80
- }
81
-
82
- async function loadMatrixCredentialsReadDeps(): Promise<MatrixCredentialsReadDeps> {
83
- matrixCredentialsReadDepsPromise ??= import("../credentials-read.js").then(
84
- (credentialsReadModule) => ({
85
- loadMatrixCredentials: credentialsReadModule.loadMatrixCredentials,
86
- credentialsMatchConfig: credentialsReadModule.credentialsMatchConfig,
87
- }),
88
- );
89
- return await matrixCredentialsReadDepsPromise;
90
- }
91
-
92
- async function loadMatrixCredentialsWriteRuntime(): Promise<MatrixCredentialsWriteRuntime> {
93
- matrixCredentialsWriteRuntimePromise ??= import("../credentials-write.runtime.js");
94
- return await matrixCredentialsWriteRuntimePromise;
95
- }
96
-
97
- async function loadMatrixSecretInputDeps(): Promise<MatrixSecretInputDeps> {
98
- matrixSecretInputDepsPromise ??= import("./config-secret-input.runtime.js").then((runtime) => ({
99
- resolveConfiguredSecretInputString: runtime.resolveConfiguredSecretInputString,
100
- }));
101
- return await matrixSecretInputDepsPromise;
102
- }
103
-
104
- function shouldRetryMatrixAuthRequest(err: unknown): boolean {
105
- return MATRIX_AUTH_REQUEST_RETRY_RE.test(formatErrorMessage(err));
106
- }
107
-
108
- function isAbortSignalTriggered(signal?: AbortSignal): boolean {
109
- return signal?.aborted === true;
110
- }
111
-
112
- function credentialsMatchBackfillAuthLineage(params: {
113
- stored: MatrixStoredCredentials | null;
114
- auth: Pick<MatrixAuth, "homeserver" | "userId" | "accessToken">;
115
- }): boolean {
116
- if (!params.stored) {
117
- return true;
118
- }
119
- return (
120
- params.stored.homeserver === params.auth.homeserver &&
121
- params.stored.userId === params.auth.userId &&
122
- params.stored.accessToken === params.auth.accessToken
123
- );
124
- }
125
-
126
- async function retryMatrixAuthRequest<T>(label: string, run: () => Promise<T>): Promise<T> {
127
- return await retryAsync(run, {
128
- attempts: 3,
129
- minDelayMs: matrixAuthClientDepsForTest?.retryMinDelayMs ?? 250,
130
- maxDelayMs: 1_500,
131
- jitter: 0.1,
132
- label,
133
- shouldRetry: (err) => shouldRetryMatrixAuthRequest(err),
134
- });
135
- }
136
-
137
- async function fetchMatrixWhoamiIdentity(params: {
138
- homeserver: string;
139
- accessToken: string;
140
- userId?: string;
141
- ssrfPolicy?: MatrixResolvedConfig["ssrfPolicy"];
142
- dispatcherPolicy?: PinnedDispatcherPolicy;
143
- }): Promise<{
144
- user_id?: string;
145
- device_id?: string;
146
- }> {
147
- const { MatrixClient, ensureMatrixSdkLoggingConfigured } = await loadMatrixAuthClientDeps();
148
- ensureMatrixSdkLoggingConfigured();
149
- const tempClient = new MatrixClient(params.homeserver, params.accessToken, {
150
- userId: params.userId,
151
- ssrfPolicy: params.ssrfPolicy,
152
- dispatcherPolicy: params.dispatcherPolicy,
153
- });
154
- return (await retryMatrixAuthRequest("matrix auth whoami", async () => {
155
- return (await tempClient.doRequest("GET", "/_matrix/client/v3/account/whoami")) as {
156
- user_id?: string;
157
- device_id?: string;
158
- };
159
- })) as {
160
- user_id?: string;
161
- device_id?: string;
162
- };
163
- }
164
-
165
- function readEnvSecretRefFallback(params: {
166
- value: unknown;
167
- env?: NodeJS.ProcessEnv;
168
- config?: Pick<CoreConfig, "secrets">;
169
- }): string | undefined {
170
- const ref = coerceSecretRef(params.value, params.config?.secrets?.defaults);
171
- if (!ref || ref.source !== "env" || !params.env) {
172
- return undefined;
173
- }
174
-
175
- const providerConfig = params.config?.secrets?.providers?.[ref.provider];
176
- if (providerConfig) {
177
- if (providerConfig.source !== "env") {
178
- throw new Error(
179
- `Secret provider "${ref.provider}" has source "${providerConfig.source}" but ref requests "env".`,
180
- );
181
- }
182
- if (providerConfig.allowlist && !providerConfig.allowlist.includes(ref.id)) {
183
- throw new Error(
184
- `Environment variable "${ref.id}" is not allowlisted in secrets.providers.${ref.provider}.allowlist.`,
185
- );
186
- }
187
- } else if (ref.provider !== (params.config?.secrets?.defaults?.env?.trim() || "default")) {
188
- throw new Error(
189
- `Secret provider "${ref.provider}" is not configured (ref: ${ref.source}:${ref.provider}:${ref.id}).`,
190
- );
191
- }
192
-
193
- const resolved = params.env[ref.id];
194
- if (typeof resolved !== "string") {
195
- return undefined;
196
- }
197
-
198
- const trimmed = resolved.trim();
199
- return trimmed.length > 0 ? trimmed : undefined;
200
- }
201
-
202
- function clean(
203
- value: unknown,
204
- path: string,
205
- opts?: {
206
- env?: NodeJS.ProcessEnv;
207
- config?: Pick<CoreConfig, "secrets">;
208
- allowEnvSecretRefFallback?: boolean;
209
- suppressSecretRef?: boolean;
210
- },
211
- ): string {
212
- const ref = coerceSecretRef(value, opts?.config?.secrets?.defaults);
213
- if (opts?.suppressSecretRef && ref) {
214
- return "";
215
- }
216
- const normalizedValue = opts?.allowEnvSecretRefFallback
217
- ? ref?.source === "env"
218
- ? (readEnvSecretRefFallback({
219
- value,
220
- env: opts.env,
221
- config: opts.config,
222
- }) ?? value)
223
- : ref
224
- ? ""
225
- : value
226
- : value;
227
- return (
228
- normalizeResolvedSecretInputString({
229
- value: normalizedValue,
230
- path,
231
- defaults: opts?.config?.secrets?.defaults,
232
- }) ?? ""
233
- );
234
- }
235
-
236
- type MatrixConfigStringField =
237
- | "homeserver"
238
- | "userId"
239
- | "accessToken"
240
- | "password"
241
- | "deviceId"
242
- | "deviceName";
243
-
244
- function resolveMatrixBaseConfigFieldPath(field: MatrixConfigStringField): string {
245
- return `channels.matrix.${field}`;
246
- }
247
-
248
- function shouldAllowEnvSecretRefFallback(field: MatrixConfigStringField): boolean {
249
- return field === "accessToken" || field === "password";
250
- }
251
-
252
- type MatrixAuthSecretField = "accessToken" | "password";
253
-
254
- type MatrixConfiguredAuthInput = {
255
- value: unknown;
256
- path: string;
257
- };
258
-
259
- function hasConfiguredSecretInputValue(value: unknown, cfg: Pick<CoreConfig, "secrets">): boolean {
260
- return (
261
- (typeof value === "string" && value.trim().length > 0) ||
262
- Boolean(coerceSecretRef(value, cfg.secrets?.defaults))
263
- );
264
- }
265
-
266
- function hasConfiguredMatrixAccessTokenSource(params: {
267
- cfg: CoreConfig;
268
- env: NodeJS.ProcessEnv;
269
- accountId: string;
270
- }): boolean {
271
- const normalizedAccountId = normalizeAccountId(params.accountId);
272
- const account = findMatrixAccountConfig(params.cfg, normalizedAccountId) ?? {};
273
- const scopedAccessTokenVar = getMatrixScopedEnvVarNames(normalizedAccountId).accessToken;
274
- if (
275
- hasConfiguredSecretInputValue(account.accessToken, params.cfg) ||
276
- clean(params.env[scopedAccessTokenVar], scopedAccessTokenVar).length > 0
277
- ) {
278
- return true;
279
- }
280
- if (normalizedAccountId !== DEFAULT_ACCOUNT_ID) {
281
- return false;
282
- }
283
- const matrix = resolveMatrixBaseConfig(params.cfg);
284
- return (
285
- hasConfiguredSecretInputValue(matrix.accessToken, params.cfg) ||
286
- clean(params.env.MATRIX_ACCESS_TOKEN, "MATRIX_ACCESS_TOKEN").length > 0
287
- );
288
- }
289
-
290
- function resolveConfiguredMatrixAuthInput(params: {
291
- cfg: CoreConfig;
292
- env: NodeJS.ProcessEnv;
293
- accountId: string;
294
- field: MatrixAuthSecretField;
295
- }): MatrixConfiguredAuthInput | undefined {
296
- const normalizedAccountId = normalizeAccountId(params.accountId);
297
- const account = findMatrixAccountConfig(params.cfg, normalizedAccountId) ?? {};
298
- const accountValue = account[params.field];
299
- if (accountValue !== undefined) {
300
- return {
301
- value: accountValue,
302
- path: resolveMatrixConfigFieldPath(params.cfg, normalizedAccountId, params.field),
303
- };
304
- }
305
-
306
- const scopedKeys = getMatrixScopedEnvVarNames(normalizedAccountId);
307
- const scopedEnv = resolveScopedMatrixEnvConfig(normalizedAccountId, params.env);
308
- const scopedValue = scopedEnv[params.field];
309
- if (scopedValue !== undefined) {
310
- return {
311
- value: scopedValue,
312
- path: params.field === "accessToken" ? scopedKeys.accessToken : scopedKeys.password,
313
- };
314
- }
315
-
316
- if (normalizedAccountId !== DEFAULT_ACCOUNT_ID) {
317
- return undefined;
318
- }
319
-
320
- const matrix = resolveMatrixBaseConfig(params.cfg);
321
- const baseValue = matrix[params.field];
322
- if (baseValue !== undefined) {
323
- return {
324
- value: baseValue,
325
- path: resolveMatrixBaseConfigFieldPath(params.field),
326
- };
327
- }
328
-
329
- const globalValue =
330
- params.field === "accessToken" ? params.env.MATRIX_ACCESS_TOKEN : params.env.MATRIX_PASSWORD;
331
- if (globalValue !== undefined) {
332
- return {
333
- value: globalValue,
334
- path: params.field === "accessToken" ? "MATRIX_ACCESS_TOKEN" : "MATRIX_PASSWORD",
335
- };
336
- }
337
-
338
- return undefined;
339
- }
340
-
341
- async function resolveConfiguredMatrixAuthSecretInput(params: {
342
- cfg: CoreConfig;
343
- env: NodeJS.ProcessEnv;
344
- accountId: string;
345
- field: MatrixAuthSecretField;
346
- }): Promise<string | undefined> {
347
- const configured = resolveConfiguredMatrixAuthInput(params);
348
- if (!configured) {
349
- return undefined;
350
- }
351
-
352
- const ref = coerceSecretRef(configured.value, params.cfg.secrets?.defaults);
353
- if (!ref) {
354
- return normalizeResolvedSecretInputString({
355
- value: configured.value,
356
- path: configured.path,
357
- defaults: params.cfg.secrets?.defaults,
358
- });
359
- }
360
-
361
- const { resolveConfiguredSecretInputString } = await loadMatrixSecretInputDeps();
362
- const resolved = await resolveConfiguredSecretInputString({
363
- config: params.cfg,
364
- env: params.env,
365
- value: configured.value,
366
- path: configured.path,
367
- unresolvedReasonStyle: "detailed",
368
- });
369
- if (resolved.value !== undefined) {
370
- return resolved.value;
371
- }
372
-
373
- throw new Error(
374
- resolved.unresolvedRefReason ?? `${configured.path} SecretRef could not be resolved.`,
375
- );
376
- }
377
-
378
- function readMatrixBaseConfigField(
379
- matrix: ReturnType<typeof resolveMatrixBaseConfig>,
380
- field: MatrixConfigStringField,
381
- opts?: {
382
- env?: NodeJS.ProcessEnv;
383
- config?: Pick<CoreConfig, "secrets">;
384
- suppressSecretRef?: boolean;
385
- },
386
- ): string {
387
- return clean(matrix[field], resolveMatrixBaseConfigFieldPath(field), {
388
- env: opts?.env,
389
- config: opts?.config,
390
- allowEnvSecretRefFallback: shouldAllowEnvSecretRefFallback(field),
391
- suppressSecretRef: opts?.suppressSecretRef,
392
- });
393
- }
394
-
395
- function readMatrixAccountConfigField(
396
- cfg: CoreConfig,
397
- accountId: string,
398
- account: Partial<Record<MatrixConfigStringField, unknown>>,
399
- field: MatrixConfigStringField,
400
- opts?: {
401
- env?: NodeJS.ProcessEnv;
402
- config?: Pick<CoreConfig, "secrets">;
403
- suppressSecretRef?: boolean;
404
- },
405
- ): string {
406
- return clean(account[field], resolveMatrixConfigFieldPath(cfg, accountId, field), {
407
- env: opts?.env,
408
- config: opts?.config,
409
- allowEnvSecretRefFallback: shouldAllowEnvSecretRefFallback(field),
410
- suppressSecretRef: opts?.suppressSecretRef,
411
- });
412
- }
413
-
414
- function clampMatrixInitialSyncLimit(value: unknown): number | undefined {
415
- return typeof value === "number" ? Math.max(0, Math.floor(value)) : undefined;
416
- }
417
-
418
- function buildMatrixNetworkFields(params: {
419
- allowPrivateNetwork: boolean | undefined;
420
- proxy?: string;
421
- dispatcherPolicy?: PinnedDispatcherPolicy;
422
- }): Pick<MatrixResolvedConfig, "allowPrivateNetwork" | "ssrfPolicy" | "dispatcherPolicy"> {
423
- const dispatcherPolicy: PinnedDispatcherPolicy | undefined =
424
- params.dispatcherPolicy ??
425
- (params.proxy ? { mode: "explicit-proxy", proxyUrl: params.proxy } : undefined);
426
- if (!params.allowPrivateNetwork && !dispatcherPolicy) {
427
- return {};
428
- }
429
- return {
430
- ...(params.allowPrivateNetwork
431
- ? {
432
- allowPrivateNetwork: true,
433
- ssrfPolicy: ssrfPolicyFromDangerouslyAllowPrivateNetwork(true),
434
- }
435
- : {}),
436
- ...(dispatcherPolicy ? { dispatcherPolicy } : {}),
437
- };
438
- }
439
-
440
- export { getMatrixScopedEnvVarNames } from "../../env-vars.js";
441
- export {
442
- hasReadyMatrixEnvAuth,
443
- resolveMatrixEnvAuthReadiness,
444
- resolveScopedMatrixEnvConfig,
445
- } from "./env-auth.js";
446
- export {
447
- resolveValidatedMatrixHomeserverUrl,
448
- validateMatrixHomeserverUrl,
449
- } from "./url-validation.js";
450
-
451
- function hasScopedMatrixEnvConfig(accountId: string, env: NodeJS.ProcessEnv): boolean {
452
- const scoped = resolveScopedMatrixEnvConfig(accountId, env);
453
- return Boolean(
454
- scoped.homeserver ||
455
- scoped.userId ||
456
- scoped.accessToken ||
457
- scoped.password ||
458
- scoped.deviceId ||
459
- scoped.deviceName,
460
- );
461
- }
462
-
463
- export function resolveMatrixConfigForAccount(
464
- cfg: CoreConfig,
465
- accountId: string,
466
- env: NodeJS.ProcessEnv = process.env,
467
- ): MatrixResolvedConfig {
468
- const matrix = resolveMatrixBaseConfig(cfg);
469
- const account = findMatrixAccountConfig(cfg, accountId) ?? {};
470
- const normalizedAccountId = normalizeAccountId(accountId);
471
- const suppressInactivePasswordSecretRef = hasConfiguredMatrixAccessTokenSource({
472
- cfg,
473
- env,
474
- accountId: normalizedAccountId,
475
- });
476
- const fieldReadOptions = {
477
- env,
478
- config: cfg,
479
- };
480
- const scopedEnv = resolveScopedMatrixEnvConfig(normalizedAccountId, env);
481
- const globalEnv = resolveGlobalMatrixEnvConfig(env);
482
- const accountField = (field: MatrixConfigStringField) =>
483
- readMatrixAccountConfigField(cfg, normalizedAccountId, account, field, {
484
- ...fieldReadOptions,
485
- suppressSecretRef: field === "password" ? suppressInactivePasswordSecretRef : undefined,
486
- });
487
- const resolvedStrings = resolveMatrixAccountStringValues({
488
- accountId: normalizedAccountId,
489
- account: {
490
- homeserver: accountField("homeserver"),
491
- userId: accountField("userId"),
492
- accessToken: accountField("accessToken"),
493
- password: accountField("password"),
494
- deviceId: accountField("deviceId"),
495
- deviceName: accountField("deviceName"),
496
- },
497
- scopedEnv,
498
- channel: {
499
- homeserver: readMatrixBaseConfigField(matrix, "homeserver", fieldReadOptions),
500
- userId: readMatrixBaseConfigField(matrix, "userId", fieldReadOptions),
501
- accessToken: readMatrixBaseConfigField(matrix, "accessToken", fieldReadOptions),
502
- password: readMatrixBaseConfigField(matrix, "password", {
503
- ...fieldReadOptions,
504
- suppressSecretRef: suppressInactivePasswordSecretRef,
505
- }),
506
- deviceId: readMatrixBaseConfigField(matrix, "deviceId", fieldReadOptions),
507
- deviceName: readMatrixBaseConfigField(matrix, "deviceName", fieldReadOptions),
508
- },
509
- globalEnv,
510
- });
511
-
512
- const accountInitialSyncLimit = clampMatrixInitialSyncLimit(account.initialSyncLimit);
513
- const initialSyncLimit =
514
- accountInitialSyncLimit ?? clampMatrixInitialSyncLimit(matrix.initialSyncLimit);
515
- const encryption =
516
- typeof account.encryption === "boolean" ? account.encryption : (matrix.encryption ?? false);
517
- const allowPrivateNetwork =
518
- isPrivateNetworkOptInEnabled(account) || isPrivateNetworkOptInEnabled(matrix)
519
- ? true
520
- : undefined;
521
-
522
- return {
523
- homeserver: resolvedStrings.homeserver,
524
- userId: resolvedStrings.userId,
525
- accessToken: resolvedStrings.accessToken || undefined,
526
- password: resolvedStrings.password || undefined,
527
- deviceId: resolvedStrings.deviceId || undefined,
528
- deviceName: resolvedStrings.deviceName || undefined,
529
- initialSyncLimit,
530
- encryption,
531
- ...buildMatrixNetworkFields({
532
- allowPrivateNetwork,
533
- proxy: account.proxy ?? matrix.proxy,
534
- }),
535
- };
536
- }
537
-
538
- function resolveImplicitMatrixAccountId(
539
- cfg: CoreConfig,
540
- env: NodeJS.ProcessEnv = process.env,
541
- ): string | null {
542
- if (requiresExplicitMatrixDefaultAccount(cfg, env)) {
543
- return null;
544
- }
545
- return normalizeAccountId(resolveMatrixDefaultOrOnlyAccountId(cfg, env));
546
- }
547
-
548
- export function resolveMatrixAuthContext(params: {
549
- cfg: CoreConfig;
550
- env?: NodeJS.ProcessEnv;
551
- accountId?: string | null;
552
- }): {
553
- cfg: CoreConfig;
554
- env: NodeJS.ProcessEnv;
555
- accountId: string;
556
- resolved: MatrixResolvedConfig;
557
- } {
558
- const cfg = requireRuntimeConfig(params.cfg, "Matrix auth context") as CoreConfig;
559
- const env = params?.env ?? process.env;
560
- const explicitAccountId = normalizeOptionalAccountId(params?.accountId);
561
- const effectiveAccountId = explicitAccountId ?? resolveImplicitMatrixAccountId(cfg, env);
562
- if (!effectiveAccountId) {
563
- throw new Error(
564
- 'Multiple Matrix accounts are configured and channels.matrix.defaultAccount is not set. Set "channels.matrix.defaultAccount" to the intended account or pass --account <id>.',
565
- );
566
- }
567
- if (
568
- explicitAccountId &&
569
- explicitAccountId !== DEFAULT_ACCOUNT_ID &&
570
- !listNormalizedMatrixAccountIds(cfg).includes(explicitAccountId) &&
571
- !hasScopedMatrixEnvConfig(explicitAccountId, env)
572
- ) {
573
- throw new Error(
574
- `Matrix account "${explicitAccountId}" is not configured. Add channels.matrix.accounts.${explicitAccountId} or define scoped ${getMatrixScopedEnvVarNames(explicitAccountId).accessToken.replace(/_ACCESS_TOKEN$/, "")}_* variables.`,
575
- );
576
- }
577
- const resolved = resolveMatrixConfigForAccount(cfg, effectiveAccountId, env);
578
-
579
- return {
580
- cfg,
581
- env,
582
- accountId: effectiveAccountId,
583
- resolved,
584
- };
585
- }
586
-
587
- export async function resolveMatrixAuth(params?: {
588
- cfg?: CoreConfig;
589
- env?: NodeJS.ProcessEnv;
590
- accountId?: string | null;
591
- }): Promise<MatrixAuth> {
592
- if (!params?.cfg) {
593
- throw new Error(
594
- "Matrix auth requires a resolved runtime config. Load and resolve config at the command or gateway boundary, then pass cfg through the runtime path.",
595
- );
596
- }
597
- const { cfg, env, accountId, resolved } = resolveMatrixAuthContext({
598
- cfg: params.cfg,
599
- env: params.env,
600
- accountId: params.accountId,
601
- });
602
- const accessToken =
603
- (await resolveConfiguredMatrixAuthSecretInput({
604
- cfg,
605
- env,
606
- accountId,
607
- field: "accessToken",
608
- })) ?? resolved.accessToken;
609
- const tokenAuthPassword = resolved.password;
610
- const homeserver = await resolveValidatedMatrixHomeserverUrl(resolved.homeserver, {
611
- dangerouslyAllowPrivateNetwork: resolved.allowPrivateNetwork,
612
- });
613
- const { loadMatrixCredentials, credentialsMatchConfig } = await loadMatrixCredentialsReadDeps();
614
- const cached = loadMatrixCredentials(env, accountId);
615
- const cachedCredentials =
616
- cached &&
617
- credentialsMatchConfig(cached, {
618
- homeserver,
619
- userId: resolved.userId || "",
620
- accessToken,
621
- })
622
- ? cached
623
- : null;
624
-
625
- // If we have an access token, we can fetch userId via whoami if not provided
626
- if (accessToken) {
627
- let userId = resolved.userId;
628
- const hasMatchingCachedToken = cachedCredentials?.accessToken === accessToken;
629
- let knownDeviceId = hasMatchingCachedToken
630
- ? cachedCredentials?.deviceId || resolved.deviceId
631
- : resolved.deviceId;
632
-
633
- if (!userId) {
634
- // Only block startup on whoami when token auth still needs the user ID.
635
- // A missing device ID alone is optional and should not force a network round-trip.
636
- const whoami = await fetchMatrixWhoamiIdentity({
637
- homeserver,
638
- accessToken,
639
- userId,
640
- ssrfPolicy: resolved.ssrfPolicy,
641
- dispatcherPolicy: resolved.dispatcherPolicy,
642
- });
643
- const fetchedUserId = whoami.user_id?.trim();
644
- if (!fetchedUserId) {
645
- throw new Error("Matrix whoami did not return user_id");
646
- }
647
- userId = fetchedUserId;
648
- knownDeviceId = knownDeviceId || whoami.device_id?.trim() || resolved.deviceId;
649
- }
650
-
651
- const shouldRefreshCachedCredentials =
652
- !cachedCredentials ||
653
- !hasMatchingCachedToken ||
654
- cachedCredentials.userId !== userId ||
655
- (cachedCredentials.deviceId || undefined) !== knownDeviceId;
656
- if (shouldRefreshCachedCredentials) {
657
- const { saveMatrixCredentials } = await loadMatrixCredentialsWriteRuntime();
658
- await saveMatrixCredentials(
659
- {
660
- homeserver,
661
- userId,
662
- accessToken,
663
- deviceId: knownDeviceId,
664
- },
665
- env,
666
- accountId,
667
- );
668
- } else if (hasMatchingCachedToken) {
669
- const { touchMatrixCredentials } = await loadMatrixCredentialsWriteRuntime();
670
- await touchMatrixCredentials(env, accountId);
671
- }
672
- return {
673
- accountId,
674
- homeserver,
675
- userId,
676
- accessToken,
677
- password: tokenAuthPassword,
678
- deviceId: knownDeviceId,
679
- deviceName: resolved.deviceName,
680
- initialSyncLimit: resolved.initialSyncLimit,
681
- encryption: resolved.encryption,
682
- ...buildMatrixNetworkFields({
683
- allowPrivateNetwork: resolved.allowPrivateNetwork,
684
- dispatcherPolicy: resolved.dispatcherPolicy,
685
- }),
686
- };
687
- }
688
-
689
- if (cachedCredentials) {
690
- const { touchMatrixCredentials } = await loadMatrixCredentialsWriteRuntime();
691
- await touchMatrixCredentials(env, accountId);
692
- return {
693
- accountId,
694
- homeserver: cachedCredentials.homeserver,
695
- userId: cachedCredentials.userId,
696
- accessToken: cachedCredentials.accessToken,
697
- password: tokenAuthPassword,
698
- deviceId: cachedCredentials.deviceId || resolved.deviceId,
699
- deviceName: resolved.deviceName,
700
- initialSyncLimit: resolved.initialSyncLimit,
701
- encryption: resolved.encryption,
702
- ...buildMatrixNetworkFields({
703
- allowPrivateNetwork: resolved.allowPrivateNetwork,
704
- dispatcherPolicy: resolved.dispatcherPolicy,
705
- }),
706
- };
707
- }
708
-
709
- if (!resolved.userId) {
710
- throw new Error("Matrix userId is required when no access token is configured (matrix.userId)");
711
- }
712
-
713
- const password =
714
- (await resolveConfiguredMatrixAuthSecretInput({
715
- cfg,
716
- env,
717
- accountId,
718
- field: "password",
719
- })) ?? resolved.password;
720
- if (!password) {
721
- throw new Error(
722
- "Matrix password is required when no access token is configured (matrix.password)",
723
- );
724
- }
725
-
726
- // Login with password using the same hardened request path as other Matrix HTTP calls.
727
- const { MatrixClient, ensureMatrixSdkLoggingConfigured } = await loadMatrixAuthClientDeps();
728
- ensureMatrixSdkLoggingConfigured();
729
- const loginClient = new MatrixClient(homeserver, "", {
730
- ssrfPolicy: resolved.ssrfPolicy,
731
- dispatcherPolicy: resolved.dispatcherPolicy,
732
- });
733
- const login = (await retryMatrixAuthRequest("matrix auth login", async () => {
734
- return (await loginClient.doRequest("POST", "/_matrix/client/v3/login", undefined, {
735
- type: "m.login.password",
736
- identifier: { type: "m.id.user", user: resolved.userId },
737
- password,
738
- device_id: resolved.deviceId,
739
- initial_device_display_name: resolved.deviceName ?? "Klaw Gateway",
740
- })) as {
741
- access_token?: string;
742
- user_id?: string;
743
- device_id?: string;
744
- };
745
- })) as {
746
- access_token?: string;
747
- user_id?: string;
748
- device_id?: string;
749
- };
750
-
751
- const loginAccessToken = login.access_token?.trim();
752
- if (!loginAccessToken) {
753
- throw new Error("Matrix login did not return an access token");
754
- }
755
-
756
- const auth: MatrixAuth = {
757
- accountId,
758
- homeserver,
759
- userId: login.user_id ?? resolved.userId,
760
- accessToken: loginAccessToken,
761
- password,
762
- deviceId: login.device_id ?? resolved.deviceId,
763
- deviceName: resolved.deviceName,
764
- initialSyncLimit: resolved.initialSyncLimit,
765
- encryption: resolved.encryption,
766
- ...buildMatrixNetworkFields({
767
- allowPrivateNetwork: resolved.allowPrivateNetwork,
768
- dispatcherPolicy: resolved.dispatcherPolicy,
769
- }),
770
- };
771
-
772
- const { saveMatrixCredentials } = await loadMatrixCredentialsWriteRuntime();
773
- await saveMatrixCredentials(
774
- {
775
- homeserver: auth.homeserver,
776
- userId: auth.userId,
777
- accessToken: auth.accessToken,
778
- deviceId: auth.deviceId,
779
- },
780
- env,
781
- accountId,
782
- );
783
-
784
- return auth;
785
- }
786
-
787
- export async function backfillMatrixAuthDeviceIdAfterStartup(params: {
788
- auth: MatrixAuth;
789
- env?: NodeJS.ProcessEnv;
790
- abortSignal?: AbortSignal;
791
- }): Promise<string | undefined> {
792
- const knownDeviceId = params.auth.deviceId?.trim();
793
- if (knownDeviceId) {
794
- return knownDeviceId;
795
- }
796
- if (isAbortSignalTriggered(params.abortSignal)) {
797
- return undefined;
798
- }
799
-
800
- const whoami = await fetchMatrixWhoamiIdentity({
801
- homeserver: params.auth.homeserver,
802
- accessToken: params.auth.accessToken,
803
- userId: params.auth.userId,
804
- ssrfPolicy: params.auth.ssrfPolicy,
805
- dispatcherPolicy: params.auth.dispatcherPolicy,
806
- });
807
- const deviceId = whoami.device_id?.trim();
808
- if (!deviceId) {
809
- return undefined;
810
- }
811
- if (isAbortSignalTriggered(params.abortSignal)) {
812
- return undefined;
813
- }
814
-
815
- const env = params.env ?? process.env;
816
- const { loadMatrixCredentials } = await loadMatrixCredentialsReadDeps();
817
- if (
818
- !credentialsMatchBackfillAuthLineage({
819
- stored: loadMatrixCredentials(env, params.auth.accountId),
820
- auth: params.auth,
821
- })
822
- ) {
823
- return undefined;
824
- }
825
-
826
- const repairedStorageMeta = repairCurrentTokenStorageMetaDeviceId({
827
- homeserver: params.auth.homeserver,
828
- userId: params.auth.userId,
829
- accessToken: params.auth.accessToken,
830
- accountId: params.auth.accountId,
831
- deviceId,
832
- env: params.env,
833
- });
834
- if (!repairedStorageMeta) {
835
- throw new Error("Matrix deviceId backfill failed to repair current-token storage metadata");
836
- }
837
- if (isAbortSignalTriggered(params.abortSignal)) {
838
- return undefined;
839
- }
840
-
841
- const credentialsWriter = await loadMatrixCredentialsWriteRuntime();
842
- const saved = await credentialsWriter.saveBackfilledMatrixDeviceId(
843
- {
844
- homeserver: params.auth.homeserver,
845
- userId: params.auth.userId,
846
- accessToken: params.auth.accessToken,
847
- deviceId,
848
- },
849
- env,
850
- params.auth.accountId,
851
- );
852
- return saved === "saved" ? deviceId : undefined;
853
- }