matrix-js-sdk 41.9.0 → 42.0.0

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 (240) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/lib/@types/auth.d.ts +0 -5
  3. package/lib/@types/auth.d.ts.map +1 -1
  4. package/lib/@types/auth.js +0 -6
  5. package/lib/@types/auth.js.map +1 -1
  6. package/lib/@types/type-guards.d.ts +43 -0
  7. package/lib/@types/type-guards.d.ts.map +1 -0
  8. package/lib/@types/type-guards.js +104 -0
  9. package/lib/@types/type-guards.js.map +1 -0
  10. package/lib/NamespacedValue.d.ts.map +1 -1
  11. package/lib/ReEmitter.d.ts.map +1 -1
  12. package/lib/ToDeviceMessageQueue.d.ts.map +1 -1
  13. package/lib/autodiscovery.d.ts.map +1 -1
  14. package/lib/capabilityPoller.d.ts.map +1 -1
  15. package/lib/client.d.ts +4 -7
  16. package/lib/client.d.ts.map +1 -1
  17. package/lib/client.js +10 -22
  18. package/lib/client.js.map +1 -1
  19. package/lib/common-crypto/CryptoBackend.d.ts.map +1 -1
  20. package/lib/content-helpers.d.ts.map +1 -1
  21. package/lib/crypto/store/indexeddb-crypto-store-backend.d.ts.map +1 -1
  22. package/lib/crypto/store/indexeddb-crypto-store.d.ts.map +1 -1
  23. package/lib/crypto/store/localStorage-crypto-store.d.ts.map +1 -1
  24. package/lib/crypto/store/memory-crypto-store.d.ts.map +1 -1
  25. package/lib/crypto-api/index.d.ts +1 -1
  26. package/lib/crypto-api/index.d.ts.map +1 -1
  27. package/lib/crypto-api/index.js.map +1 -1
  28. package/lib/crypto-api/verification.d.ts +23 -5
  29. package/lib/crypto-api/verification.d.ts.map +1 -1
  30. package/lib/crypto-api/verification.js.map +1 -1
  31. package/lib/embedded.d.ts.map +1 -1
  32. package/lib/errors.d.ts.map +1 -1
  33. package/lib/extensible_events_v1/ExtensibleEvent.d.ts.map +1 -1
  34. package/lib/extensible_events_v1/InvalidEventError.d.ts.map +1 -1
  35. package/lib/extensible_events_v1/MessageEvent.d.ts.map +1 -1
  36. package/lib/extensible_events_v1/PollEndEvent.d.ts.map +1 -1
  37. package/lib/extensible_events_v1/PollResponseEvent.d.ts.map +1 -1
  38. package/lib/extensible_events_v1/PollStartEvent.d.ts.map +1 -1
  39. package/lib/filter-component.d.ts.map +1 -1
  40. package/lib/filter.d.ts.map +1 -1
  41. package/lib/http-api/errors.d.ts.map +1 -1
  42. package/lib/http-api/fetch.d.ts +1 -1
  43. package/lib/http-api/fetch.d.ts.map +1 -1
  44. package/lib/http-api/fetch.js.map +1 -1
  45. package/lib/http-api/index.d.ts +1 -7
  46. package/lib/http-api/index.d.ts.map +1 -1
  47. package/lib/http-api/index.js +0 -15
  48. package/lib/http-api/index.js.map +1 -1
  49. package/lib/http-api/interface.d.ts +0 -9
  50. package/lib/http-api/interface.d.ts.map +1 -1
  51. package/lib/http-api/interface.js +0 -2
  52. package/lib/http-api/interface.js.map +1 -1
  53. package/lib/http-api/refresh.d.ts.map +1 -1
  54. package/lib/index.d.ts.map +1 -1
  55. package/lib/interactive-auth.d.ts.map +1 -1
  56. package/lib/logger.d.ts.map +1 -1
  57. package/lib/matrix.d.ts +1 -1
  58. package/lib/matrix.d.ts.map +1 -1
  59. package/lib/matrix.js +1 -1
  60. package/lib/matrix.js.map +1 -1
  61. package/lib/matrixrtc/CallMembership.d.ts.map +1 -1
  62. package/lib/matrixrtc/LivekitTransport.d.ts.map +1 -1
  63. package/lib/matrixrtc/MatrixRTCSession.d.ts.map +1 -1
  64. package/lib/matrixrtc/MatrixRTCSessionManager.d.ts.map +1 -1
  65. package/lib/matrixrtc/MembershipManager.d.ts.map +1 -1
  66. package/lib/matrixrtc/MembershipManagerActionScheduler.d.ts.map +1 -1
  67. package/lib/matrixrtc/RTCEncryptionManager.d.ts.map +1 -1
  68. package/lib/matrixrtc/ToDeviceKeyTransport.d.ts.map +1 -1
  69. package/lib/matrixrtc/membershipData/common.d.ts.map +1 -1
  70. package/lib/matrixrtc/membershipData/rtc.d.ts.map +1 -1
  71. package/lib/matrixrtc/membershipData/session.d.ts.map +1 -1
  72. package/lib/matrixrtc/types.d.ts.map +1 -1
  73. package/lib/matrixrtc/utils.d.ts.map +1 -1
  74. package/lib/models/MSC3089Branch.d.ts.map +1 -1
  75. package/lib/models/MSC3089TreeSpace.d.ts.map +1 -1
  76. package/lib/models/beacon.d.ts.map +1 -1
  77. package/lib/models/device.d.ts.map +1 -1
  78. package/lib/models/event-context.d.ts.map +1 -1
  79. package/lib/models/event-timeline-set.d.ts.map +1 -1
  80. package/lib/models/event-timeline.d.ts.map +1 -1
  81. package/lib/models/event.d.ts.map +1 -1
  82. package/lib/models/invites-ignorer.d.ts.map +1 -1
  83. package/lib/models/poll.d.ts.map +1 -1
  84. package/lib/models/read-receipt.d.ts.map +1 -1
  85. package/lib/models/related-relations.d.ts.map +1 -1
  86. package/lib/models/relations-container.d.ts.map +1 -1
  87. package/lib/models/relations.d.ts.map +1 -1
  88. package/lib/models/room-member.d.ts.map +1 -1
  89. package/lib/models/room-receipts.d.ts.map +1 -1
  90. package/lib/models/room-retention.d.ts.map +1 -1
  91. package/lib/models/room-state.d.ts.map +1 -1
  92. package/lib/models/room-sticky-events.d.ts.map +1 -1
  93. package/lib/models/room-summary.d.ts.map +1 -1
  94. package/lib/models/room.d.ts.map +1 -1
  95. package/lib/models/search-result.d.ts.map +1 -1
  96. package/lib/models/thread.d.ts.map +1 -1
  97. package/lib/models/typed-event-emitter.d.ts.map +1 -1
  98. package/lib/models/user.d.ts.map +1 -1
  99. package/lib/oauth/authorize.d.ts +133 -0
  100. package/lib/oauth/authorize.d.ts.map +1 -0
  101. package/lib/oauth/authorize.js +193 -0
  102. package/lib/oauth/authorize.js.map +1 -0
  103. package/lib/oauth/discover.d.ts +58 -0
  104. package/lib/oauth/discover.d.ts.map +1 -0
  105. package/lib/oauth/discover.js +35 -0
  106. package/lib/oauth/discover.js.map +1 -0
  107. package/lib/oauth/error.d.ts +19 -0
  108. package/lib/oauth/error.d.ts.map +1 -0
  109. package/lib/oauth/error.js +36 -0
  110. package/lib/oauth/error.js.map +1 -0
  111. package/lib/oauth/index.d.ts +87 -0
  112. package/lib/oauth/index.d.ts.map +1 -0
  113. package/lib/oauth/index.js +234 -0
  114. package/lib/oauth/index.js.map +1 -0
  115. package/lib/oauth/register.d.ts +136 -0
  116. package/lib/oauth/register.d.ts.map +1 -0
  117. package/lib/oauth/register.js +73 -0
  118. package/lib/oauth/register.js.map +1 -0
  119. package/lib/oauth/tokenRefresher.d.ts +21 -0
  120. package/lib/oauth/tokenRefresher.d.ts.map +1 -0
  121. package/lib/oauth/tokenRefresher.js +68 -0
  122. package/lib/oauth/tokenRefresher.js.map +1 -0
  123. package/lib/pushprocessor.d.ts.map +1 -1
  124. package/lib/receipt-accumulator.d.ts.map +1 -1
  125. package/lib/rendezvous/MSC4108SignInWithQR.d.ts +7 -7
  126. package/lib/rendezvous/MSC4108SignInWithQR.d.ts.map +1 -1
  127. package/lib/rendezvous/MSC4108SignInWithQR.js +11 -11
  128. package/lib/rendezvous/MSC4108SignInWithQR.js.map +1 -1
  129. package/lib/rendezvous/RendezvousError.d.ts.map +1 -1
  130. package/lib/rendezvous/channels/MSC4108SecureChannel.d.ts.map +1 -1
  131. package/lib/rendezvous/index.d.ts.map +1 -1
  132. package/lib/rendezvous/index.js.map +1 -1
  133. package/lib/rendezvous/transports/MSC4108RendezvousSession.d.ts.map +1 -1
  134. package/lib/retentionPolicy.d.ts.map +1 -1
  135. package/lib/room-hierarchy.d.ts.map +1 -1
  136. package/lib/rust-crypto/CrossSigningIdentity.d.ts.map +1 -1
  137. package/lib/rust-crypto/DehydratedDeviceManager.d.ts.map +1 -1
  138. package/lib/rust-crypto/DehydratedDeviceManager.js +11 -13
  139. package/lib/rust-crypto/DehydratedDeviceManager.js.map +1 -1
  140. package/lib/rust-crypto/KeyClaimManager.d.ts.map +1 -1
  141. package/lib/rust-crypto/OutgoingRequestProcessor.d.ts.map +1 -1
  142. package/lib/rust-crypto/OutgoingRequestsManager.d.ts.map +1 -1
  143. package/lib/rust-crypto/PerSessionKeyBackupDownloader.d.ts.map +1 -1
  144. package/lib/rust-crypto/RoomEncryptor.d.ts.map +1 -1
  145. package/lib/rust-crypto/backup.d.ts.map +1 -1
  146. package/lib/rust-crypto/rust-crypto.d.ts.map +1 -1
  147. package/lib/rust-crypto/verification.d.ts.map +1 -1
  148. package/lib/scheduler.d.ts.map +1 -1
  149. package/lib/secret-storage.d.ts.map +1 -1
  150. package/lib/serverCapabilities.d.ts.map +1 -1
  151. package/lib/sliding-sync-sdk.d.ts.map +1 -1
  152. package/lib/sliding-sync.d.ts.map +1 -1
  153. package/lib/store/indexeddb-local-backend.d.ts.map +1 -1
  154. package/lib/store/indexeddb-remote-backend.d.ts.map +1 -1
  155. package/lib/store/indexeddb-store-worker.d.ts.map +1 -1
  156. package/lib/store/indexeddb.d.ts.map +1 -1
  157. package/lib/store/memory.d.ts.map +1 -1
  158. package/lib/store/stub.d.ts.map +1 -1
  159. package/lib/sync-accumulator.d.ts.map +1 -1
  160. package/lib/sync.d.ts.map +1 -1
  161. package/lib/testing.d.ts +2 -10
  162. package/lib/testing.d.ts.map +1 -1
  163. package/lib/testing.js +4 -19
  164. package/lib/testing.js.map +1 -1
  165. package/lib/timeline-window.d.ts.map +1 -1
  166. package/lib/utils.d.ts.map +1 -1
  167. package/lib/webrtc/call.d.ts.map +1 -1
  168. package/lib/webrtc/callEventHandler.d.ts.map +1 -1
  169. package/lib/webrtc/callFeed.d.ts.map +1 -1
  170. package/lib/webrtc/groupCall.d.ts.map +1 -1
  171. package/lib/webrtc/groupCallEventHandler.d.ts.map +1 -1
  172. package/lib/webrtc/mediaHandler.d.ts.map +1 -1
  173. package/lib/webrtc/stats/callFeedStatsReporter.d.ts.map +1 -1
  174. package/lib/webrtc/stats/callStatsReportGatherer.d.ts.map +1 -1
  175. package/lib/webrtc/stats/connectionStatsBuilder.d.ts.map +1 -1
  176. package/lib/webrtc/stats/connectionStatsReportBuilder.d.ts.map +1 -1
  177. package/lib/webrtc/stats/groupCallStats.d.ts.map +1 -1
  178. package/lib/webrtc/stats/media/mediaSsrcHandler.d.ts.map +1 -1
  179. package/lib/webrtc/stats/media/mediaTrackHandler.d.ts.map +1 -1
  180. package/lib/webrtc/stats/media/mediaTrackStats.d.ts.map +1 -1
  181. package/lib/webrtc/stats/media/mediaTrackStatsHandler.d.ts.map +1 -1
  182. package/lib/webrtc/stats/statsReportEmitter.d.ts.map +1 -1
  183. package/lib/webrtc/stats/summaryStatsReportGatherer.d.ts.map +1 -1
  184. package/lib/webrtc/stats/trackStatsBuilder.d.ts.map +1 -1
  185. package/lib/webrtc/stats/transportStatsBuilder.d.ts.map +1 -1
  186. package/lib/webrtc/stats/valueFormatter.d.ts.map +1 -1
  187. package/package.json +7 -9
  188. package/src/@types/auth.ts +0 -6
  189. package/src/@types/type-guards.ts +126 -0
  190. package/src/client.ts +13 -29
  191. package/src/crypto-api/index.ts +1 -1
  192. package/src/crypto-api/verification.ts +23 -5
  193. package/src/http-api/fetch.ts +1 -1
  194. package/src/http-api/index.ts +1 -23
  195. package/src/http-api/interface.ts +0 -11
  196. package/src/matrix.ts +1 -1
  197. package/src/oauth/authorize.ts +274 -0
  198. package/src/oauth/discover.ts +102 -0
  199. package/src/{oidc → oauth}/error.ts +8 -7
  200. package/src/oauth/index.ts +297 -0
  201. package/src/oauth/register.ts +166 -0
  202. package/src/oauth/tokenRefresher.ts +77 -0
  203. package/src/rendezvous/MSC4108SignInWithQR.ts +11 -12
  204. package/src/rendezvous/index.ts +2 -2
  205. package/src/rust-crypto/DehydratedDeviceManager.ts +14 -13
  206. package/src/testing.ts +3 -22
  207. package/lib/oidc/authorize.d.ts +0 -157
  208. package/lib/oidc/authorize.d.ts.map +0 -1
  209. package/lib/oidc/authorize.js +0 -365
  210. package/lib/oidc/authorize.js.map +0 -1
  211. package/lib/oidc/discovery.d.ts +0 -22
  212. package/lib/oidc/discovery.d.ts.map +0 -1
  213. package/lib/oidc/discovery.js +0 -65
  214. package/lib/oidc/discovery.js.map +0 -1
  215. package/lib/oidc/error.d.ts +0 -18
  216. package/lib/oidc/error.d.ts.map +0 -1
  217. package/lib/oidc/error.js +0 -35
  218. package/lib/oidc/error.js.map +0 -1
  219. package/lib/oidc/index.d.ts +0 -16
  220. package/lib/oidc/index.d.ts.map +0 -1
  221. package/lib/oidc/index.js +0 -30
  222. package/lib/oidc/index.js.map +0 -1
  223. package/lib/oidc/register.d.ts +0 -70
  224. package/lib/oidc/register.d.ts.map +0 -1
  225. package/lib/oidc/register.js +0 -134
  226. package/lib/oidc/register.js.map +0 -1
  227. package/lib/oidc/tokenRefresher.d.ts +0 -91
  228. package/lib/oidc/tokenRefresher.d.ts.map +0 -1
  229. package/lib/oidc/tokenRefresher.js +0 -173
  230. package/lib/oidc/tokenRefresher.js.map +0 -1
  231. package/lib/oidc/validate.d.ts +0 -78
  232. package/lib/oidc/validate.d.ts.map +0 -1
  233. package/lib/oidc/validate.js +0 -181
  234. package/lib/oidc/validate.js.map +0 -1
  235. package/src/oidc/authorize.ts +0 -431
  236. package/src/oidc/discovery.ts +0 -67
  237. package/src/oidc/index.ts +0 -33
  238. package/src/oidc/register.ts +0 -168
  239. package/src/oidc/tokenRefresher.ts +0 -184
  240. package/src/oidc/validate.ts +0 -265
