Skip to content

Fetch server capabilities during client initialisation #2093

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 7 commits into from
Jan 11, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
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 spec/TestClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ TestClient.prototype.start = function() {
this.httpBackend.when("POST", "/filter").respond(200, { filter_id: "fid" });
this.expectDeviceKeyUpload();

this.httpBackend.when("GET", "/capabilities").respond(200, { capabilities: {} });

// we let the client do a very basic initial sync, which it needs before
// it will upload one-time keys.
this.httpBackend.when("GET", "/sync").respond(200, { next_batch: 1 });
Expand Down
1 change: 1 addition & 0 deletions spec/integ/matrix-client-crypto.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -722,6 +722,7 @@ describe("MatrixClient crypto", function() {
return Promise.resolve()
.then(() => {
logger.log(aliTestClient + ': starting');
httpBackend.when("GET", "/capabilities").respond(200, {});
httpBackend.when("GET", "/pushrules").respond(200, {});
httpBackend.when("POST", "/filter").respond(200, { filter_id: "fid" });
aliTestClient.expectDeviceKeyUpload();
Expand Down
1 change: 1 addition & 0 deletions spec/integ/matrix-client-event-emitter.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ describe("MatrixClient events", function() {
httpBackend = testClient.httpBackend;
httpBackend.when("GET", "/pushrules").respond(200, {});
httpBackend.when("POST", "/filter").respond(200, { filter_id: "a filter id" });
httpBackend.when("GET", "/capabilities").respond(200, { capabilities: {} });
});

afterEach(function() {
Expand Down
1 change: 1 addition & 0 deletions spec/integ/matrix-client-event-timeline.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ const EVENTS = [

// start the client, and wait for it to initialise
function startClient(httpBackend, client) {
httpBackend.when("GET", "/capabilities").respond(200, { capabilities: {} });
httpBackend.when("GET", "/pushrules").respond(200, {});
httpBackend.when("POST", "/filter").respond(200, { filter_id: "fid" });
httpBackend.when("GET", "/sync").respond(200, INITIAL_SYNC_DATA);
Expand Down
4 changes: 3 additions & 1 deletion spec/integ/matrix-client-opts.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,10 +105,12 @@ describe("MatrixClient opts", function() {
expectedEventTypes.indexOf(event.getType()), 1,
);
});
httpBackend.when("GET", "/capabilities").respond(200, { capabilities: {} });
httpBackend.when("GET", "/pushrules").respond(200, {});
httpBackend.when("POST", "/filter").respond(200, { filter_id: "foo" });
httpBackend.when("GET", "/sync").respond(200, syncData);
await client.startClient();
client.startClient();
await httpBackend.flush("/capabilities", 1);
await httpBackend.flush("/pushrules", 1);
await httpBackend.flush("/filter", 1);
await Promise.all([
Expand Down
7 changes: 5 additions & 2 deletions spec/integ/matrix-client-room-timeline.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,15 +109,18 @@ describe("MatrixClient room timelines", function() {
client = testClient.client;

setNextSyncData();
httpBackend.when("GET", "/capabilities").respond(200, { capabilities: {} });
httpBackend.when("GET", "/pushrules").respond(200, {});
httpBackend.when("POST", "/filter").respond(200, { filter_id: "fid" });
httpBackend.when("GET", "/sync").respond(200, SYNC_DATA);
httpBackend.when("GET", "/sync").respond(200, function() {
return NEXT_SYNC_DATA;
});
client.startClient();
return httpBackend.flush("/pushrules").then(function() {
return httpBackend.flush("/filter");
return httpBackend.flush("/capabilities").then(function() {
return httpBackend.flush("/pushrules").then(function() {
return httpBackend.flush("/filter");
});
});
});

Expand Down
1 change: 1 addition & 0 deletions spec/integ/matrix-client-syncing.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ describe("MatrixClient syncing", function() {
const testClient = new TestClient(selfUserId, "DEVICE", selfAccessToken);
httpBackend = testClient.httpBackend;
client = testClient.client;
httpBackend.when("GET", "/capabilities").respond(200, { capabilities: {} });
httpBackend.when("GET", "/pushrules").respond(200, {});
httpBackend.when("POST", "/filter").respond(200, { filter_id: "a filter id" });
});
Expand Down
27 changes: 14 additions & 13 deletions spec/test-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -341,28 +341,29 @@ HttpResponse.SYNC_RESPONSE = {
data: HttpResponse.SYNC_DATA,
};

HttpResponse.CAPABILITIES_RESPONSE = {
method: "GET",
path: "/capabilities",
data: { capabilities: {} },
};

HttpResponse.defaultResponses = function(userId) {
return [
HttpResponse.PUSH_RULES_RESPONSE,
HttpResponse.filterResponse(userId),
HttpResponse.SYNC_RESPONSE,
HttpResponse.CAPABILITIES_RESPONSE,
];
};

export function setHttpResponses(
client, responses, acceptKeepalives, ignoreUnhandledSyncs,
httpBackend, responses
) {
const httpResponseObj = new HttpResponse(
responses, acceptKeepalives, ignoreUnhandledSyncs,
);
responses.forEach(response => {
httpBackend
.when(response.method, response.path)
.respond(200, response.data);
});

const httpReq = httpResponseObj.request.bind(httpResponseObj);
client.http = [
"authedRequest", "authedRequestWithPrefix", "getContentUri",
"request", "requestWithPrefix", "uploadContent",
].reduce((r, k) => {r[k] = jest.fn(); return r;}, {});
client.http.authedRequest.mockImplementation(httpReq);
client.http.authedRequestWithPrefix.mockImplementation(httpReq);
client.http.requestWithPrefix.mockImplementation(httpReq);
client.http.request.mockImplementation(httpReq);
httpBackend.flushAllExpected();
}
33 changes: 18 additions & 15 deletions spec/unit/crypto/cross-signing.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,14 @@ async function makeTestClient(userInfo, options, keys) {
options.cryptoCallbacks = Object.assign(
{}, { getCrossSigningKey, saveCrossSigningKeys }, options.cryptoCallbacks || {},
);
const client = (new TestClient(
const testClient = new TestClient(
userInfo.userId, userInfo.deviceId, undefined, undefined, options,
)).client;
);
const client = testClient.client;

await client.initCrypto();

return client;
return { client, httpBackend: testClient.httpBackend };
}

describe("Cross Signing", function() {
Expand All @@ -60,7 +61,7 @@ describe("Cross Signing", function() {
});

it("should sign the master key with the device key", async function() {
const alice = await makeTestClient(
const { client: alice } = await makeTestClient(
{ userId: "@alice:example.com", deviceId: "Osborne2" },
);
alice.uploadDeviceSigningKeys = jest.fn(async (auth, keys) => {
Expand All @@ -80,7 +81,7 @@ describe("Cross Signing", function() {
});

it("should abort bootstrap if device signing auth fails", async function() {
const alice = await makeTestClient(
const { client: alice } = await makeTestClient(
{ userId: "@alice:example.com", deviceId: "Osborne2" },
);
alice.uploadDeviceSigningKeys = async (auth, keys) => {
Expand Down Expand Up @@ -131,7 +132,7 @@ describe("Cross Signing", function() {
});

it("should upload a signature when a user is verified", async function() {
const alice = await makeTestClient(
const { client: alice } = await makeTestClient(
{ userId: "@alice:example.com", deviceId: "Osborne2" },
);
alice.uploadDeviceSigningKeys = async () => {};
Expand Down Expand Up @@ -175,7 +176,7 @@ describe("Cross Signing", function() {
0x34, 0xf2, 0x4b, 0x64, 0x9b, 0x52, 0xf8, 0x5f,
]);

const alice = await makeTestClient(
const { client: alice, httpBackend } = await makeTestClient(
{ userId: "@alice:example.com", deviceId: "Osborne2" },
{
cryptoCallbacks: {
Expand Down Expand Up @@ -236,6 +237,7 @@ describe("Cross Signing", function() {

// feed sync result that includes master key, ssk, device key
const responses = [
HttpResponse.CAPABILITIES_RESPONSE,
HttpResponse.PUSH_RULES_RESPONSE,
{
method: "POST",
Expand Down Expand Up @@ -311,7 +313,7 @@ describe("Cross Signing", function() {
},
},
];
setHttpResponses(alice, responses, true, true);
setHttpResponses(httpBackend, responses);

await alice.startClient();

Expand All @@ -332,7 +334,7 @@ describe("Cross Signing", function() {
});

it("should use trust chain to determine device verification", async function() {
const alice = await makeTestClient(
const { client: alice } = await makeTestClient(
{ userId: "@alice:example.com", deviceId: "Osborne2" },
);
alice.uploadDeviceSigningKeys = async () => {};
Expand Down Expand Up @@ -417,7 +419,7 @@ describe("Cross Signing", function() {

it("should trust signatures received from other devices", async function() {
const aliceKeys = {};
const alice = await makeTestClient(
const { client: alice, httpBackend } = await makeTestClient(
{ userId: "@alice:example.com", deviceId: "Osborne2" },
null,
aliceKeys,
Expand Down Expand Up @@ -491,6 +493,7 @@ describe("Cross Signing", function() {
// - master key signed by her usk (pretend that it was signed by another
// of Alice's devices)
const responses = [
HttpResponse.CAPABILITIES_RESPONSE,
HttpResponse.PUSH_RULES_RESPONSE,
{
method: "POST",
Expand Down Expand Up @@ -561,7 +564,7 @@ describe("Cross Signing", function() {
},
},
];
setHttpResponses(alice, responses);
setHttpResponses(httpBackend, responses);

await alice.startClient();

Expand All @@ -579,7 +582,7 @@ describe("Cross Signing", function() {
});

it("should dis-trust an unsigned device", async function() {
const alice = await makeTestClient(
const { client: alice } = await makeTestClient(
{ userId: "@alice:example.com", deviceId: "Osborne2" },
);
alice.uploadDeviceSigningKeys = async () => {};
Expand Down Expand Up @@ -648,7 +651,7 @@ describe("Cross Signing", function() {
});

it("should dis-trust a user when their ssk changes", async function() {
const alice = await makeTestClient(
const { client: alice } = await makeTestClient(
{ userId: "@alice:example.com", deviceId: "Osborne2" },
);
alice.uploadDeviceSigningKeys = async () => {};
Expand Down Expand Up @@ -786,7 +789,7 @@ describe("Cross Signing", function() {
it("should offer to upgrade device verifications to cross-signing", async function() {
let upgradeResolveFunc;

const alice = await makeTestClient(
const { client: alice } = await makeTestClient(
{ userId: "@alice:example.com", deviceId: "Osborne2" },
{
cryptoCallbacks: {
Expand All @@ -798,7 +801,7 @@ describe("Cross Signing", function() {
},
},
);
const bob = await makeTestClient(
const { client: bob } = await makeTestClient(
{ userId: "@bob:example.com", deviceId: "Dynabook" },
);

Expand Down
24 changes: 20 additions & 4 deletions spec/unit/matrix-client.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,12 @@ describe("MatrixClient", function() {
data: SYNC_DATA,
};

const CAPABILITIES_RESPONSE = {
method: "GET",
path: "/capabilities",
data: { capabilities: {} },
};

let httpLookups = [
// items are objects which look like:
// {
Expand Down Expand Up @@ -167,6 +173,7 @@ describe("MatrixClient", function() {
acceptKeepalives = true;
pendingLookup = null;
httpLookups = [];
httpLookups.push(CAPABILITIES_RESPONSE);
httpLookups.push(PUSH_RULES_RESPONSE);
httpLookups.push(FILTER_RESPONSE);
httpLookups.push(SYNC_RESPONSE);
Expand Down Expand Up @@ -364,9 +371,11 @@ describe("MatrixClient", function() {
});

it("should not POST /filter if a matching filter already exists", async function() {
httpLookups = [];
httpLookups.push(PUSH_RULES_RESPONSE);
httpLookups.push(SYNC_RESPONSE);
httpLookups = [
CAPABILITIES_RESPONSE,
PUSH_RULES_RESPONSE,
SYNC_RESPONSE,
];
const filterId = "ehfewf";
store.getFilterIdByName.mockReturnValue(filterId);
const filter = new Filter(0, filterId);
Expand Down Expand Up @@ -447,12 +456,15 @@ describe("MatrixClient", function() {

describe("retryImmediately", function() {
it("should return false if there is no request waiting", async function() {
httpLookups = [];
httpLookups.push(CAPABILITIES_RESPONSE);
await client.startClient();
expect(client.retryImmediately()).toBe(false);
});

it("should work on /filter", function(done) {
httpLookups = [];
httpLookups.push(CAPABILITIES_RESPONSE);
httpLookups.push(PUSH_RULES_RESPONSE);
httpLookups.push({
method: "POST", path: FILTER_PATH, error: { errcode: "NOPE_NOPE_NOPE" },
Expand Down Expand Up @@ -503,6 +515,7 @@ describe("MatrixClient", function() {

it("should work on /pushrules", function(done) {
httpLookups = [];
httpLookups.push(CAPABILITIES_RESPONSE);
httpLookups.push({
method: "GET", path: "/pushrules/", error: { errcode: "NOPE_NOPE_NOPE" },
});
Expand Down Expand Up @@ -559,6 +572,7 @@ describe("MatrixClient", function() {
it("should transition null -> ERROR after a failed /filter", function(done) {
const expectedStates = [];
httpLookups = [];
httpLookups.push(CAPABILITIES_RESPONSE);
httpLookups.push(PUSH_RULES_RESPONSE);
httpLookups.push({
method: "POST", path: FILTER_PATH, error: { errcode: "NOPE_NOPE_NOPE" },
Expand All @@ -573,6 +587,7 @@ describe("MatrixClient", function() {
const expectedStates = [];
acceptKeepalives = false;
httpLookups = [];
httpLookups.push(CAPABILITIES_RESPONSE);
httpLookups.push(PUSH_RULES_RESPONSE);
httpLookups.push(FILTER_RESPONSE);
httpLookups.push({
Expand Down Expand Up @@ -697,7 +712,8 @@ describe("MatrixClient", function() {

describe("guest rooms", function() {
it("should only do /sync calls (without filter/pushrules)", function(done) {
httpLookups = []; // no /pushrules or /filter
httpLookups = []; // no /pushrules or /filterw
httpLookups.push(CAPABILITIES_RESPONSE);
httpLookups.push({
method: "GET",
path: "/sync",
Expand Down
2 changes: 1 addition & 1 deletion src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1041,7 +1041,7 @@ export class MatrixClient extends EventEmitter {
this.syncApi.stop();
}

await this.getCapabilities();
await this.getCapabilities(true);

// shallow-copy the opts dict before modifying and storing it
this.clientOpts = Object.assign({}, opts) as IStoredClientOpts;
Expand Down