You've already forked matrix-js-sdk
mirror of
https://github.com/matrix-org/matrix-js-sdk.git
synced 2025-11-23 17:02:25 +03:00
Release tranche of breaking changes (#4963)
* Remove deprecated `IJoinRoomOpts.syncRoom` option (#4914) This option is non-functional, and was deprecated in https://github.com/matrix-org/matrix-js-sdk/pull/4913. Remove it altogether. * Remove support for `onlyData != true` (#4939) * Remove deprecated fields, methods, utilities (#4959) --------- Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> Co-authored-by: Richard van der Hoff <richard@matrix.org>
This commit is contained in:
committed by
GitHub
parent
3a33c658bb
commit
b80d0091d2
@@ -1491,8 +1491,10 @@ describe("crypto", () => {
|
||||
|
||||
expect(ev.decryptionFailureReason).toEqual(expectedErrorCode);
|
||||
|
||||
// `isEncryptedDisabledForUnverifiedDevices` should be true for `m.unverified` and false for other errors.
|
||||
expect(ev.isEncryptedDisabledForUnverifiedDevices).toEqual(withheldCode === "m.unverified");
|
||||
// `decryptionFailureReason` should be `MEGOLM_KEY_WITHHELD_FOR_UNVERIFIED_DEVICE` for `m.unverified`
|
||||
expect(
|
||||
ev.decryptionFailureReason === DecryptionFailureCode.MEGOLM_KEY_WITHHELD_FOR_UNVERIFIED_DEVICE,
|
||||
).toEqual(withheldCode === "m.unverified");
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
@@ -14,8 +14,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { type Mocked } from "jest-mock";
|
||||
|
||||
import type { Mocked, MockedFunction } from "jest-mock";
|
||||
import { FetchHttpApi } from "../../../src/http-api/fetch";
|
||||
import { TypedEventEmitter } from "../../../src/models/typed-event-emitter";
|
||||
import {
|
||||
@@ -43,8 +42,8 @@ describe("FetchHttpApi", () => {
|
||||
});
|
||||
|
||||
it("should support aborting multiple times", () => {
|
||||
const fetchFn = jest.fn().mockResolvedValue({ ok: true });
|
||||
const api = new FetchHttpApi(new TypedEventEmitter<any, any>(), { baseUrl, prefix, fetchFn });
|
||||
const fetchFn = makeMockFetchFn();
|
||||
const api = new FetchHttpApi(new TypedEventEmitter<any, any>(), { baseUrl, prefix, fetchFn, onlyData: true });
|
||||
|
||||
api.request(Method.Get, "/foo");
|
||||
api.request(Method.Get, "/baz");
|
||||
@@ -68,13 +67,13 @@ describe("FetchHttpApi", () => {
|
||||
it("should fall back to global fetch if fetchFn not provided", () => {
|
||||
globalThis.fetch = jest.fn();
|
||||
expect(globalThis.fetch).not.toHaveBeenCalled();
|
||||
const api = new FetchHttpApi(new TypedEventEmitter<any, any>(), { baseUrl, prefix });
|
||||
const api = new FetchHttpApi(new TypedEventEmitter<any, any>(), { baseUrl, prefix, onlyData: true });
|
||||
api.fetch("test");
|
||||
expect(globalThis.fetch).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should update identity server base url", () => {
|
||||
const api = new FetchHttpApi<IHttpOpts>(new TypedEventEmitter<any, any>(), { baseUrl, prefix });
|
||||
const api = new FetchHttpApi<IHttpOpts>(new TypedEventEmitter<any, any>(), { baseUrl, prefix, onlyData: true });
|
||||
expect(api.opts.idBaseUrl).toBeUndefined();
|
||||
api.setIdBaseUrl("https://id.foo.bar");
|
||||
expect(api.opts.idBaseUrl).toBe("https://id.foo.bar");
|
||||
@@ -82,23 +81,35 @@ describe("FetchHttpApi", () => {
|
||||
|
||||
describe("idServerRequest", () => {
|
||||
it("should throw if no idBaseUrl", () => {
|
||||
const api = new FetchHttpApi(new TypedEventEmitter<any, any>(), { baseUrl, prefix });
|
||||
const api = new FetchHttpApi(new TypedEventEmitter<any, any>(), { baseUrl, prefix, onlyData: true });
|
||||
expect(() => api.idServerRequest(Method.Get, "/test", {}, IdentityPrefix.V2)).toThrow(
|
||||
"No identity server base URL set",
|
||||
);
|
||||
});
|
||||
|
||||
it("should send params as query string for GET requests", () => {
|
||||
const fetchFn = jest.fn().mockResolvedValue({ ok: true });
|
||||
const api = new FetchHttpApi(new TypedEventEmitter<any, any>(), { baseUrl, idBaseUrl, prefix, fetchFn });
|
||||
const fetchFn = makeMockFetchFn();
|
||||
const api = new FetchHttpApi(new TypedEventEmitter<any, any>(), {
|
||||
baseUrl,
|
||||
idBaseUrl,
|
||||
prefix,
|
||||
fetchFn,
|
||||
onlyData: true,
|
||||
});
|
||||
api.idServerRequest(Method.Get, "/test", { foo: "bar", via: ["a", "b"] }, IdentityPrefix.V2);
|
||||
expect(fetchFn.mock.calls[0][0].searchParams.get("foo")).toBe("bar");
|
||||
expect(fetchFn.mock.calls[0][0].searchParams.getAll("via")).toEqual(["a", "b"]);
|
||||
});
|
||||
|
||||
it("should send params as body for non-GET requests", () => {
|
||||
const fetchFn = jest.fn().mockResolvedValue({ ok: true });
|
||||
const api = new FetchHttpApi(new TypedEventEmitter<any, any>(), { baseUrl, idBaseUrl, prefix, fetchFn });
|
||||
const fetchFn = makeMockFetchFn();
|
||||
const api = new FetchHttpApi(new TypedEventEmitter<any, any>(), {
|
||||
baseUrl,
|
||||
idBaseUrl,
|
||||
prefix,
|
||||
fetchFn,
|
||||
onlyData: true,
|
||||
});
|
||||
const params = { foo: "bar", via: ["a", "b"] };
|
||||
api.idServerRequest(Method.Post, "/test", params, IdentityPrefix.V2);
|
||||
expect(fetchFn.mock.calls[0][0].searchParams.get("foo")).not.toBe("bar");
|
||||
@@ -106,18 +117,27 @@ describe("FetchHttpApi", () => {
|
||||
});
|
||||
|
||||
it("should add Authorization header if token provided", () => {
|
||||
const fetchFn = jest.fn().mockResolvedValue({ ok: true });
|
||||
const api = new FetchHttpApi(new TypedEventEmitter<any, any>(), { baseUrl, idBaseUrl, prefix, fetchFn });
|
||||
const fetchFn = makeMockFetchFn();
|
||||
const api = new FetchHttpApi(new TypedEventEmitter<any, any>(), {
|
||||
baseUrl,
|
||||
idBaseUrl,
|
||||
prefix,
|
||||
fetchFn,
|
||||
onlyData: true,
|
||||
});
|
||||
api.idServerRequest(Method.Post, "/test", {}, IdentityPrefix.V2, "token");
|
||||
expect(fetchFn.mock.calls[0][1].headers.Authorization).toBe("Bearer token");
|
||||
});
|
||||
});
|
||||
|
||||
it("should return the Response object if onlyData=false", async () => {
|
||||
const res = { ok: true };
|
||||
const fetchFn = jest.fn().mockResolvedValue(res);
|
||||
const api = new FetchHttpApi(new TypedEventEmitter<any, any>(), { baseUrl, prefix, fetchFn, onlyData: false });
|
||||
await expect(api.requestOtherUrl(Method.Get, "http://url")).resolves.toBe(res);
|
||||
it("should complain if constructed without `onlyData: true`", async () => {
|
||||
expect(
|
||||
() =>
|
||||
new FetchHttpApi(new TypedEventEmitter<any, any>(), {
|
||||
baseUrl,
|
||||
prefix,
|
||||
}),
|
||||
).toThrow("Constructing FetchHttpApi without `onlyData=true` is no longer supported.");
|
||||
});
|
||||
|
||||
it("should set an Accept header, and parse the response as JSON, by default", async () => {
|
||||
@@ -165,37 +185,40 @@ describe("FetchHttpApi", () => {
|
||||
});
|
||||
|
||||
it("should send token via query params if useAuthorizationHeader=false", async () => {
|
||||
const fetchFn = jest.fn().mockResolvedValue({ ok: true });
|
||||
const fetchFn = makeMockFetchFn();
|
||||
const api = new FetchHttpApi(new TypedEventEmitter<any, any>(), {
|
||||
baseUrl,
|
||||
prefix,
|
||||
fetchFn,
|
||||
accessToken: "token",
|
||||
useAuthorizationHeader: false,
|
||||
onlyData: true,
|
||||
});
|
||||
await api.authedRequest(Method.Get, "/path");
|
||||
expect(fetchFn.mock.calls[0][0].searchParams.get("access_token")).toBe("token");
|
||||
});
|
||||
|
||||
it("should send token via headers by default", async () => {
|
||||
const fetchFn = jest.fn().mockResolvedValue({ ok: true });
|
||||
const fetchFn = makeMockFetchFn();
|
||||
const api = new FetchHttpApi(new TypedEventEmitter<any, any>(), {
|
||||
baseUrl,
|
||||
prefix,
|
||||
fetchFn,
|
||||
accessToken: "token",
|
||||
onlyData: true,
|
||||
});
|
||||
await api.authedRequest(Method.Get, "/path");
|
||||
expect(fetchFn.mock.calls[0][1].headers["Authorization"]).toBe("Bearer token");
|
||||
});
|
||||
|
||||
it("should not send a token if not calling `authedRequest`", () => {
|
||||
const fetchFn = jest.fn().mockResolvedValue({ ok: true });
|
||||
const fetchFn = makeMockFetchFn();
|
||||
const api = new FetchHttpApi(new TypedEventEmitter<any, any>(), {
|
||||
baseUrl,
|
||||
prefix,
|
||||
fetchFn,
|
||||
accessToken: "token",
|
||||
onlyData: true,
|
||||
});
|
||||
api.request(Method.Get, "/path");
|
||||
expect(fetchFn.mock.calls[0][0].searchParams.get("access_token")).toBeFalsy();
|
||||
@@ -203,13 +226,14 @@ describe("FetchHttpApi", () => {
|
||||
});
|
||||
|
||||
it("should ensure no token is leaked out via query params if sending via headers", async () => {
|
||||
const fetchFn = jest.fn().mockResolvedValue({ ok: true });
|
||||
const fetchFn = makeMockFetchFn();
|
||||
const api = new FetchHttpApi(new TypedEventEmitter<any, any>(), {
|
||||
baseUrl,
|
||||
prefix,
|
||||
fetchFn,
|
||||
accessToken: "token",
|
||||
useAuthorizationHeader: true,
|
||||
onlyData: true,
|
||||
});
|
||||
await api.authedRequest(Method.Get, "/path", { access_token: "123" });
|
||||
expect(fetchFn.mock.calls[0][0].searchParams.get("access_token")).toBeFalsy();
|
||||
@@ -217,26 +241,28 @@ describe("FetchHttpApi", () => {
|
||||
});
|
||||
|
||||
it("should not override manually specified access token via query params", async () => {
|
||||
const fetchFn = jest.fn().mockResolvedValue({ ok: true });
|
||||
const fetchFn = makeMockFetchFn();
|
||||
const api = new FetchHttpApi(new TypedEventEmitter<any, any>(), {
|
||||
baseUrl,
|
||||
prefix,
|
||||
fetchFn,
|
||||
accessToken: "token",
|
||||
useAuthorizationHeader: false,
|
||||
onlyData: true,
|
||||
});
|
||||
await api.authedRequest(Method.Get, "/path", { access_token: "RealToken" });
|
||||
expect(fetchFn.mock.calls[0][0].searchParams.get("access_token")).toBe("RealToken");
|
||||
});
|
||||
|
||||
it("should not override manually specified access token via header", async () => {
|
||||
const fetchFn = jest.fn().mockResolvedValue({ ok: true });
|
||||
const fetchFn = makeMockFetchFn();
|
||||
const api = new FetchHttpApi(new TypedEventEmitter<any, any>(), {
|
||||
baseUrl,
|
||||
prefix,
|
||||
fetchFn,
|
||||
accessToken: "token",
|
||||
useAuthorizationHeader: true,
|
||||
onlyData: true,
|
||||
});
|
||||
await api.authedRequest(Method.Get, "/path", undefined, undefined, {
|
||||
headers: { Authorization: "Bearer RealToken" },
|
||||
@@ -245,8 +271,8 @@ describe("FetchHttpApi", () => {
|
||||
});
|
||||
|
||||
it("should not override Accept header", async () => {
|
||||
const fetchFn = jest.fn().mockResolvedValue({ ok: true });
|
||||
const api = new FetchHttpApi(new TypedEventEmitter<any, any>(), { baseUrl, prefix, fetchFn });
|
||||
const fetchFn = makeMockFetchFn();
|
||||
const api = new FetchHttpApi(new TypedEventEmitter<any, any>(), { baseUrl, prefix, fetchFn, onlyData: true });
|
||||
await api.authedRequest(Method.Get, "/path", undefined, undefined, {
|
||||
headers: { Accept: "text/html" },
|
||||
});
|
||||
@@ -269,7 +295,7 @@ describe("FetchHttpApi", () => {
|
||||
),
|
||||
});
|
||||
const emitter = new TypedEventEmitter<HttpApiEvent, HttpApiEventHandlerMap>();
|
||||
const api = new FetchHttpApi(emitter, { baseUrl, prefix, fetchFn });
|
||||
const api = new FetchHttpApi(emitter, { baseUrl, prefix, fetchFn, onlyData: true });
|
||||
|
||||
await Promise.all([
|
||||
emitPromise(emitter, HttpApiEvent.NoConsent),
|
||||
@@ -279,9 +305,9 @@ describe("FetchHttpApi", () => {
|
||||
|
||||
describe("authedRequest", () => {
|
||||
it("should not include token if unset", async () => {
|
||||
const fetchFn = jest.fn().mockResolvedValue({ ok: true });
|
||||
const fetchFn = makeMockFetchFn();
|
||||
const emitter = new TypedEventEmitter<HttpApiEvent, HttpApiEventHandlerMap>();
|
||||
const api = new FetchHttpApi(emitter, { baseUrl, prefix, fetchFn });
|
||||
const api = new FetchHttpApi(emitter, { baseUrl, prefix, fetchFn, onlyData: true });
|
||||
await api.authedRequest(Method.Post, "/account/password");
|
||||
expect(fetchFn.mock.calls[0][1].headers.Authorization).toBeUndefined();
|
||||
});
|
||||
@@ -310,6 +336,7 @@ describe("FetchHttpApi", () => {
|
||||
const okayResponse = {
|
||||
ok: true,
|
||||
status: 200,
|
||||
json: jest.fn().mockResolvedValue({ x: 1 }),
|
||||
};
|
||||
|
||||
describe("without a tokenRefreshFunction", () => {
|
||||
@@ -317,7 +344,14 @@ describe("FetchHttpApi", () => {
|
||||
const fetchFn = jest.fn().mockResolvedValue(unknownTokenResponse);
|
||||
const emitter = new TypedEventEmitter<HttpApiEvent, HttpApiEventHandlerMap>();
|
||||
jest.spyOn(emitter, "emit");
|
||||
const api = new FetchHttpApi(emitter, { baseUrl, prefix, fetchFn, accessToken, refreshToken });
|
||||
const api = new FetchHttpApi(emitter, {
|
||||
baseUrl,
|
||||
prefix,
|
||||
fetchFn,
|
||||
accessToken,
|
||||
refreshToken,
|
||||
onlyData: true,
|
||||
});
|
||||
await expect(api.authedRequest(Method.Post, "/account/password")).rejects.toThrow(
|
||||
unknownTokenErr,
|
||||
);
|
||||
@@ -339,6 +373,7 @@ describe("FetchHttpApi", () => {
|
||||
tokenRefreshFunction,
|
||||
accessToken,
|
||||
refreshToken,
|
||||
onlyData: true,
|
||||
});
|
||||
await expect(api.authedRequest(Method.Post, "/account/password")).rejects.toThrow(
|
||||
unknownTokenErr,
|
||||
@@ -360,6 +395,7 @@ describe("FetchHttpApi", () => {
|
||||
tokenRefreshFunction,
|
||||
accessToken,
|
||||
refreshToken,
|
||||
onlyData: true,
|
||||
});
|
||||
await expect(api.authedRequest(Method.Post, "/account/password")).rejects.toThrow(
|
||||
unknownTokenErr,
|
||||
@@ -388,11 +424,12 @@ describe("FetchHttpApi", () => {
|
||||
tokenRefreshFunction,
|
||||
accessToken,
|
||||
refreshToken,
|
||||
onlyData: true,
|
||||
});
|
||||
const result = await api.authedRequest(Method.Post, "/account/password", undefined, undefined, {
|
||||
headers: {},
|
||||
});
|
||||
expect(result).toEqual(okayResponse);
|
||||
expect(result).toEqual({ x: 1 });
|
||||
expect(tokenRefreshFunction).toHaveBeenCalledWith(refreshToken);
|
||||
|
||||
expect(fetchFn).toHaveBeenCalledTimes(2);
|
||||
@@ -431,6 +468,7 @@ describe("FetchHttpApi", () => {
|
||||
tokenRefreshFunction,
|
||||
accessToken,
|
||||
refreshToken,
|
||||
onlyData: true,
|
||||
});
|
||||
await expect(api.authedRequest(Method.Post, "/account/password")).rejects.toThrow(
|
||||
unknownTokenErr,
|
||||
@@ -486,6 +524,7 @@ describe("FetchHttpApi", () => {
|
||||
tokenRefreshFunction,
|
||||
accessToken,
|
||||
refreshToken,
|
||||
onlyData: true,
|
||||
});
|
||||
await expect(api.authedRequest(Method.Post, "/account/password")).rejects.toThrow(
|
||||
unknownTokenErr,
|
||||
@@ -506,7 +545,7 @@ describe("FetchHttpApi", () => {
|
||||
const makeApi = (thisBaseUrl = baseUrl): FetchHttpApi<any> => {
|
||||
const fetchFn = jest.fn();
|
||||
const emitter = new TypedEventEmitter<HttpApiEvent, HttpApiEventHandlerMap>();
|
||||
return new FetchHttpApi(emitter, { baseUrl: thisBaseUrl, prefix, fetchFn });
|
||||
return new FetchHttpApi(emitter, { baseUrl: thisBaseUrl, prefix, fetchFn, onlyData: true });
|
||||
};
|
||||
|
||||
type TestParams = {
|
||||
@@ -559,7 +598,13 @@ describe("FetchHttpApi", () => {
|
||||
const makeApiWithExtraParams = (extraParams: QueryDict): FetchHttpApi<any> => {
|
||||
const fetchFn = jest.fn();
|
||||
const emitter = new TypedEventEmitter<HttpApiEvent, HttpApiEventHandlerMap>();
|
||||
return new FetchHttpApi(emitter, { baseUrl: localBaseUrl, prefix, fetchFn, extraParams });
|
||||
return new FetchHttpApi(emitter, {
|
||||
baseUrl: localBaseUrl,
|
||||
prefix,
|
||||
fetchFn,
|
||||
onlyData: true,
|
||||
extraParams,
|
||||
});
|
||||
};
|
||||
|
||||
const userId = "@rsb-tbg:localhost";
|
||||
@@ -612,7 +657,7 @@ describe("FetchHttpApi", () => {
|
||||
it("should work when extraParams is undefined", () => {
|
||||
const fetchFn = jest.fn();
|
||||
const emitter = new TypedEventEmitter<HttpApiEvent, HttpApiEventHandlerMap>();
|
||||
const api = new FetchHttpApi(emitter, { baseUrl: localBaseUrl, prefix, fetchFn });
|
||||
const api = new FetchHttpApi(emitter, { baseUrl: localBaseUrl, prefix, fetchFn, onlyData: true });
|
||||
|
||||
const queryParams = { userId: "123" };
|
||||
const result = api.getUrl("/test", queryParams);
|
||||
@@ -645,10 +690,11 @@ describe("FetchHttpApi", () => {
|
||||
prefix,
|
||||
fetchFn,
|
||||
logger: mockLogger,
|
||||
onlyData: true,
|
||||
});
|
||||
const prom = api.requestOtherUrl(Method.Get, "https://server:8448/some/path?query=param#fragment");
|
||||
jest.advanceTimersByTime(1234);
|
||||
responseResolvers.resolve({ ok: true, status: 200, text: () => Promise.resolve("RESPONSE") } as Response);
|
||||
responseResolvers.resolve({ ok: true, status: 200, json: () => Promise.resolve("RESPONSE") } as Response);
|
||||
await prom;
|
||||
expect(mockLogger.debug).not.toHaveBeenCalledWith("fragment");
|
||||
expect(mockLogger.debug).not.toHaveBeenCalledWith("query");
|
||||
@@ -691,6 +737,7 @@ describe("FetchHttpApi", () => {
|
||||
tokenRefreshFunction,
|
||||
accessToken: "ACCESS_TOKEN",
|
||||
refreshToken: "REFRESH_TOKEN",
|
||||
onlyData: true,
|
||||
});
|
||||
|
||||
const prom1 = api.authedRequest(Method.Get, "/path1");
|
||||
@@ -746,6 +793,7 @@ describe("FetchHttpApi", () => {
|
||||
tokenRefreshFunction,
|
||||
accessToken: "ACCESS_TOKEN",
|
||||
refreshToken: "REFRESH_TOKEN",
|
||||
onlyData: true,
|
||||
});
|
||||
|
||||
const prom1 = api.authedRequest(Method.Get, "/path1");
|
||||
@@ -783,3 +831,7 @@ describe("FetchHttpApi", () => {
|
||||
expect(api.opts.refreshToken).toBe("NEW_REFRESH_TOKEN");
|
||||
});
|
||||
});
|
||||
|
||||
function makeMockFetchFn(): MockedFunction<any> {
|
||||
return jest.fn().mockResolvedValue({ ok: true, json: jest.fn().mockResolvedValue({}) });
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ describe("MatrixHttpApi", () => {
|
||||
it("should fall back to `fetch` where xhr is unavailable", async () => {
|
||||
globalThis.XMLHttpRequest = undefined!;
|
||||
const fetchFn = jest.fn().mockResolvedValue({ ok: true, json: jest.fn().mockResolvedValue({}) });
|
||||
const api = new MatrixHttpApi(new TypedEventEmitter<any, any>(), { baseUrl, prefix, fetchFn });
|
||||
const api = new MatrixHttpApi(new TypedEventEmitter<any, any>(), { baseUrl, prefix, fetchFn, onlyData: true });
|
||||
upload = api.uploadContent({} as File);
|
||||
await upload;
|
||||
expect(fetchFn).toHaveBeenCalled();
|
||||
@@ -70,7 +70,7 @@ describe("MatrixHttpApi", () => {
|
||||
|
||||
it("should prefer xhr where available", () => {
|
||||
const fetchFn = jest.fn().mockResolvedValue({ ok: true });
|
||||
const api = new MatrixHttpApi(new TypedEventEmitter<any, any>(), { baseUrl, prefix, fetchFn });
|
||||
const api = new MatrixHttpApi(new TypedEventEmitter<any, any>(), { baseUrl, prefix, fetchFn, onlyData: true });
|
||||
upload = api.uploadContent({} as File);
|
||||
expect(fetchFn).not.toHaveBeenCalled();
|
||||
expect(xhr.open).toHaveBeenCalled();
|
||||
@@ -82,6 +82,7 @@ describe("MatrixHttpApi", () => {
|
||||
prefix,
|
||||
accessToken: "token",
|
||||
useAuthorizationHeader: false,
|
||||
onlyData: true,
|
||||
});
|
||||
upload = api.uploadContent({} as File);
|
||||
expect(xhr.open).toHaveBeenCalledWith(
|
||||
@@ -96,6 +97,7 @@ describe("MatrixHttpApi", () => {
|
||||
baseUrl,
|
||||
prefix,
|
||||
accessToken: "token",
|
||||
onlyData: true,
|
||||
});
|
||||
upload = api.uploadContent({} as File);
|
||||
expect(xhr.open).toHaveBeenCalledWith(Method.Post, baseUrl.toLowerCase() + "/_matrix/media/v3/upload");
|
||||
@@ -103,7 +105,7 @@ describe("MatrixHttpApi", () => {
|
||||
});
|
||||
|
||||
it("should include filename by default", () => {
|
||||
const api = new MatrixHttpApi(new TypedEventEmitter<any, any>(), { baseUrl, prefix });
|
||||
const api = new MatrixHttpApi(new TypedEventEmitter<any, any>(), { baseUrl, prefix, onlyData: true });
|
||||
upload = api.uploadContent({} as File, { name: "name" });
|
||||
expect(xhr.open).toHaveBeenCalledWith(
|
||||
Method.Post,
|
||||
@@ -112,13 +114,13 @@ describe("MatrixHttpApi", () => {
|
||||
});
|
||||
|
||||
it("should allow not sending the filename", () => {
|
||||
const api = new MatrixHttpApi(new TypedEventEmitter<any, any>(), { baseUrl, prefix });
|
||||
const api = new MatrixHttpApi(new TypedEventEmitter<any, any>(), { baseUrl, prefix, onlyData: true });
|
||||
upload = api.uploadContent({} as File, { name: "name", includeFilename: false });
|
||||
expect(xhr.open).toHaveBeenCalledWith(Method.Post, baseUrl.toLowerCase() + "/_matrix/media/v3/upload");
|
||||
});
|
||||
|
||||
it("should abort xhr when the upload is aborted", () => {
|
||||
const api = new MatrixHttpApi(new TypedEventEmitter<any, any>(), { baseUrl, prefix });
|
||||
const api = new MatrixHttpApi(new TypedEventEmitter<any, any>(), { baseUrl, prefix, onlyData: true });
|
||||
upload = api.uploadContent({} as File);
|
||||
api.cancelUpload(upload);
|
||||
expect(xhr.abort).toHaveBeenCalled();
|
||||
@@ -126,7 +128,7 @@ describe("MatrixHttpApi", () => {
|
||||
});
|
||||
|
||||
it("should timeout if no progress in 30s", () => {
|
||||
const api = new MatrixHttpApi(new TypedEventEmitter<any, any>(), { baseUrl, prefix });
|
||||
const api = new MatrixHttpApi(new TypedEventEmitter<any, any>(), { baseUrl, prefix, onlyData: true });
|
||||
upload = api.uploadContent({} as File);
|
||||
jest.advanceTimersByTime(25000);
|
||||
// @ts-ignore
|
||||
@@ -138,7 +140,7 @@ describe("MatrixHttpApi", () => {
|
||||
});
|
||||
|
||||
it("should call progressHandler", () => {
|
||||
const api = new MatrixHttpApi(new TypedEventEmitter<any, any>(), { baseUrl, prefix });
|
||||
const api = new MatrixHttpApi(new TypedEventEmitter<any, any>(), { baseUrl, prefix, onlyData: true });
|
||||
const progressHandler = jest.fn();
|
||||
upload = api.uploadContent({} as File, { progressHandler });
|
||||
const progressEvent = new Event("progress") as ProgressEvent;
|
||||
@@ -154,7 +156,7 @@ describe("MatrixHttpApi", () => {
|
||||
});
|
||||
|
||||
it("should error when no response body", () => {
|
||||
const api = new MatrixHttpApi(new TypedEventEmitter<any, any>(), { baseUrl, prefix });
|
||||
const api = new MatrixHttpApi(new TypedEventEmitter<any, any>(), { baseUrl, prefix, onlyData: true });
|
||||
upload = api.uploadContent({} as File);
|
||||
|
||||
xhr.readyState = DONE;
|
||||
@@ -167,7 +169,7 @@ describe("MatrixHttpApi", () => {
|
||||
});
|
||||
|
||||
it("should error on a 400-code", () => {
|
||||
const api = new MatrixHttpApi(new TypedEventEmitter<any, any>(), { baseUrl, prefix });
|
||||
const api = new MatrixHttpApi(new TypedEventEmitter<any, any>(), { baseUrl, prefix, onlyData: true });
|
||||
upload = api.uploadContent({} as File);
|
||||
|
||||
xhr.readyState = DONE;
|
||||
@@ -184,7 +186,7 @@ describe("MatrixHttpApi", () => {
|
||||
});
|
||||
|
||||
it("should return response on successful upload", () => {
|
||||
const api = new MatrixHttpApi(new TypedEventEmitter<any, any>(), { baseUrl, prefix });
|
||||
const api = new MatrixHttpApi(new TypedEventEmitter<any, any>(), { baseUrl, prefix, onlyData: true });
|
||||
upload = api.uploadContent({} as File);
|
||||
|
||||
xhr.readyState = DONE;
|
||||
@@ -198,14 +200,14 @@ describe("MatrixHttpApi", () => {
|
||||
});
|
||||
|
||||
it("should abort xhr when calling `cancelUpload`", () => {
|
||||
const api = new MatrixHttpApi(new TypedEventEmitter<any, any>(), { baseUrl, prefix });
|
||||
const api = new MatrixHttpApi(new TypedEventEmitter<any, any>(), { baseUrl, prefix, onlyData: true });
|
||||
upload = api.uploadContent({} as File);
|
||||
expect(api.cancelUpload(upload)).toBeTruthy();
|
||||
expect(xhr.abort).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should return false when `cancelUpload` is called but unsuccessful", async () => {
|
||||
const api = new MatrixHttpApi(new TypedEventEmitter<any, any>(), { baseUrl, prefix });
|
||||
const api = new MatrixHttpApi(new TypedEventEmitter<any, any>(), { baseUrl, prefix, onlyData: true });
|
||||
upload = api.uploadContent({} as File);
|
||||
|
||||
xhr.readyState = DONE;
|
||||
@@ -220,7 +222,7 @@ describe("MatrixHttpApi", () => {
|
||||
});
|
||||
|
||||
it("should return active uploads in `getCurrentUploads`", () => {
|
||||
const api = new MatrixHttpApi(new TypedEventEmitter<any, any>(), { baseUrl, prefix });
|
||||
const api = new MatrixHttpApi(new TypedEventEmitter<any, any>(), { baseUrl, prefix, onlyData: true });
|
||||
upload = api.uploadContent({} as File);
|
||||
expect(api.getCurrentUploads().find((u) => u.promise === upload)).toBeTruthy();
|
||||
api.cancelUpload(upload);
|
||||
@@ -228,7 +230,12 @@ describe("MatrixHttpApi", () => {
|
||||
});
|
||||
|
||||
it("should return expected object from `getContentUri`", () => {
|
||||
const api = new MatrixHttpApi(new TypedEventEmitter<any, any>(), { baseUrl, prefix, accessToken: "token" });
|
||||
const api = new MatrixHttpApi(new TypedEventEmitter<any, any>(), {
|
||||
baseUrl,
|
||||
prefix,
|
||||
accessToken: "token",
|
||||
onlyData: true,
|
||||
});
|
||||
expect(api.getContentUri()).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -3597,24 +3597,6 @@ describe("MatrixClient", function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe("getAuthIssuer", () => {
|
||||
it("should use unstable prefix", async () => {
|
||||
httpLookups = [
|
||||
{
|
||||
method: "GET",
|
||||
path: `/auth_issuer`,
|
||||
data: {
|
||||
issuer: "https://issuer/",
|
||||
},
|
||||
prefix: "/_matrix/client/unstable/org.matrix.msc2965",
|
||||
},
|
||||
];
|
||||
|
||||
await expect(client.getAuthIssuer()).resolves.toEqual({ issuer: "https://issuer/" });
|
||||
expect(httpLookups.length).toEqual(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe("getAuthMetadata", () => {
|
||||
beforeEach(() => {
|
||||
fetchMock.mockReset();
|
||||
|
||||
@@ -379,7 +379,9 @@ describe("MatrixEvent", () => {
|
||||
expect(encryptedEvent.isBeingDecrypted()).toBeFalsy();
|
||||
expect(encryptedEvent.isDecryptionFailure()).toBeTruthy();
|
||||
expect(encryptedEvent.decryptionFailureReason).toEqual(DecryptionFailureCode.UNKNOWN_ERROR);
|
||||
expect(encryptedEvent.isEncryptedDisabledForUnverifiedDevices).toBeFalsy();
|
||||
expect(encryptedEvent.decryptionFailureReason).not.toBe(
|
||||
DecryptionFailureCode.MEGOLM_KEY_WITHHELD_FOR_UNVERIFIED_DEVICE,
|
||||
);
|
||||
expect(encryptedEvent.getContent()).toEqual({
|
||||
msgtype: "m.bad.encrypted",
|
||||
body: "** Unable to decrypt: Error: test error **",
|
||||
@@ -403,7 +405,9 @@ describe("MatrixEvent", () => {
|
||||
expect(encryptedEvent.decryptionFailureReason).toEqual(
|
||||
DecryptionFailureCode.MEGOLM_UNKNOWN_INBOUND_SESSION_ID,
|
||||
);
|
||||
expect(encryptedEvent.isEncryptedDisabledForUnverifiedDevices).toBeFalsy();
|
||||
expect(encryptedEvent.decryptionFailureReason).not.toBe(
|
||||
DecryptionFailureCode.MEGOLM_KEY_WITHHELD_FOR_UNVERIFIED_DEVICE,
|
||||
);
|
||||
expect(encryptedEvent.getContent()).toEqual({
|
||||
msgtype: "m.bad.encrypted",
|
||||
body: "** Unable to decrypt: DecryptionError: uisi **",
|
||||
@@ -427,7 +431,9 @@ describe("MatrixEvent", () => {
|
||||
expect(encryptedEvent.isEncrypted()).toBeTruthy();
|
||||
expect(encryptedEvent.isBeingDecrypted()).toBeFalsy();
|
||||
expect(encryptedEvent.isDecryptionFailure()).toBeTruthy();
|
||||
expect(encryptedEvent.isEncryptedDisabledForUnverifiedDevices).toBeTruthy();
|
||||
expect(encryptedEvent.decryptionFailureReason).toBe(
|
||||
DecryptionFailureCode.MEGOLM_KEY_WITHHELD_FOR_UNVERIFIED_DEVICE,
|
||||
);
|
||||
expect(encryptedEvent.getContent()).toEqual({
|
||||
msgtype: "m.bad.encrypted",
|
||||
body: "** Unable to decrypt: DecryptionError: The sender has disabled encrypting to unverified devices. **",
|
||||
|
||||
@@ -27,11 +27,6 @@ import { type EventType, type RelationType, type RoomType } from "./event.ts";
|
||||
/* eslint-disable camelcase */
|
||||
|
||||
export interface IJoinRoomOpts {
|
||||
/**
|
||||
* @deprecated does nothing
|
||||
*/
|
||||
syncRoom?: boolean;
|
||||
|
||||
/**
|
||||
* If the caller has a keypair 3pid invite, the signing URL is passed in this parameter.
|
||||
*/
|
||||
|
||||
@@ -22,9 +22,3 @@ import { type AuthDict } from "../interactive-auth.ts";
|
||||
export type UIARequest<T> = T & {
|
||||
auth?: AuthDict;
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper type to represent HTTP response body for a UIA enabled endpoint
|
||||
* @deprecated - a successful response for a UIA enabled endpoint is no different, UIA is signalled via an error
|
||||
*/
|
||||
export type UIAResponse<T> = T;
|
||||
|
||||
@@ -1085,20 +1085,6 @@ export enum ClientEvent {
|
||||
*/
|
||||
ClientWellKnown = "WellKnown.client",
|
||||
ReceivedVoipEvent = "received_voip_event",
|
||||
/**
|
||||
* @deprecated This event is not supported anymore.
|
||||
*
|
||||
* Fires if a to-device event is received that cannot be decrypted.
|
||||
* Encrypted to-device events will (generally) use plain Olm encryption,
|
||||
* in which case decryption failures are fatal: the event will never be
|
||||
* decryptable, unlike Megolm encrypted events where the key may simply
|
||||
* arrive later.
|
||||
*
|
||||
* An undecryptable to-device event is therefore likely to indicate problems.
|
||||
*
|
||||
* The payload is the undecyptable to-device event
|
||||
*/
|
||||
UndecryptableToDeviceEvent = "toDeviceEvent.undecryptable",
|
||||
TurnServers = "turnServers",
|
||||
TurnServersError = "turnServers.error",
|
||||
}
|
||||
@@ -1163,7 +1149,6 @@ export type ClientEventHandlerMap = {
|
||||
[ClientEvent.Event]: (event: MatrixEvent) => void;
|
||||
[ClientEvent.ToDeviceEvent]: (event: MatrixEvent) => void;
|
||||
[ClientEvent.ReceivedToDeviceMessage]: (payload: ReceivedToDeviceMessage) => void;
|
||||
[ClientEvent.UndecryptableToDeviceEvent]: (event: MatrixEvent) => void;
|
||||
[ClientEvent.AccountData]: (event: MatrixEvent, lastEvent?: MatrixEvent) => void;
|
||||
[ClientEvent.Room]: (room: Room) => void;
|
||||
[ClientEvent.DeleteRoom]: (roomId: string) => void;
|
||||
@@ -6862,9 +6847,7 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
|
||||
*
|
||||
* @param opts - options object
|
||||
*
|
||||
* @returns Promise which resolves to response object, as
|
||||
* determined by this.opts.onlyData, opts.rawResponse, and
|
||||
* opts.onlyContentUri. Rejects with an error (usually a MatrixError).
|
||||
* @returns Promise which resolves to response object, or rejects with an error (usually a MatrixError).
|
||||
*/
|
||||
public uploadContent(file: FileType, opts?: UploadOpts): Promise<UploadResponse> {
|
||||
return this.http.uploadContent(file, opts);
|
||||
@@ -8417,21 +8400,6 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the OIDC issuer responsible for authentication on this server, if any
|
||||
* @returns Resolves: A promise of an object containing the OIDC issuer if configured
|
||||
* @returns Rejects: when the request fails (module:http-api.MatrixError)
|
||||
* @experimental - part of MSC2965
|
||||
* @deprecated in favour of getAuthMetadata
|
||||
*/
|
||||
public async getAuthIssuer(): Promise<{
|
||||
issuer: string;
|
||||
}> {
|
||||
return this.http.request(Method.Get, "/auth_issuer", undefined, undefined, {
|
||||
prefix: ClientPrefix.Unstable + "/org.matrix.msc2965",
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Discover and validate delegated auth configuration
|
||||
* - delegated auth issuer openid-configuration is reachable
|
||||
@@ -8451,7 +8419,12 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
|
||||
});
|
||||
} catch (e) {
|
||||
if (e instanceof MatrixError && e.errcode === "M_UNRECOGNIZED") {
|
||||
const { issuer } = await this.getAuthIssuer();
|
||||
// Fall back to older variant of MSC2965
|
||||
const { issuer } = await this.http.request<{
|
||||
issuer: string;
|
||||
}>(Method.Get, "/auth_issuer", undefined, undefined, {
|
||||
prefix: ClientPrefix.Unstable + "/org.matrix.msc2965",
|
||||
});
|
||||
return discoverAndValidateOIDCIssuerWellKnown(issuer);
|
||||
}
|
||||
throw e;
|
||||
|
||||
@@ -468,16 +468,6 @@ export interface CryptoApi {
|
||||
*/
|
||||
getVerificationRequestsToDeviceInProgress(userId: string): VerificationRequest[];
|
||||
|
||||
/**
|
||||
* Finds a DM verification request that is already in progress for the given room id
|
||||
*
|
||||
* @param roomId - the room to use for verification
|
||||
*
|
||||
* @returns the VerificationRequest that is in progress, if any
|
||||
* @deprecated prefer `userId` parameter variant.
|
||||
*/
|
||||
findVerificationRequestDMInProgress(roomId: string): VerificationRequest | undefined;
|
||||
|
||||
/**
|
||||
* Finds a DM verification request that is already in progress for the given room and user.
|
||||
*
|
||||
@@ -545,18 +535,6 @@ export interface CryptoApi {
|
||||
*/
|
||||
getSessionBackupPrivateKey(): Promise<Uint8Array | null>;
|
||||
|
||||
/**
|
||||
* Store the backup decryption key.
|
||||
*
|
||||
* This should be called if the client has received the key from another device via secret sharing (gossiping).
|
||||
* It is the responsability of the caller to check that the decryption key is valid for the current backup version.
|
||||
*
|
||||
* @param key - the backup decryption key
|
||||
*
|
||||
* @deprecated prefer the variant with a `version` parameter.
|
||||
*/
|
||||
storeSessionBackupPrivateKey(key: Uint8Array): Promise<void>;
|
||||
|
||||
/**
|
||||
* Store the backup decryption key.
|
||||
*
|
||||
@@ -801,45 +779,6 @@ export enum DecryptionFailureCode {
|
||||
|
||||
/** Unknown or unclassified error. */
|
||||
UNKNOWN_ERROR = "UNKNOWN_ERROR",
|
||||
|
||||
/** @deprecated only used in legacy crypto */
|
||||
MEGOLM_BAD_ROOM = "MEGOLM_BAD_ROOM",
|
||||
|
||||
/** @deprecated only used in legacy crypto */
|
||||
MEGOLM_MISSING_FIELDS = "MEGOLM_MISSING_FIELDS",
|
||||
|
||||
/** @deprecated only used in legacy crypto */
|
||||
OLM_DECRYPT_GROUP_MESSAGE_ERROR = "OLM_DECRYPT_GROUP_MESSAGE_ERROR",
|
||||
|
||||
/** @deprecated only used in legacy crypto */
|
||||
OLM_BAD_ENCRYPTED_MESSAGE = "OLM_BAD_ENCRYPTED_MESSAGE",
|
||||
|
||||
/** @deprecated only used in legacy crypto */
|
||||
OLM_BAD_RECIPIENT = "OLM_BAD_RECIPIENT",
|
||||
|
||||
/** @deprecated only used in legacy crypto */
|
||||
OLM_BAD_RECIPIENT_KEY = "OLM_BAD_RECIPIENT_KEY",
|
||||
|
||||
/** @deprecated only used in legacy crypto */
|
||||
OLM_BAD_ROOM = "OLM_BAD_ROOM",
|
||||
|
||||
/** @deprecated only used in legacy crypto */
|
||||
OLM_BAD_SENDER_CHECK_FAILED = "OLM_BAD_SENDER_CHECK_FAILED",
|
||||
|
||||
/** @deprecated only used in legacy crypto */
|
||||
OLM_BAD_SENDER = "OLM_BAD_SENDER",
|
||||
|
||||
/** @deprecated only used in legacy crypto */
|
||||
OLM_FORWARDED_MESSAGE = "OLM_FORWARDED_MESSAGE",
|
||||
|
||||
/** @deprecated only used in legacy crypto */
|
||||
OLM_MISSING_CIPHERTEXT = "OLM_MISSING_CIPHERTEXT",
|
||||
|
||||
/** @deprecated only used in legacy crypto */
|
||||
OLM_NOT_INCLUDED_IN_RECIPIENTS = "OLM_NOT_INCLUDED_IN_RECIPIENTS",
|
||||
|
||||
/** @deprecated only used in legacy crypto */
|
||||
UNKNOWN_ENCRYPTION_ALGORITHM = "UNKNOWN_ENCRYPTION_ALGORITHM",
|
||||
}
|
||||
|
||||
/** Base {@link DeviceIsolationMode} kind. */
|
||||
@@ -1104,8 +1043,6 @@ export type ImportRoomKeyProgressData = ImportRoomKeyFetchProgress | ImportRoomK
|
||||
export interface ImportRoomKeysOpts {
|
||||
/** Reports ongoing progress of the import process. Can be used for feedback. */
|
||||
progressCallback?: (stage: ImportRoomKeyProgressData) => void;
|
||||
/** @deprecated the rust SDK will always such imported keys as untrusted */
|
||||
untrusted?: boolean;
|
||||
/** @deprecated not useful externally */
|
||||
source?: string;
|
||||
}
|
||||
@@ -1193,13 +1130,6 @@ export interface CryptoCallbacks {
|
||||
name: string,
|
||||
) => Promise<[string, Uint8Array] | null>;
|
||||
|
||||
/** @deprecated: unused with the Rust crypto stack. */
|
||||
getCrossSigningKey?: (keyType: string, pubKey: string) => Promise<Uint8Array | null>;
|
||||
/** @deprecated: unused with the Rust crypto stack. */
|
||||
saveCrossSigningKeys?: (keys: Record<string, Uint8Array>) => void;
|
||||
/** @deprecated: unused with the Rust crypto stack. */
|
||||
shouldUpgradeDeviceVerifications?: (users: Record<string, any>) => Promise<string[]>;
|
||||
|
||||
/**
|
||||
* Called by {@link CryptoApi.bootstrapSecretStorage} when a new default secret storage key is created.
|
||||
*
|
||||
@@ -1211,24 +1141,6 @@ export interface CryptoCallbacks {
|
||||
* @param key - private key to store
|
||||
*/
|
||||
cacheSecretStorageKey?: (keyId: string, keyInfo: SecretStorageKeyDescription, key: Uint8Array) => void;
|
||||
|
||||
/** @deprecated: unused with the Rust crypto stack. */
|
||||
onSecretRequested?: (
|
||||
userId: string,
|
||||
deviceId: string,
|
||||
requestId: string,
|
||||
secretName: string,
|
||||
deviceTrust: DeviceVerificationStatus,
|
||||
) => Promise<string | undefined>;
|
||||
|
||||
/** @deprecated: unused with the Rust crypto stack. */
|
||||
getDehydrationKey?: (
|
||||
keyInfo: SecretStorageKeyDescription,
|
||||
checkFunc: (key: Uint8Array) => void,
|
||||
) => Promise<Uint8Array>;
|
||||
|
||||
/** @deprecated: unused with the Rust crypto stack. */
|
||||
getBackupKey?: () => Promise<Uint8Array>;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1243,13 +1155,6 @@ export interface CreateSecretStorageOpts {
|
||||
*/
|
||||
createSecretStorageKey?: () => Promise<GeneratedSecretStorageKey>;
|
||||
|
||||
/**
|
||||
* The current key backup object. If passed,
|
||||
* the passphrase and recovery key from this backup will be used.
|
||||
* @deprecated Not used by the Rust crypto stack.
|
||||
*/
|
||||
keyBackupInfo?: KeyBackupInfo;
|
||||
|
||||
/**
|
||||
* If true, a new key backup version will be
|
||||
* created and the private key stored in the new SSSS store. Ignored if keyBackupInfo
|
||||
@@ -1261,18 +1166,6 @@ export interface CreateSecretStorageOpts {
|
||||
* Reset even if keys already exist.
|
||||
*/
|
||||
setupNewSecretStorage?: boolean;
|
||||
|
||||
/**
|
||||
* Function called to get the user's current key backup passphrase.
|
||||
*
|
||||
* Should return a promise that resolves with a Uint8Array
|
||||
* containing the key, or rejects if the key cannot be obtained.
|
||||
*
|
||||
* Only used when the client has existing key backup, but no secret storage.
|
||||
*
|
||||
* @deprecated Not used by the Rust crypto stack.
|
||||
*/
|
||||
getKeyBackupPassphrase?: () => Promise<Uint8Array>;
|
||||
}
|
||||
|
||||
/** Types of cross-signing key */
|
||||
|
||||
@@ -114,25 +114,6 @@ export interface VerificationRequest
|
||||
*/
|
||||
cancel(params?: { reason?: string; code?: string }): Promise<void>;
|
||||
|
||||
/**
|
||||
* Create a {@link Verifier} to do this verification via a particular method.
|
||||
*
|
||||
* If a verifier has already been created for this request, returns that verifier.
|
||||
*
|
||||
* This does *not* send the `m.key.verification.start` event - to do so, call {@link Verifier.verify} on the
|
||||
* returned verifier.
|
||||
*
|
||||
* If no previous events have been sent, pass in `targetDevice` to set who to direct this request to.
|
||||
*
|
||||
* @param method - the name of the verification method to use.
|
||||
* @param targetDevice - details of where to send the request to.
|
||||
*
|
||||
* @returns The verifier which will do the actual verification.
|
||||
*
|
||||
* @deprecated Use {@link VerificationRequest#startVerification} instead.
|
||||
*/
|
||||
beginKeyVerification(method: string, targetDevice?: { userId?: string; deviceId?: string }): Verifier;
|
||||
|
||||
/**
|
||||
* Send an `m.key.verification.start` event to start verification via a particular method.
|
||||
*
|
||||
@@ -163,15 +144,6 @@ export interface VerificationRequest
|
||||
*/
|
||||
get verifier(): Verifier | undefined;
|
||||
|
||||
/**
|
||||
* Get the data for a QR code allowing the other device to verify this one, if it supports it.
|
||||
*
|
||||
* Only set after a .ready if the other party can scan a QR code, otherwise undefined.
|
||||
*
|
||||
* @deprecated Not supported in Rust Crypto. Use {@link VerificationRequest#generateQRCode} instead.
|
||||
*/
|
||||
getQRCodeBytes(): Uint8ClampedArray | undefined;
|
||||
|
||||
/**
|
||||
* Generate the data for a QR code allowing the other device to verify this one, if it supports it.
|
||||
*
|
||||
|
||||
@@ -25,9 +25,6 @@ export interface MapperOpts {
|
||||
preventReEmit?: boolean;
|
||||
// decrypt event proactively
|
||||
decrypt?: boolean;
|
||||
|
||||
/** @deprecated no longer used */
|
||||
toDevice?: boolean;
|
||||
}
|
||||
|
||||
export function eventMapperFor(client: MatrixClient, options: MapperOpts): EventMapper {
|
||||
|
||||
@@ -34,22 +34,6 @@ import { anySignal, parseErrorResponse, timeoutSignal } from "./utils.ts";
|
||||
import { type QueryDict } from "../utils.ts";
|
||||
import { TokenRefresher, TokenRefreshOutcome } from "./refresh.ts";
|
||||
|
||||
interface TypedResponse<T> extends Response {
|
||||
json(): Promise<T>;
|
||||
}
|
||||
|
||||
/**
|
||||
* The type returned by {@link FetchHttpApi.request}, etc.
|
||||
*
|
||||
* If {@link IHttpOpts.onlyData} is unset or false, then the request methods return a
|
||||
* {@link https://developer.mozilla.org/en-US/docs/Web/API/Response Response} object,
|
||||
* which we abstract via `TypedResponse`. Otherwise, we just cast it to `T`.
|
||||
*
|
||||
* @typeParam T - The type (specified by the application on the request method) that we will cast the response to.
|
||||
* @typeParam O - The type of the options object on the {@link FetchHttpApi} instance.
|
||||
*/
|
||||
export type ResponseType<T, O extends IHttpOpts> = O extends { onlyData: true } | undefined ? T : TypedResponse<T>;
|
||||
|
||||
export class FetchHttpApi<O extends IHttpOpts> {
|
||||
private abortController = new AbortController();
|
||||
private readonly tokenRefresher: TokenRefresher;
|
||||
@@ -59,7 +43,9 @@ export class FetchHttpApi<O extends IHttpOpts> {
|
||||
public readonly opts: O,
|
||||
) {
|
||||
checkObjectHasKeys(opts, ["baseUrl", "prefix"]);
|
||||
opts.onlyData = !!opts.onlyData;
|
||||
if (!opts.onlyData) {
|
||||
throw new Error("Constructing FetchHttpApi without `onlyData=true` is no longer supported.");
|
||||
}
|
||||
opts.useAuthorizationHeader = opts.useAuthorizationHeader ?? true;
|
||||
|
||||
this.tokenRefresher = new TokenRefresher(opts);
|
||||
@@ -91,7 +77,7 @@ export class FetchHttpApi<O extends IHttpOpts> {
|
||||
params: Record<string, string | string[]> | undefined,
|
||||
prefix: string,
|
||||
accessToken?: string,
|
||||
): Promise<ResponseType<T, O>> {
|
||||
): Promise<T> {
|
||||
if (!this.opts.idBaseUrl) {
|
||||
throw new Error("No identity server base URL set");
|
||||
}
|
||||
@@ -132,17 +118,8 @@ export class FetchHttpApi<O extends IHttpOpts> {
|
||||
* When `paramOpts.doNotAttemptTokenRefresh` is true, token refresh will not be attempted
|
||||
* when an expired token is encountered. Used to only attempt token refresh once.
|
||||
*
|
||||
* @returns Promise which resolves to
|
||||
* ```
|
||||
* {
|
||||
* data: {Object},
|
||||
* headers: {Object},
|
||||
* code: {Number},
|
||||
* }
|
||||
* ```
|
||||
* If `onlyData` is set, this will resolve to the `data` object only.
|
||||
* @returns Rejects with an error if a problem occurred.
|
||||
* This includes network problems and Matrix-specific error JSON.
|
||||
* @returns The parsed response.
|
||||
* @throws Error if a problem occurred. This includes network problems and Matrix-specific error JSON.
|
||||
*/
|
||||
public authedRequest<T>(
|
||||
method: Method,
|
||||
@@ -150,7 +127,7 @@ export class FetchHttpApi<O extends IHttpOpts> {
|
||||
queryParams: QueryDict = {},
|
||||
body?: Body,
|
||||
paramOpts: IRequestOpts = {},
|
||||
): Promise<ResponseType<T, O>> {
|
||||
): Promise<T> {
|
||||
return this.doAuthedRequest<T>(1, method, path, queryParams, body, paramOpts);
|
||||
}
|
||||
|
||||
@@ -162,7 +139,7 @@ export class FetchHttpApi<O extends IHttpOpts> {
|
||||
queryParams: QueryDict,
|
||||
body?: Body,
|
||||
paramOpts: IRequestOpts = {},
|
||||
): Promise<ResponseType<T, O>> {
|
||||
): Promise<T> {
|
||||
// avoid mutating paramOpts so they can be used on retry
|
||||
const opts = deepCopy(paramOpts);
|
||||
// we have to manually copy the abortSignal over as it is not a plain object
|
||||
@@ -228,18 +205,8 @@ export class FetchHttpApi<O extends IHttpOpts> {
|
||||
*
|
||||
* @param opts - additional options
|
||||
*
|
||||
* @returns Promise which resolves to
|
||||
* ```
|
||||
* {
|
||||
* data: {Object},
|
||||
* headers: {Object},
|
||||
* code: {Number},
|
||||
* }
|
||||
* ```
|
||||
* If `onlyData</code> is set, this will resolve to the <code>data`
|
||||
* object only.
|
||||
* @returns Rejects with an error if a problem
|
||||
* occurred. This includes network problems and Matrix-specific error JSON.
|
||||
* @returns The parsed response.
|
||||
* @throws Error if a problem occurred. This includes network problems and Matrix-specific error JSON.
|
||||
*/
|
||||
public request<T>(
|
||||
method: Method,
|
||||
@@ -247,7 +214,7 @@ export class FetchHttpApi<O extends IHttpOpts> {
|
||||
queryParams?: QueryDict,
|
||||
body?: Body,
|
||||
opts?: IRequestOpts,
|
||||
): Promise<ResponseType<T, O>> {
|
||||
): Promise<T> {
|
||||
const fullUri = this.getUrl(path, queryParams, opts?.prefix, opts?.baseUrl);
|
||||
return this.requestOtherUrl<T>(method, fullUri, body, opts);
|
||||
}
|
||||
@@ -261,17 +228,15 @@ export class FetchHttpApi<O extends IHttpOpts> {
|
||||
*
|
||||
* @param opts - additional options
|
||||
*
|
||||
* @returns Promise which resolves to data unless `onlyData` is specified as false,
|
||||
* where the resolved value will be a fetch Response object.
|
||||
* @returns Rejects with an error if a problem
|
||||
* occurred. This includes network problems and Matrix-specific error JSON.
|
||||
* @returns The parsed response.
|
||||
* @throws Error if a problem occurred. This includes network problems and Matrix-specific error JSON.
|
||||
*/
|
||||
public async requestOtherUrl<T>(
|
||||
method: Method,
|
||||
url: URL | string,
|
||||
body?: Body,
|
||||
opts: BaseRequestOpts = {},
|
||||
): Promise<ResponseType<T, O>> {
|
||||
): Promise<T> {
|
||||
if (opts.json !== undefined && opts.rawResponseBody !== undefined) {
|
||||
throw new Error("Invalid call to `FetchHttpApi` sets both `opts.json` and `opts.rawResponseBody`");
|
||||
}
|
||||
@@ -349,14 +314,12 @@ export class FetchHttpApi<O extends IHttpOpts> {
|
||||
throw parseErrorResponse(res, await res.text());
|
||||
}
|
||||
|
||||
if (!this.opts.onlyData) {
|
||||
return res as ResponseType<T, O>;
|
||||
} else if (opts.rawResponseBody) {
|
||||
return (await res.blob()) as ResponseType<T, O>;
|
||||
if (opts.rawResponseBody) {
|
||||
return (await res.blob()) as T;
|
||||
} else if (jsonResponse) {
|
||||
return await res.json();
|
||||
} else {
|
||||
return (await res.text()) as ResponseType<T, O>;
|
||||
return (await res.text()) as T;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -48,9 +48,7 @@ export class MatrixHttpApi<O extends IHttpOpts> extends FetchHttpApi<O> {
|
||||
*
|
||||
* @param opts - options object
|
||||
*
|
||||
* @returns Promise which resolves to response object, as
|
||||
* determined by this.opts.onlyData, opts.rawResponse, and
|
||||
* opts.onlyContentUri. Rejects with an error (usually a MatrixError).
|
||||
* @returns Promise which resolves to response object, or rejects with an error (usually a MatrixError).
|
||||
*/
|
||||
public uploadContent(file: FileType, opts: UploadOpts = {}): Promise<UploadResponse> {
|
||||
const includeFilename = opts.includeFilename ?? true;
|
||||
@@ -149,11 +147,7 @@ export class MatrixHttpApi<O extends IHttpOpts> extends FetchHttpApi<O> {
|
||||
prefix: MediaPrefix.V3,
|
||||
headers,
|
||||
abortSignal: abortController.signal,
|
||||
})
|
||||
.then((response) => {
|
||||
return this.opts.onlyData ? <UploadResponse>response : response.json();
|
||||
})
|
||||
.then(uploadResolvers.resolve, uploadResolvers.reject);
|
||||
}).then(uploadResolvers.resolve, uploadResolvers.reject);
|
||||
}
|
||||
|
||||
// remove the upload from the list on completion
|
||||
|
||||
@@ -69,10 +69,7 @@ export interface IHttpOpts {
|
||||
tokenRefreshFunction?: TokenRefreshFunction;
|
||||
useAuthorizationHeader?: boolean; // defaults to true
|
||||
|
||||
/**
|
||||
* Normally, methods in `FetchHttpApi` will return a {@link https://developer.mozilla.org/en-US/docs/Web/API/Response Response} object.
|
||||
* If this is set to `true`, they instead return the response body.
|
||||
*/
|
||||
/** For historical reasons, must be set to `true`. Will eventually be removed. */
|
||||
onlyData?: boolean;
|
||||
|
||||
localTimeoutMs?: number;
|
||||
@@ -103,11 +100,10 @@ export interface BaseRequestOpts extends Pick<RequestInit, "priority"> {
|
||||
*
|
||||
* * Set `Accept: application/json` in the request headers (again, unless overridden by {@link headers}).
|
||||
*
|
||||
* * If `IHTTPOpts.onlyData` is set to `true` on the `FetchHttpApi` instance, parse the response as
|
||||
* JSON and return the parsed response.
|
||||
* * Parse the response as JSON and return the parsed response.
|
||||
*
|
||||
* Setting this to `false` inhibits all three behaviors, and (if `IHTTPOpts.onlyData` is set to `true`) the response
|
||||
* is instead parsed as a UTF-8 string. It defaults to `true`, unless {@link rawResponseBody} is set.
|
||||
* Setting this to `false` inhibits all three behaviors, and the response is instead parsed as a UTF-8 string. It
|
||||
* defaults to `true`, unless {@link rawResponseBody} is set.
|
||||
*
|
||||
* @deprecated Instead of setting this to `false`, set {@link rawResponseBody} to `true`.
|
||||
*/
|
||||
@@ -118,9 +114,8 @@ export interface BaseRequestOpts extends Pick<RequestInit, "priority"> {
|
||||
*
|
||||
* * Inhibits the automatic addition of `Accept: application/json` in the request headers.
|
||||
*
|
||||
* * Assuming `IHTTPOpts.onlyData` is set to `true` on the `FetchHttpApi` instance, causes the
|
||||
* raw response to be returned as a {@link https://developer.mozilla.org/en-US/docs/Web/API/Blob|Blob}
|
||||
* instead of parsing it as `json`.
|
||||
* * Causes the raw response to be returned as a {@link https://developer.mozilla.org/en-US/docs/Web/API/Blob|Blob}
|
||||
* instead of parsing it as JSON.
|
||||
*/
|
||||
rawResponseBody?: boolean;
|
||||
}
|
||||
|
||||
@@ -109,8 +109,6 @@ export interface MembershipConfig {
|
||||
* This is what goes into the m.rtc.member event expiry field and is typically set to a number of hours.
|
||||
*/
|
||||
membershipEventExpiryMs?: number;
|
||||
/** @deprecated renamed to `membershipEventExpiryMs`*/
|
||||
membershipExpiryTimeout?: number;
|
||||
|
||||
/**
|
||||
* The time in (in milliseconds) which the manager will prematurely send the updated state event before the membership `expires` time to make sure it
|
||||
@@ -122,23 +120,17 @@ export interface MembershipConfig {
|
||||
* This value does not have an effect on the value of `SessionMembershipData.expires`.
|
||||
*/
|
||||
membershipEventExpiryHeadroomMs?: number;
|
||||
/** @deprecated renamed to `membershipEventExpiryHeadroomMs`*/
|
||||
membershipExpiryTimeoutHeadroom?: number;
|
||||
|
||||
/**
|
||||
* The timeout (in milliseconds) with which the deleayed leave event on the server is configured.
|
||||
* After this time the server will set the event to the disconnected stat if it has not received a keep-alive from the client.
|
||||
*/
|
||||
delayedLeaveEventDelayMs?: number;
|
||||
/** @deprecated renamed to `delayedLeaveEventDelayMs`*/
|
||||
membershipServerSideExpiryTimeout?: number;
|
||||
|
||||
/**
|
||||
* The interval (in milliseconds) in which the client will send membership keep-alives to the server.
|
||||
*/
|
||||
delayedLeaveEventRestartMs?: number;
|
||||
/** @deprecated renamed to `delayedLeaveEventRestartMs`*/
|
||||
membershipKeepAlivePeriod?: number;
|
||||
|
||||
/**
|
||||
* The maximum number of retries that the manager will do for delayed event sending/updating and state event sending when a server rate limit has been hit.
|
||||
@@ -156,9 +148,6 @@ export interface MembershipConfig {
|
||||
*/
|
||||
networkErrorRetryMs?: number;
|
||||
|
||||
/** @deprecated renamed to `networkErrorRetryMs`*/
|
||||
callMemberEventRetryDelayMinimum?: number;
|
||||
|
||||
/**
|
||||
* If true, use the new to-device transport for sending encryption keys.
|
||||
*/
|
||||
|
||||
@@ -362,35 +362,22 @@ export class MembershipManager
|
||||
private delayedLeaveEventDelayMsOverride?: number;
|
||||
|
||||
private get networkErrorRetryMs(): number {
|
||||
return this.joinConfig?.networkErrorRetryMs ?? this.joinConfig?.callMemberEventRetryDelayMinimum ?? 3_000;
|
||||
return this.joinConfig?.networkErrorRetryMs ?? 3_000;
|
||||
}
|
||||
private get membershipEventExpiryMs(): number {
|
||||
return (
|
||||
this.joinConfig?.membershipEventExpiryMs ??
|
||||
this.joinConfig?.membershipExpiryTimeout ??
|
||||
DEFAULT_EXPIRE_DURATION
|
||||
);
|
||||
return this.joinConfig?.membershipEventExpiryMs ?? DEFAULT_EXPIRE_DURATION;
|
||||
}
|
||||
private get membershipEventExpiryHeadroomMs(): number {
|
||||
return (
|
||||
this.joinConfig?.membershipEventExpiryHeadroomMs ??
|
||||
this.joinConfig?.membershipExpiryTimeoutHeadroom ??
|
||||
5_000
|
||||
);
|
||||
return this.joinConfig?.membershipEventExpiryHeadroomMs ?? 5_000;
|
||||
}
|
||||
private computeNextExpiryActionTs(iteration: number): number {
|
||||
return this.state.startTime + this.membershipEventExpiryMs * iteration - this.membershipEventExpiryHeadroomMs;
|
||||
}
|
||||
private get delayedLeaveEventDelayMs(): number {
|
||||
return (
|
||||
this.delayedLeaveEventDelayMsOverride ??
|
||||
this.joinConfig?.delayedLeaveEventDelayMs ??
|
||||
this.joinConfig?.membershipServerSideExpiryTimeout ??
|
||||
8_000
|
||||
);
|
||||
return this.delayedLeaveEventDelayMsOverride ?? this.joinConfig?.delayedLeaveEventDelayMs ?? 8_000;
|
||||
}
|
||||
private get delayedLeaveEventRestartMs(): number {
|
||||
return this.joinConfig?.delayedLeaveEventRestartMs ?? this.joinConfig?.membershipKeepAlivePeriod ?? 5_000;
|
||||
return this.joinConfig?.delayedLeaveEventRestartMs ?? 5_000;
|
||||
}
|
||||
private get maximumRateLimitRetryCount(): number {
|
||||
return this.joinConfig?.maximumRateLimitRetryCount ?? 10;
|
||||
|
||||
@@ -822,16 +822,6 @@ export class MatrixEvent extends TypedEventEmitter<MatrixEventEmittedEvents, Mat
|
||||
return this._decryptionFailureReason;
|
||||
}
|
||||
|
||||
/**
|
||||
* True if this event is an encrypted event which we failed to decrypt, the receiver's device is unverified and
|
||||
* the sender has disabled encrypting to unverified devices.
|
||||
*
|
||||
* @deprecated: Prefer `event.decryptionFailureReason === DecryptionFailureCode.MEGOLM_KEY_WITHHELD_FOR_UNVERIFIED_DEVICE`.
|
||||
*/
|
||||
public get isEncryptedDisabledForUnverifiedDevices(): boolean {
|
||||
return this.decryptionFailureReason === DecryptionFailureCode.MEGOLM_KEY_WITHHELD_FOR_UNVERIFIED_DEVICE;
|
||||
}
|
||||
|
||||
public shouldAttemptDecryption(): boolean {
|
||||
if (this.isRedacted()) return false;
|
||||
if (this.isBeingDecrypted()) return false;
|
||||
|
||||
@@ -504,7 +504,6 @@ export class Room extends ReadReceipt<RoomEmittedEvents, RoomEventHandlerMap> {
|
||||
this.pendingEventList = [];
|
||||
this.client.store.getPendingEvents(this.roomId).then((events) => {
|
||||
const mapper = this.client.getEventMapper({
|
||||
toDevice: false,
|
||||
decrypt: false,
|
||||
});
|
||||
events.forEach(async (serializedEvent: Partial<IEvent>) => {
|
||||
|
||||
12
src/utils.ts
12
src/utils.ts
@@ -435,18 +435,6 @@ export function immediate(): Promise<void> {
|
||||
export function isNullOrUndefined(val: any): boolean {
|
||||
return val === null || val === undefined;
|
||||
}
|
||||
/**
|
||||
* @deprecated use {@link PromiseWithResolvers} instead.
|
||||
*/
|
||||
export type IDeferred<T> = PromiseWithResolvers<T>;
|
||||
|
||||
/**
|
||||
* Creates a deferred promise. This is a promise that can be resolved or rejected.
|
||||
* @deprecated use {@link Promise.withResolvers} instead.
|
||||
*/
|
||||
export function defer<T = void>(): IDeferred<T> {
|
||||
return Promise.withResolvers<T>();
|
||||
}
|
||||
|
||||
export async function promiseMapSeries<T>(
|
||||
promises: Array<T | Promise<T>>,
|
||||
|
||||
Reference in New Issue
Block a user