package/src/client.ts CHANGED
@@ -242,11 +242,7 @@ import { type RoomMessageEventContent, type StickerEventContent } from "./@types
242
242
  import { type ImageInfo } from "./@types/media.ts";
243
243
  import { type Capabilities, ServerCapabilities } from "./serverCapabilities.ts";
244
244
  import { sha256 } from "./digest.ts";
245
- import {
246
- discoverAndValidateOIDCIssuerWellKnown,
247
- type OidcClientConfig,
248
- validateAuthMetadataAndKeys,
249
- } from "./oidc/index.ts";
245
+ import { type ValidatedAuthMetadata, OAuth2Error, isValidAuthMetadata } from "./oauth/index.ts";
250
246
  import { type EmptyObject } from "./@types/common.ts";
251
247
  import { UnsupportedDelayedEventsEndpointError, UnsupportedStickyEventsEndpointError } from "./errors.ts";
252
248
  import { type Transport } from "./matrixrtc/index.ts";
@@ -349,8 +345,7 @@ export interface ICreateClientOpts {
349
345
  * Set to false to send the access token to the server via a query parameter rather
350
346
  * than the Authorization HTTP header.
351
347
  *
352
- * Note that as of v1.11 of the Matrix spec, sending the access token via a query
353
- * is deprecated.
348
+ * @deprecated as of v1.11 in https://spec.matrix.org/v1.17/client-server-api/#using-access-tokens
354
349
  *
355
350
  * Default true.
356
351
  */
@@ -8893,34 +8888,23 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
8893
8888
  /**
8894
8889
  * Discover and validate the auth metadata for the OAuth 2.0 API.
8895
8890
  *
8896
- * Fetches /auth_metadata falling back to legacy implementation using /auth_issuer followed by
8897
- * https://oidc-issuer.example.com/.well-known/openid-configuration and other files linked therein.
8898
8891
  * When successful, validated metadata is returned.
8899
8892
  *
8900
- * @returns validated authentication metadata and optionally signing keys
8893
+ * @returns validated authentication metadata
8901
8894
  * @throws when delegated auth config is invalid or unreachable
8902
8895
  */
8903
- public async getAuthMetadata(): Promise<OidcClientConfig> {
8904
- let authMetadata: unknown | undefined;
8905
- try {
8906
- const useStable = await this.isVersionSupported("v1.15");
8907
- authMetadata = await this.http.request<unknown>(Method.Get, "/auth_metadata", undefined, undefined, {
8908
- prefix: useStable ? ClientPrefix.V1 : ClientPrefix.Unstable + "/org.matrix.msc2965",
8909
- });
8910
- } catch (e) {
8911
- if (e instanceof MatrixError && e.errcode === "M_UNRECOGNIZED") {
8912
- // Fall back to older variant of MSC2965
8913
- const { issuer } = await this.http.request<{
8914
- issuer: string;
8915
- }>(Method.Get, "/auth_issuer", undefined, undefined, {
8916
- prefix: ClientPrefix.Unstable + "/org.matrix.msc2965",
8917
- });
8918
- return discoverAndValidateOIDCIssuerWellKnown(issuer);
8919
- }
8920
- throw e;
8896
+ public async getAuthMetadata(): Promise<ValidatedAuthMetadata> {
8897
+ const useStable = await this.isVersionSupported("v1.15");
8898
+ const authMetadata = await this.http.request(Method.Get, "/auth_metadata", undefined, undefined, {
8899
+ prefix: useStable ? ClientPrefix.V1 : ClientPrefix.Unstable + "/org.matrix.msc2965",
8900
+ });
8901
+
8902
+ if (isValidAuthMetadata(authMetadata)) {
8903
+ return authMetadata;
8921
8904
  }
8922
8905
 
8923
- return validateAuthMetadataAndKeys(authMetadata);
8906
+ logger.error("Issuer configuration not valid");
8907
+ throw new Error(OAuth2Error.OpSupport);
8924
8908
  }
8925
8909
  }
8926
8910
 
@@ -721,7 +721,7 @@ export interface CryptoApi {
721
721
  ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
722
722
 
723
723
  /**
724
- * Export secrets bundle for transmitting to another device as part of OIDC QR login
724
+ * Export secrets bundle for transmitting to another device as part of OAuth2 QR login
725
725
  */
726
726
  exportSecretsBundle?(): Promise<Awaited<ReturnType<SecretsBundle["to_json"]>>>;
727
727
 
@@ -119,7 +119,15 @@ export interface VerificationRequest extends TypedEventEmitter<
119
119
  /**
120
120
  * Send an `m.key.verification.start` event to start verification via a particular method.
121
121
  *
122
- * This is normally used when starting a verification via emojis (ie, `method` is set to `m.sas.v1`).
122
+ * This is used for SAS (emoji) verification: `method` should be set to `m.sas.v1`. It does not start
123
+ * QR-code verification, and passing a QR-code method (such as `m.reciprocate.v1`, `m.qr_code.scan.v1`,
124
+ * or `m.qr_code.show.v1`) will be rejected with an "Unsupported verification method" error.
125
+ *
126
+ * For QR-code verification, use {@link VerificationRequest#generateQRCode} to display a QR code to the
127
+ * other device, or {@link VerificationRequest#scanQRCode} to consume a QR code scanned from it. This is
128
+ * only possible once the `phase` is {@link VerificationPhase.Ready}; when it is, a client can typically
129
+ * offer the user any of three options: show a QR code, scan the other party's QR code, or fall back to
130
+ * emoji (SAS) verification via this method.
123
131
  *
124
132
  * @param method - the name of the verification method to use.
125
133
  *
@@ -130,8 +138,10 @@ export interface VerificationRequest extends TypedEventEmitter<
130
138
  /**
131
139
  * Start a QR code verification by providing a scanned QR code for this verification flow.
132
140
  *
133
- * Validates the QR code, and if it is ok, sends an `m.key.verification.start` event with `method` set to
134
- * `m.reciprocate.v1`, to tell the other side the scan was successful.
141
+ * Call this once the user has scanned the QR code displayed by the other device (for example, the bytes
142
+ * produced by that device's {@link VerificationRequest#generateQRCode}). Validates the QR code, and if it
143
+ * is ok, sends an `m.key.verification.start` event with `method` set to `m.reciprocate.v1`, to tell the
144
+ * other side the scan was successful.
135
145
  *
136
146
  * See also {@link VerificationRequest#startVerification} which can be used to start other verification methods.
137
147
  *
@@ -149,8 +159,16 @@ export interface VerificationRequest extends TypedEventEmitter<
149
159
  /**
150
160
  * Generate the data for a QR code allowing the other device to verify this one, if it supports it.
151
161
  *
152
- * Only returns data once `phase` is {@link VerificationPhase.Ready} and the other party can scan a QR code;
153
- * otherwise returns `undefined`.
162
+ * Returns the QR code data only when all of the following hold; otherwise it returns `undefined`:
163
+ * - `phase` is {@link VerificationPhase.Ready};
164
+ * - the other party advertises support for scanning a QR code (ie, `otherPartySupportsMethod("m.qr_code.scan.v1")`
165
+ * is true); and
166
+ * - this device has its cross-signing keys available locally. A frequent cause of an unexpected `undefined`
167
+ * is that cross-signing has not been set up or the keys have not yet been fetched, so the QR code cannot be
168
+ * constructed even though the phase and method checks pass.
169
+ *
170
+ * On success, display the returned bytes as a QR code for the other device to scan; if the other side scans it
171
+ * and confirms, there is nothing further to do on this side.
154
172
  */
155
173
  generateQRCode(): Promise<Uint8ClampedArray | undefined>;
156
174
 
@@ -208,7 +208,7 @@ export class FetchHttpApi<O extends IHttpOpts> {
208
208
  * @returns The parsed response.
209
209
  * @throws Error if a problem occurred. This includes network problems and Matrix-specific error JSON.
210
210
  */
211
- public request<T>(
211
+ public request<T = unknown>(
212
212
  method: Method,
213
213
  path: string,
214
214
  queryParams?: QueryDict,
@@ -15,14 +15,7 @@ limitations under the License.
15
15
  */
16
16
 
17
17
  import { FetchHttpApi } from "./fetch.ts";
18
- import {
19
- type FileType,
20
- type IContentUri,
21
- type IHttpOpts,
22
- type Upload,
23
- type UploadOpts,
24
- type UploadResponse,
25
- } from "./interface.ts";
18
+ import { type FileType, type IHttpOpts, type Upload, type UploadOpts, type UploadResponse } from "./interface.ts";
26
19
  import { MediaPrefix } from "./prefix.ts";
27
20
  import { type QueryDict, removeElement } from "../utils.ts";
28
21
  import * as callbacks from "../realtime-callbacks.ts";
@@ -176,19 +169,4 @@ export class MatrixHttpApi<O extends IHttpOpts> extends FetchHttpApi<O> {
176
169
  public getCurrentUploads(): Upload[] {
177
170
  return this.uploads;
178
171
  }
179
-
180
- /**
181
- * Get the content repository url with query parameters.
182
- * @returns An object with a 'base', 'path' and 'params' for base URL,
183
- * path and query parameters respectively.
184
- */
185
- public getContentUri(): IContentUri {
186
- return {
187
- base: this.opts.baseUrl,
188
- path: MediaPrefix.V3 + "/upload",
189
- params: {
190
- access_token: this.opts.accessToken!,
191
- },
192
- };
193
- }
194
172
  }
@@ -21,7 +21,6 @@ import { type QueryDict } from "../utils.ts";
21
21
  export type Body = Record<string, any> | BodyInit;
22
22
 
23
23
  /**
24
- * @experimental
25
24
  * Unencrypted access and (optional) refresh token
26
25
  */
27
26
  export type AccessTokens = {
@@ -40,7 +39,6 @@ export type AccessTokens = {
40
39
  };
41
40
 
42
41
  /**
43
- * @experimental
44
42
  * Function that performs token refresh using the given refreshToken.
45
43
  * Returns a promise that resolves to the refreshed access and (optional) refresh tokens.
46
44
  *
@@ -143,15 +141,6 @@ export interface IRequestOpts extends BaseRequestOpts {
143
141
  inhibitLogoutEmit?: boolean;
144
142
  }
145
143
 
146
- export interface IContentUri {
147
- base: string;
148
- path: string;
149
- params: {
150
- // eslint-disable-next-line camelcase
151
- access_token: string;
152
- };
153
- }
154
-
155
144
  export enum HttpApiEvent {
156
145
  SessionLoggedOut = "Session.logged_out",
157
146
  NoConsent = "no_consent",
package/src/matrix.ts CHANGED
@@ -44,7 +44,7 @@ export * from "./models/typed-event-emitter.ts";
44
44
  export * from "./models/user.ts";
45
45
  export * from "./models/device.ts";
46
46
  export * from "./models/search-result.ts";
47
- export * from "./oidc/index.ts";
47
+ export * from "./oauth/index.ts";
48
48
  export * from "./scheduler.ts";
49
49
  export * from "./filter.ts";
50
50
  export * from "./timeline-window.ts";
@@ -0,0 +1,274 @@
1
+ /*
2
+ Copyright 2023 The Matrix.org Foundation C.I.C.
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ */
16
+
17
+ import { secureRandomString } from "../randomstring.ts";
18
+ import { OAuth2Error } from "./error.ts";
19
+ import { type ValidatedAuthMetadata } from "./discover.ts";
20
+ import {
21
+ hasOptionalNumberProperty,
22
+ hasOptionalStringProperty,
23
+ hasRequiredNumberProperty,
24
+ hasRequiredStringProperty,
25
+ isRecord,
26
+ } from "../@types/type-guards.ts";
27
+ import { Method } from "../http-api";
28
+ import { OAuthGrantType } from "./register.ts";
29
+ import { sleep } from "../utils.ts";
30
+
31
+ /**
32
+ * The expected response type from the token endpoint during authorization code flow
33
+ * Normalized to always use capitalized 'Bearer' for token_type
34
+ *
35
+ * See https://datatracker.ietf.org/doc/html/rfc6749#section-4.1.4
36
+ */
37
+ export type BearerTokenResponse = Omit<ValidTokenResponse, "token_type"> & {
38
+ token_type: "Bearer";
39
+ };
40
+
41
+ /**
42
+ * Metadata from OAuth 2.0 token_endpoint as per
43
+ * https://datatracker.ietf.org/doc/html/rfc6749#section-5.1
44
+ * With validated properties required in type
45
+ *
46
+ * This response is expected for the authorization code grant and refresh token grant,
47
+ * as defined in the Matrix spec.
48
+ */
49
+ interface ValidTokenResponse {
50
+ token_type: "Bearer" | "bearer";
51
+ access_token: string;
52
+ expires_in?: number;
53
+ refresh_token?: string;
54
+ scope?: string;
55
+ }
56
+
57
+ /**
58
+ * Validate the given response matches the format expected for a {@link ValidTokenResponse}
59
+ * @param response - the response to validate
60
+ * @throws if the response does not match the expected format
61
+ */
62
+ export function validateBearerTokenResponse(response: unknown): asserts response is ValidTokenResponse {
63
+ if (
64
+ !isRecord(response) ||
65
+ !hasRequiredStringProperty(response, "token_type") ||
66
+ // token_type is case-insensitive, some OPs return `token_type: "bearer"`
67
+ response["token_type"].toLowerCase() !== "bearer" ||
68
+ !hasRequiredStringProperty(response, "access_token") ||
69
+ !hasOptionalNumberProperty(response, "expires_in") ||
70
+ !hasOptionalStringProperty(response, "refresh_token") ||
71
+ !hasOptionalStringProperty(response, "scope")
72
+ ) {
73
+ throw new Error(OAuth2Error.InvalidBearerTokenResponse);
74
+ }
75
+ }
76
+
77
+ /**
78
+ * Generate the scope used in authorization request with OAuth2 IdP
79
+ * @returns scope
80
+ */
81
+ export const generateScope = (deviceId?: string): string => {
82
+ const safeDeviceId = deviceId ?? secureRandomString(10);
83
+ return `urn:matrix:client:api:* urn:matrix:client:device:${safeDeviceId}`;
84
+ };
85
+
86
+ /**
87
+ * Normalize token_type to use capital case to make consuming the token response easier
88
+ * token_type is case insensitive, and it is spec-compliant for OPs to return token_type: "bearer"
89
+ * Later, when used in auth headers it is case sensitive and must be Bearer
90
+ * See: https://datatracker.ietf.org/doc/html/rfc6749#section-4.1.4
91
+ *
92
+ * @param response - validated token response
93
+ * @returns response with token_type set to 'Bearer'
94
+ */
95
+ export const normalizeBearerTokenResponseTokenType = (response: ValidTokenResponse): BearerTokenResponse => ({
96
+ ...response,
97
+ token_type: "Bearer",
98
+ });
99
+
100
+ /**
101
+ * Response from the OAuth2 token endpoint when exchanging a token for grant_type device_code.
102
+ */
103
+ export interface DeviceAccessTokenResponse {
104
+ access_token: string;
105
+ token_type: string;
106
+ refresh_token?: string;
107
+ scope?: string;
108
+ expires_in?: number;
109
+ }
110
+
111
+ /**
112
+ * Validate the given response matches the format expected for a {@link DeviceAccessTokenResponse}
113
+ * @param response - the response to validate
114
+ * @throws if the response does not match the expected format
115
+ */
116
+ export function isValidDeviceAccessTokenResponse(response: unknown): response is DeviceAccessTokenResponse {
117
+ return (
118
+ isRecord(response) &&
119
+ hasRequiredStringProperty(response, "access_token") &&
120
+ hasRequiredStringProperty(response, "token_type") &&
121
+ hasOptionalStringProperty(response, "refresh_token") &&
122
+ hasOptionalStringProperty(response, "scope") &&
123
+ hasOptionalNumberProperty(response, "expires_in")
124
+ );
125
+ }
126
+
127
+ /**
128
+ * Error from the OAuth2 token endpoint when exchanging a token for grant_type device_code.
129
+ */
130
+ export interface DeviceAccessTokenError {
131
+ error: string;
132
+ error_description?: string;
133
+ error_uri?: string;
134
+ session_state?: string;
135
+ }
136
+
137
+ /**
138
+ * Response from the OAuth2 device authorization endpoint.
139
+ * As specified in https://datatracker.ietf.org/doc/html/rfc8628#section-3.2
140
+ */
141
+ export interface DeviceAuthorizationResponse {
142
+ /** The device verification code. */
143
+ device_code: string;
144
+ /** The end-user verification code. */
145
+ user_code: string;
146
+ /**
147
+ * The end-user verification URI on the authorization server.
148
+ * The URI should be short and easy to remember as end users will be asked to manually type it into their user agent.
149
+ */
150
+ verification_uri: string;
151
+ /**
152
+ * The URI which doesn’t require the user to manually type the user_code, designed for non-textual transmission.
153
+ */
154
+ verification_uri_complete?: string;
155
+ /** The lifetime in seconds of the "device_code" and "user_code". */
156
+ expires_in: number;
157
+ /**
158
+ * The minimum amount of time in seconds that the client SHOULD wait between polling requests to the token endpoint.
159
+ * If no value is provided, clients MUST use 5 as the default.
160
+ */
161
+ interval?: number;
162
+ }
163
+
164
+ /**
165
+ * Validate the given response matches the format expected for a {@link DeviceAuthorizationResponse}
166
+ * @param response - the response to validate
167
+ * @throws if the response does not match the expected format
168
+ */
169
+ export function validateDeviceAuthorizationResponse(
170
+ response: unknown,
171
+ ): asserts response is DeviceAuthorizationResponse {
172
+ if (
173
+ !isRecord(response) ||
174
+ !hasRequiredStringProperty(response, "device_code") ||
175
+ !hasRequiredStringProperty(response, "user_code") ||
176
+ !hasRequiredStringProperty(response, "verification_uri") ||
177
+ !hasRequiredNumberProperty(response, "expires_in") ||
178
+ !hasOptionalStringProperty(response, "verification_uri_complete") ||
179
+ !hasOptionalNumberProperty(response, "interval")
180
+ ) {
181
+ throw new Error(OAuth2Error.InvalidDeviceAuthorizationResponse);
182
+ }
183
+ }
184
+
185
+ /**
186
+ * Begin OAuth2 device authorization flow.
187
+ * @param options - The device authorization parameters.
188
+ * @param options.clientId - the client ID returned from client registration.
189
+ * @param options.scope - the scope to request for authorization.
190
+ * @param options.metadata - the validated OAuth2 metadata for the Identity Provider.
191
+ * @returns a promise that resolves to a device access token response,
192
+ * or an error response if the user denies authorization or the device code expires.
193
+ */
194
+ export const startDeviceAuthorization = async ({
195
+ clientId,
196
+ scope,
197
+ metadata,
198
+ }: {
199
+ clientId: string;
200
+ scope: string;
201
+ metadata: ValidatedAuthMetadata;
202
+ }): Promise<DeviceAuthorizationResponse> => {
203
+ const body = new URLSearchParams({ client_id: clientId, scope: scope }).toString();
204
+
205
+ const url = metadata.device_authorization_endpoint;
206
+ if (!url) {
207
+ throw new Error("No device_authorization_endpoint given");
208
+ }
209
+
210
+ const response = await fetch(url, {
211
+ method: Method.Post,
212
+ headers: {
213
+ "Content-Type": "application/x-www-form-urlencoded",
214
+ },
215
+ body,
216
+ });
217
+
218
+ const data = await response.json();
219
+ validateDeviceAuthorizationResponse(data);
220
+ return data;
221
+ };
222
+
223
+ /**
224
+ * Polls the OAuth2 token endpoint until we get a device access token response, or encounter an unrecoverable error.
225
+ * @param options - The device authorization parameters.
226
+ * @param options.session - The session returned from a previous call to {@link startDeviceAuthorization}.
227
+ * @param options.metadata - The validated OAuth2 metadata for the Identity Provider.
228
+ * @param options.clientId - The client ID returned from client registration.
229
+ * @returns a promise that resolves to a device access token response,
230
+ * or an error response if the user denies authorization or the device code expires.
231
+ */
232
+ export const waitForDeviceAuthorization = async ({
233
+ session,
234
+ metadata,
235
+ clientId,
236
+ }: {
237
+ session: DeviceAuthorizationResponse;
238
+ metadata: ValidatedAuthMetadata;
239
+ clientId: string;
240
+ }): Promise<DeviceAccessTokenResponse | DeviceAccessTokenError> => {
241
+ let interval = (session.interval ?? 5) * 1000; // poll interval
242
+ const expiration = Date.now() + session.expires_in * 1000;
243
+ do {
244
+ const body = new URLSearchParams({
245
+ device_code: session.device_code,
246
+ grant_type: OAuthGrantType.DeviceAuthorization,
247
+ client_id: clientId,
248
+ }).toString();
249
+ const response = await fetch(metadata.token_endpoint, {
250
+ method: Method.Post,
251
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
252
+ body,
253
+ });
254
+
255
+ const data = await response.json();
256
+
257
+ if (response.ok && isValidDeviceAccessTokenResponse(data)) {
258
+ return data;
259
+ }
260
+ const errorResponse = data as DeviceAccessTokenError;
261
+ switch (errorResponse.error) {
262
+ case "authorization_pending":
263
+ break;
264
+ case "slow_down":
265
+ interval += 5000;
266
+ break;
267
+ case "access_denied":
268
+ case "expired_token":
269
+ return errorResponse;
270
+ }
271
+ await sleep(interval);
272
+ } while (Date.now() < expiration);
273
+ return { error: "expired" };
274
+ };
@@ -0,0 +1,102 @@
1
+ /*
2
+ Copyright 2023 The Matrix.org Foundation C.I.C.
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ */
16
+
17
+ import {
18
+ hasOptionalStringProperty,
19
+ hasRequiredStringProperty,
20
+ isRecord,
21
+ optionalStringArrayProperty,
22
+ requiredArrayValue,
23
+ } from "../@types/type-guards.ts";
24
+ import { OAuthGrantType } from "./index.ts";
25
+
26
+ /**
27
+ * Metadata from OAuth 2.0 client authentication API as per
28
+ * https://spec.matrix.org/v1.18/client-server-api/#get_matrixclientv1auth_metadata
29
+ * With validated properties required in type
30
+ */
31
+ export interface ValidatedAuthMetadata {
32
+ /** List of actions that the account management URL supports. */
33
+ account_management_actions_supported?: string[];
34
+ /** The URL where the user is able to access the account management capabilities of the homeserver. */
35
+ account_management_uri?: string;
36
+ /** URL of the authorization endpoint, necessary to use the authorization code grant. */
37
+ authorization_endpoint: string;
38
+ /**
39
+ * List of OAuth 2.0 Proof Key for Code Exchange (PKCE) code challenge methods that the server supports at the authorization endpoint.
40
+ *
41
+ * This array MUST contain at least the S256 value, for improved security in the authorization code grant.
42
+ */
43
+ code_challenge_methods_supported: string[];
44
+ /** URL of the device authorization endpoint, as defined in RFC 8628, necessary to use the device authorization grant. */
45
+ device_authorization_endpoint?: string;
46
+ /**
47
+ * List of OAuth 2.0 grant type strings that the server supports at the token endpoint.
48
+ *
49
+ * This array MUST contain at least the authorization_code and refresh_token values,
50
+ * for clients to be able to use the authorization code grant and refresh token grant, respectively.
51
+ */
52
+ grant_types_supported: string[];
53
+ /** The authorization server’s issuer identifier, which is a URL that uses the https scheme and has no query or fragment components. */
54
+ issuer: string;
55
+ /** List of OpenID Connect prompt values that the server supports at the authorization endpoint. */
56
+ prompt_values_supported?: string[];
57
+ /** URL of the client registration endpoint, necessary to perform dynamic registration of a client. */
58
+ registration_endpoint: string;
59
+ /**
60
+ * List of OAuth 2.0 response mode strings that the server supports at the authorization endpoint.
61
+ *
62
+ * This array MUST contain at least the query and fragment values, for improved security in the authorization code grant.
63
+ */
64
+ response_modes_supported: string[];
65
+ /**
66
+ * List of OAuth 2.0 response type strings that the server supports at the authorization endpoint.
67
+ *
68
+ * This array MUST contain at least the code value, for clients to be able to use the authorization code grant.
69
+ */
70
+ response_types_supported: string[];
71
+ /** URL of the revocation endpoint, necessary to log out a client by invalidating its access and refresh tokens. */
72
+ revocation_endpoint: string;
73
+ /** URL of the token endpoint, used by the grants. */
74
+ token_endpoint: string;
75
+ }
76
+
77
+ /**
78
+ * Validates OAuth 2.0 auth metadata as defined by
79
+ * https://spec.matrix.org/v1.18/client-server-api/#get_matrixclientv1auth_metadata
80
+ * @param authMetadata - json object
81
+ * @returns boolean of whether the input is valid
82
+ */
83
+ export const isValidAuthMetadata = (authMetadata: unknown): authMetadata is ValidatedAuthMetadata => {
84
+ return (
85
+ isRecord(authMetadata) &&
86
+ hasRequiredStringProperty(authMetadata, "issuer") &&
87
+ hasRequiredStringProperty(authMetadata, "authorization_endpoint") &&
88
+ hasRequiredStringProperty(authMetadata, "token_endpoint") &&
89
+ hasRequiredStringProperty(authMetadata, "revocation_endpoint") &&
90
+ hasRequiredStringProperty(authMetadata, "registration_endpoint") &&
91
+ hasOptionalStringProperty(authMetadata, "account_management_uri") &&
92
+ hasOptionalStringProperty(authMetadata, "device_authorization_endpoint") &&
93
+ optionalStringArrayProperty(authMetadata, "account_management_actions_supported") &&
94
+ optionalStringArrayProperty(authMetadata, "prompt_values_supported") &&
95
+ requiredArrayValue(authMetadata, "response_modes_supported", "query") &&
96
+ requiredArrayValue(authMetadata, "response_modes_supported", "fragment") &&
97
+ requiredArrayValue(authMetadata, "response_types_supported", "code") &&
98
+ requiredArrayValue(authMetadata, "grant_types_supported", OAuthGrantType.AuthorizationCode) &&
99
+ requiredArrayValue(authMetadata, "grant_types_supported", OAuthGrantType.RefreshToken) &&
100
+ requiredArrayValue(authMetadata, "code_challenge_methods_supported", "S256")
101
+ );
102
+ };
@@ -15,19 +15,20 @@ limitations under the License.
15
15
  */
16
16
 
17
17
  /**
18
- * Errors expected to be encountered during OIDC discovery, client registration, and authentication.
18
+ * Errors expected to be encountered during OAuth2 discovery, client registration, and authentication.
19
19
  * Not intended to be displayed directly to the user.
20
20
  */
21
- export enum OidcError {
22
- NotSupported = "OIDC authentication not supported",
23
- Misconfigured = "OIDC is misconfigured",
24
- General = "Something went wrong with OIDC discovery",
25
- OpSupport = "Configured OIDC OP does not support required functions",
21
+ export enum OAuth2Error {
22
+ General = "Something went wrong with OAuth2 discovery",
23
+ OpSupport = "Configured OAuth2 OP does not support required functions",
26
24
  DynamicRegistrationNotSupported = "Dynamic registration not supported",
27
25
  DynamicRegistrationFailed = "Dynamic registration failed",
28
26
  DynamicRegistrationInvalid = "Dynamic registration invalid response",
29
27
  CodeExchangeFailed = "Failed to exchange code for token",
30
28
  InvalidBearerTokenResponse = "Invalid bearer token response",
31
- InvalidIdToken = "Invalid ID token",
29
+ InvalidDeviceAuthorizationResponse = "Invalid device authorization response",
32
30
  MissingOrInvalidStoredState = "State required to finish logging in is not found in storage.",
31
+ RefreshTokenFailed = "Failed to refresh token",
32
+ RevokeTokenFailed = "Failed to revoke token",
33
+ DeviceAuthorizationGrantFailed = "Failed to perform device authorization grant",
33
34
  }