Skip to content

Set minimum supported Matrix 1.1 version (drop legacy r0 versions) #3007

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 21 commits into from
Aug 14, 2023
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
This is the [Matrix](https://matrix.org) Client-Server SDK for JavaScript and TypeScript. This SDK can be run in a
browser or in Node.js.

#### Minimum Matrix server version: v1.1

The Matrix specification is constantly evolving - while this SDK aims for maximum backwards compatibility, it only
guarantees that a feature will be supported for at least 4 spec releases. For example, if a feature the js-sdk supports
is removed in v1.4 then the feature is _eligible_ for removal from the SDK when v1.8 is released. This SDK has no
Expand Down
92 changes: 78 additions & 14 deletions spec/integ/matrix-client-methods.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ describe("MatrixClient", function () {

it("should upload the file", function () {
httpBackend
.when("POST", "/_matrix/media/r0/upload")
.when("POST", "/_matrix/media/v3/upload")
.check(function (req) {
expect(req.rawData).toEqual(buf);
expect(req.queryParams?.filename).toEqual("hi.txt");
Expand Down Expand Up @@ -108,7 +108,7 @@ describe("MatrixClient", function () {

it("should parse errors into a MatrixError", function () {
httpBackend
.when("POST", "/_matrix/media/r0/upload")
.when("POST", "/_matrix/media/v3/upload")
.check(function (req) {
expect(req.rawData).toEqual(buf);
// @ts-ignore private property
Expand Down Expand Up @@ -1102,10 +1102,6 @@ describe("MatrixClient", function () {
submit_url: "https://foobar.matrix/_matrix/matrix",
};

httpBackend.when("GET", "/_matrix/client/versions").respond(200, {
versions: ["r0.6.0"],
});

const prom = client.requestRegisterEmailToken("bob@email", "secret", 1);
httpBackend
.when("POST", "/register/email/requestToken")
Expand All @@ -1126,10 +1122,6 @@ describe("MatrixClient", function () {
it("should supply an id_access_token", async () => {
const targetEmail = "[email protected]";

httpBackend.when("GET", "/_matrix/client/versions").respond(200, {
versions: ["r0.6.0"],
});

httpBackend
.when("POST", "/invite")
.check((req) => {
Expand Down Expand Up @@ -1165,10 +1157,6 @@ describe("MatrixClient", function () {
],
};

httpBackend.when("GET", "/_matrix/client/versions").respond(200, {
versions: ["r0.6.0"],
});

httpBackend
.when("POST", "/createRoom")
.check((req) => {
Expand Down Expand Up @@ -1652,6 +1640,82 @@ describe("MatrixClient", function () {
]);
});
});

describe("getFallbackAuthUrl", () => {
it("should return fallback url", () => {
expect(client.getFallbackAuthUrl("loginType", "authSessionId")).toMatchInlineSnapshot(
`"http://alice.localhost.test.server/_matrix/client/r0/auth/loginType/fallback/web?session=authSessionId"`,
);
});
});

describe("addThreePidOnly", () => {
it("should make expected POST request", async () => {
httpBackend
.when("POST", "/_matrix/client/r0/account/3pid/add")
.check(function (req) {
expect(req.data).toEqual({
client_secret: "secret",
sid: "sid",
});
expect(req.headers["Authorization"]).toBe("Bearer " + accessToken);
})
.respond(200, {});

await Promise.all([
client.addThreePidOnly({
client_secret: "secret",
sid: "sid",
}),
httpBackend.flushAllExpected(),
]);
});
});

describe("bindThreePid", () => {
it("should make expected POST request", async () => {
httpBackend
.when("POST", "/_matrix/client/r0/account/3pid/bind")
.check(function (req) {
expect(req.data).toEqual({
client_secret: "secret",
id_server: "server",
id_access_token: "token",
sid: "sid",
});
expect(req.headers["Authorization"]).toBe("Bearer " + accessToken);
})
.respond(200, {});

await Promise.all([
client.bindThreePid({
client_secret: "secret",
id_server: "server",
id_access_token: "token",
sid: "sid",
}),
httpBackend.flushAllExpected(),
]);
});
});

describe("unbindThreePid", () => {
it("should make expected POST request", async () => {
httpBackend
.when("POST", "/_matrix/client/r0/account/3pid/unbind")
.check(function (req) {
expect(req.data).toEqual({
medium: "email",
address: "[email protected]",
id_server: "identity.localhost",
});
expect(req.headers["Authorization"]).toBe("Bearer " + accessToken);
})
.respond(200, {});

await Promise.all([client.unbindThreePid("email", "[email protected]"), httpBackend.flushAllExpected()]);
});
});
});

function withThreadId(event: MatrixEvent, newThreadId: string): MatrixEvent {
Expand Down
4 changes: 0 additions & 4 deletions spec/integ/matrix-client-syncing.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -224,8 +224,6 @@ describe("MatrixClient syncing", () => {
});

it("should honour lazyLoadMembers if user is not a guest", () => {
client!.doesServerSupportLazyLoading = jest.fn().mockResolvedValue(true);

httpBackend!
.when("GET", "/sync")
.check((req) => {
Expand All @@ -242,8 +240,6 @@ describe("MatrixClient syncing", () => {
it("should not honour lazyLoadMembers if user is a guest", () => {
httpBackend!.expectedRequests = [];
httpBackend!.when("GET", "/versions").respond(200, {});
client!.doesServerSupportLazyLoading = jest.fn().mockResolvedValue(true);

httpBackend!
.when("GET", "/sync")
.check((req) => {
Expand Down
1 change: 0 additions & 1 deletion spec/test-utils/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,6 @@ export const mockClientMethodsEvents = () => ({
* Returns basic mocked client methods related to server support
*/
export const mockClientMethodsServer = (): Partial<Record<MethodLikeKeys<MatrixClient>, unknown>> => ({
doesServerSupportSeparateAddAndBind: jest.fn(),
getIdentityServerUrl: jest.fn(),
getHomeserverUrl: jest.fn(),
getCapabilities: jest.fn().mockReturnValue({}),
Expand Down
55 changes: 43 additions & 12 deletions spec/unit/autodiscovery.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ limitations under the License.
import fetchMock from "fetch-mock-jest";
import MockHttpBackend from "matrix-mock-request";

import { M_AUTHENTICATION } from "../../src";
import { AutoDiscoveryAction, M_AUTHENTICATION } from "../../src";
import { AutoDiscovery } from "../../src/autodiscovery";
import { OidcError } from "../../src/oidc/error";
import { makeDelegatedAuthConfig } from "../test-utils/oidc";
Expand Down Expand Up @@ -351,7 +351,7 @@ describe("AutoDiscovery", function () {
function () {
const httpBackend = getHttpBackend();
httpBackend.when("GET", "/_matrix/client/versions").respond(200, {
not_matrix_versions: ["r0.0.1"],
not_matrix_versions: ["v1.1"],
});
httpBackend.when("GET", "/.well-known/matrix/client").respond(200, {
"m.homeserver": {
Expand Down Expand Up @@ -388,7 +388,7 @@ describe("AutoDiscovery", function () {
expect(req.path).toEqual("https://example.org/_matrix/client/versions");
})
.respond(200, {
versions: ["r0.0.1"],
versions: ["v1.1"],
});
httpBackend.when("GET", "/.well-known/matrix/client").respond(200, {
"m.homeserver": {
Expand Down Expand Up @@ -428,7 +428,7 @@ describe("AutoDiscovery", function () {
expect(req.path).toEqual("https://chat.example.org/_matrix/client/versions");
})
.respond(200, {
versions: ["r0.0.1"],
versions: ["v1.1"],
});
httpBackend.when("GET", "/.well-known/matrix/client").respond(200, {
"m.homeserver": {
Expand Down Expand Up @@ -469,7 +469,7 @@ describe("AutoDiscovery", function () {
expect(req.path).toEqual("https://chat.example.org/_matrix/client/versions");
})
.respond(200, {
versions: ["r0.0.1"],
versions: ["v1.1"],
});
httpBackend.when("GET", "/.well-known/matrix/client").respond(200, {
"m.homeserver": {
Expand Down Expand Up @@ -515,7 +515,7 @@ describe("AutoDiscovery", function () {
expect(req.path).toEqual("https://chat.example.org/_matrix/client/versions");
})
.respond(200, {
versions: ["r0.0.1"],
versions: ["v1.1"],
});
httpBackend.when("GET", "/.well-known/matrix/client").respond(200, {
"m.homeserver": {
Expand Down Expand Up @@ -560,7 +560,7 @@ describe("AutoDiscovery", function () {
expect(req.path).toEqual("https://chat.example.org/_matrix/client/versions");
})
.respond(200, {
versions: ["r0.0.1"],
versions: ["v1.1"],
});
httpBackend.when("GET", "/.well-known/matrix/client").respond(200, {
"m.homeserver": {
Expand Down Expand Up @@ -606,7 +606,7 @@ describe("AutoDiscovery", function () {
expect(req.path).toEqual("https://chat.example.org/_matrix/client/versions");
})
.respond(200, {
versions: ["r0.0.1"],
versions: ["v1.1"],
});
httpBackend.when("GET", "/_matrix/identity/v2").respond(404, {});
httpBackend.when("GET", "/.well-known/matrix/client").respond(200, {
Expand Down Expand Up @@ -653,7 +653,7 @@ describe("AutoDiscovery", function () {
expect(req.path).toEqual("https://chat.example.org/_matrix/client/versions");
})
.respond(200, {
versions: ["r0.0.1"],
versions: ["v1.1"],
});
httpBackend.when("GET", "/_matrix/identity/v2").respond(500, {});
httpBackend.when("GET", "/.well-known/matrix/client").respond(200, {
Expand Down Expand Up @@ -697,7 +697,7 @@ describe("AutoDiscovery", function () {
expect(req.path).toEqual("https://chat.example.org/_matrix/client/versions");
})
.respond(200, {
versions: ["r0.0.1"],
versions: ["v1.1"],
});
httpBackend
.when("GET", "/_matrix/identity/v2")
Expand Down Expand Up @@ -747,7 +747,7 @@ describe("AutoDiscovery", function () {
expect(req.path).toEqual("https://chat.example.org/_matrix/client/versions");
})
.respond(200, {
versions: ["r0.0.1"],
versions: ["v1.1"],
});
httpBackend
.when("GET", "/_matrix/identity/v2")
Expand Down Expand Up @@ -867,6 +867,37 @@ describe("AutoDiscovery", function () {
]);
});

it("should FAIL_ERROR for unsupported Matrix version", () => {
const httpBackend = getHttpBackend();
httpBackend.when("GET", "/.well-known/matrix/client").respond(200, {
"m.homeserver": {
base_url: "https://example.org",
},
});
httpBackend.when("GET", "/_matrix/client/versions").respond(200, {
versions: ["r0.6.0"],
});
return Promise.all([
httpBackend.flushAllExpected(),
AutoDiscovery.findClientConfig("example.org").then((conf) => {
const expected = {
"m.homeserver": {
state: AutoDiscoveryAction.FAIL_ERROR,
error: AutoDiscovery.ERROR_HOMESERVER_TOO_OLD,
base_url: "https://example.org",
},
"m.identity_server": {
state: "PROMPT",
error: null,
base_url: null,
},
};

expect(conf).toEqual(expected);
}),
]);
});

describe("m.authentication", () => {
const homeserverName = "example.org";
const homeserverUrl = "https://chat.example.org/";
Expand All @@ -879,7 +910,7 @@ describe("AutoDiscovery", function () {

beforeEach(() => {
fetchMock.resetBehavior();
fetchMock.get(`${homeserverUrl}_matrix/client/versions`, { versions: ["r0.0.1"] });
fetchMock.get(`${homeserverUrl}_matrix/client/versions`, { versions: ["v1.1"] });

fetchMock.get("https://example.org/.well-known/matrix/client", {
"m.homeserver": {
Expand Down
8 changes: 4 additions & 4 deletions spec/unit/content-repo.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ describe("ContentRepo", function () {
it("should return a download URL if no width/height/resize are specified", function () {
const mxcUri = "mxc://server.name/resourceid";
expect(getHttpUriForMxc(baseUrl, mxcUri)).toEqual(
baseUrl + "/_matrix/media/r0/download/server.name/resourceid",
baseUrl + "/_matrix/media/v3/download/server.name/resourceid",
);
});

Expand All @@ -44,21 +44,21 @@ describe("ContentRepo", function () {
it("should return a thumbnail URL if a width/height/resize is specified", function () {
const mxcUri = "mxc://server.name/resourceid";
expect(getHttpUriForMxc(baseUrl, mxcUri, 32, 64, "crop")).toEqual(
baseUrl + "/_matrix/media/r0/thumbnail/server.name/resourceid" + "?width=32&height=64&method=crop",
baseUrl + "/_matrix/media/v3/thumbnail/server.name/resourceid" + "?width=32&height=64&method=crop",
);
});

it("should put fragments from mxc:// URIs after any query parameters", function () {
const mxcUri = "mxc://server.name/resourceid#automade";
expect(getHttpUriForMxc(baseUrl, mxcUri, 32)).toEqual(
baseUrl + "/_matrix/media/r0/thumbnail/server.name/resourceid" + "?width=32#automade",
baseUrl + "/_matrix/media/v3/thumbnail/server.name/resourceid" + "?width=32#automade",
);
});

it("should put fragments from mxc:// URIs at the end of the HTTP URI", function () {
const mxcUri = "mxc://server.name/resourceid#automade";
expect(getHttpUriForMxc(baseUrl, mxcUri)).toEqual(
baseUrl + "/_matrix/media/r0/download/server.name/resourceid#automade",
baseUrl + "/_matrix/media/v3/download/server.name/resourceid#automade",
);
});
});
Expand Down
2 changes: 1 addition & 1 deletion spec/unit/http-api/__snapshots__/index.spec.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ exports[`MatrixHttpApi should return expected object from \`getContentUri\` 1`]
"params": {
"access_token": "token",
},
"path": "/_matrix/media/r0/upload",
"path": "/_matrix/media/v3/upload",
}
`;
8 changes: 4 additions & 4 deletions spec/unit/http-api/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ describe("MatrixHttpApi", () => {
upload = api.uploadContent({} as File);
expect(xhr.open).toHaveBeenCalledWith(
Method.Post,
baseUrl.toLowerCase() + "/_matrix/media/r0/upload?access_token=token",
baseUrl.toLowerCase() + "/_matrix/media/v3/upload?access_token=token",
);
expect(xhr.setRequestHeader).not.toHaveBeenCalledWith("Authorization");
});
Expand All @@ -96,7 +96,7 @@ describe("MatrixHttpApi", () => {
accessToken: "token",
});
upload = api.uploadContent({} as File);
expect(xhr.open).toHaveBeenCalledWith(Method.Post, baseUrl.toLowerCase() + "/_matrix/media/r0/upload");
expect(xhr.open).toHaveBeenCalledWith(Method.Post, baseUrl.toLowerCase() + "/_matrix/media/v3/upload");
expect(xhr.setRequestHeader).toHaveBeenCalledWith("Authorization", "Bearer token");
});

Expand All @@ -105,14 +105,14 @@ describe("MatrixHttpApi", () => {
upload = api.uploadContent({} as File, { name: "name" });
expect(xhr.open).toHaveBeenCalledWith(
Method.Post,
baseUrl.toLowerCase() + "/_matrix/media/r0/upload?filename=name",
baseUrl.toLowerCase() + "/_matrix/media/v3/upload?filename=name",
);
});

it("should allow not sending the filename", () => {
const api = new MatrixHttpApi(new TypedEventEmitter<any, any>(), { baseUrl, prefix });
upload = api.uploadContent({} as File, { name: "name", includeFilename: false });
expect(xhr.open).toHaveBeenCalledWith(Method.Post, baseUrl.toLowerCase() + "/_matrix/media/r0/upload");
expect(xhr.open).toHaveBeenCalledWith(Method.Post, baseUrl.toLowerCase() + "/_matrix/media/v3/upload");
});

it("should abort xhr when the upload is aborted", () => {
Expand Down
Loading