1
0
mirror of https://github.com/matrix-org/matrix-js-sdk.git synced 2025-07-31 15:24:23 +03:00

Improve typing (#2055)

This commit is contained in:
Michael Telatynski
2021-12-09 14:22:58 +00:00
committed by GitHub
parent 95e7a76ba9
commit f8097221e6
28 changed files with 189 additions and 284 deletions

View File

@ -15,7 +15,7 @@
"build:minify-browser": "terser dist/browser-matrix.js --compress --mangle --source-map --output dist/browser-matrix.min.js",
"gendoc": "jsdoc -c jsdoc.json -P package.json",
"lint": "yarn lint:types && yarn lint:js",
"lint:js": "eslint --max-warnings 7 src spec",
"lint:js": "eslint --max-warnings 4 src spec",
"lint:js-fix": "eslint --fix src spec",
"lint:types": "tsc --noEmit",
"test": "jest",

View File

@ -4,13 +4,13 @@ import { Room } from "../../src/models/room";
import { TestClient } from "../TestClient";
describe("MatrixClient retrying", function() {
let client = null;
let httpBackend = null;
let client: TestClient = null;
let httpBackend: TestClient["httpBackend"] = null;
let scheduler;
const userId = "@alice:localhost";
const accessToken = "aseukfgwef";
const roomId = "!room:here";
let room;
let room: Room;
beforeEach(function() {
scheduler = new MatrixScheduler();
@ -53,10 +53,10 @@ describe("MatrixClient retrying", function() {
const p1 = client.sendMessage(roomId, {
"msgtype": "m.text",
"body": "m1",
}).then(function(ev) {
}).then(function() {
// we expect the first message to fail
throw new Error('Message 1 unexpectedly sent successfully');
}, (e) => {
}, () => {
// this is expected
});
@ -78,7 +78,7 @@ describe("MatrixClient retrying", function() {
expect(ev2.status).toEqual(EventStatus.SENDING);
// the first message should get sent, and the second should get queued
httpBackend.when("PUT", "/send/m.room.message/").check(function(rq) {
httpBackend.when("PUT", "/send/m.room.message/").check(function() {
// ev2 should now have been queued
expect(ev2.status).toEqual(EventStatus.QUEUED);

View File

@ -1018,7 +1018,7 @@ describe("MSC3089TreeSpace", () => {
it('should return falsy for unknown files', () => {
const fileEventId = "$file";
room.currentState = {
getStateEvents: (eventType: string, stateKey?: string) => {
getStateEvents: (eventType: string, stateKey?: string): MatrixEvent[] | MatrixEvent | null => {
expect(eventType).toEqual(UNSTABLE_MSC3089_BRANCH.unstable); // test to ensure we're definitely using unstable
expect(stateKey).toEqual(fileEventId);
return null;

View File

@ -111,10 +111,10 @@ describe("utils", function() {
describe("deepCompare", function() {
const assert = {
isTrue: function(x) {
isTrue: function(x: any) {
expect(x).toBe(true);
},
isFalse: function(x) {
isFalse: function(x: any) {
expect(x).toBe(false);
},
};
@ -176,10 +176,10 @@ describe("utils", function() {
// no two different function is equal really, they capture their
// context variables so even if they have same toString(), they
// won't have same functionality
const func = function(x) {
const func = function() {
return true;
};
const func2 = function(x) {
const func2 = function() {
return true;
};
assert.isTrue(utils.deepCompare(func, func));
@ -189,66 +189,6 @@ describe("utils", function() {
});
});
describe("extend", function() {
const SOURCE = { "prop2": 1, "string2": "x", "newprop": "new" };
it("should extend", function() {
const target = {
"prop1": 5, "prop2": 7, "string1": "baz", "string2": "foo",
};
const merged = {
"prop1": 5, "prop2": 1, "string1": "baz", "string2": "x",
"newprop": "new",
};
const sourceOrig = JSON.stringify(SOURCE);
utils.extend(target, SOURCE);
expect(JSON.stringify(target)).toEqual(JSON.stringify(merged));
// check the originial wasn't modified
expect(JSON.stringify(SOURCE)).toEqual(sourceOrig);
});
it("should ignore null", function() {
const target = {
"prop1": 5, "prop2": 7, "string1": "baz", "string2": "foo",
};
const merged = {
"prop1": 5, "prop2": 1, "string1": "baz", "string2": "x",
"newprop": "new",
};
const sourceOrig = JSON.stringify(SOURCE);
utils.extend(target, null, SOURCE);
expect(JSON.stringify(target)).toEqual(JSON.stringify(merged));
// check the originial wasn't modified
expect(JSON.stringify(SOURCE)).toEqual(sourceOrig);
});
it("should handle properties created with defineProperties", function() {
const source = Object.defineProperties({}, {
"enumerableProp": {
get: function() {
return true;
},
enumerable: true,
},
"nonenumerableProp": {
get: function() {
return true;
},
},
});
// TODO: Fix type
const target: any = {};
utils.extend(target, source);
expect(target.enumerableProp).toBe(true);
expect(target.nonenumerableProp).toBe(undefined);
});
});
describe("chunkPromises", function() {
it("should execute promises in chunks", async function() {
let promiseCount = 0;
@ -273,7 +213,7 @@ describe("utils", function() {
it('should retry', async () => {
let count = 0;
const val = {};
const fn = (attempt) => {
const fn = (attempt: any) => {
count++;
// If this expectation fails then it can appear as a Jest Timeout due to
@ -480,7 +420,7 @@ describe("utils", function() {
},
[72]: "test",
};
const output = [
const output: any = [
["72", "test"],
["a", 42],
["b", [

View File

@ -17,6 +17,7 @@ limitations under the License.
import { TestClient } from '../../TestClient';
import { MatrixCall, CallErrorCode, CallEvent } from '../../../src/webrtc/call';
import { SDPStreamMetadataKey, SDPStreamMetadataPurpose } from '../../../src/webrtc/callEventTypes';
import { RoomMember } from "../../../src";
const DUMMY_SDP = (
"v=0\r\n" +
@ -85,7 +86,7 @@ class MockRTCPeerConnection {
class MockMediaStream {
constructor(
public id,
public id: string,
) {}
getTracks() { return []; }
@ -362,7 +363,7 @@ describe('Call', function() {
await callPromise;
call.getOpponentMember = () => {
return { userId: "@bob:bar.uk" };
return { userId: "@bob:bar.uk" } as RoomMember;
};
await call.onAnswerReceived({

View File

@ -30,7 +30,7 @@ export class ReEmitter {
// We include the source as the last argument for event handlers which may need it,
// such as read receipt listeners on the client class which won't have the context
// of the room.
const forSource = (...args) => {
const forSource = (...args: any[]) => {
// EventEmitter special cases 'error' to make the emit function throw if no
// handler is attached, which sort of makes sense for making sure that something
// handles an error, but for re-emitting, there could be a listener on the original

View File

@ -1423,7 +1423,7 @@ export class MatrixClient extends EventEmitter {
// We swallow errors because we need a default object anyhow
return this.http.authedRequest(
undefined, "GET", "/capabilities",
).catch((e) => {
).catch((e: Error) => {
logger.error(e);
return null; // otherwise consume the error
}).then((r) => {
@ -3106,7 +3106,7 @@ export class MatrixClient extends EventEmitter {
* data event.
* @return {module:http-api.MatrixError} Rejects: with an error response.
*/
public async getAccountDataFromServer(eventType: string): Promise<Record<string, any>> {
public async getAccountDataFromServer<T>(eventType: string): Promise<T> {
if (this.isInitialSyncComplete()) {
const event = this.store.getAccountData(eventType);
if (!event) {
@ -3201,7 +3201,7 @@ export class MatrixClient extends EventEmitter {
);
}
const queryString = {};
const queryString: Record<string, string | string[]> = {};
if (opts.viaServers) {
queryString["server_name"] = opts.viaServers;
}
@ -3411,7 +3411,7 @@ export class MatrixClient extends EventEmitter {
content: IContent,
txnId?: string,
callback?: Callback,
);
): Promise<ISendEventResponse>;
public sendEvent(
roomId: string,
threadId: string | null,
@ -3419,7 +3419,7 @@ export class MatrixClient extends EventEmitter {
content: IContent,
txnId?: string,
callback?: Callback,
)
): Promise<ISendEventResponse>;
public sendEvent(
roomId: string,
threadId: string | null,
@ -3699,14 +3699,14 @@ export class MatrixClient extends EventEmitter {
eventId: string,
txnId?: string | undefined,
cbOrOpts?: Callback | IRedactOpts,
);
): Promise<ISendEventResponse>;
public redactEvent(
roomId: string,
threadId: string | null,
eventId: string,
txnId?: string | undefined,
cbOrOpts?: Callback | IRedactOpts,
);
): Promise<ISendEventResponse>;
public redactEvent(
roomId: string,
threadId: string | null,
@ -3744,14 +3744,14 @@ export class MatrixClient extends EventEmitter {
content: IContent,
txnId?: string,
callback?: Callback,
)
): Promise<ISendEventResponse>;
public sendMessage(
roomId: string,
threadId: string | null,
content: IContent,
txnId?: string,
callback?: Callback,
)
): Promise<ISendEventResponse>;
public sendMessage(
roomId: string,
threadId: string | null | IContent,
@ -3793,14 +3793,14 @@ export class MatrixClient extends EventEmitter {
body: string,
txnId?: string,
callback?: Callback,
)
): Promise<ISendEventResponse>;
public sendTextMessage(
roomId: string,
threadId: string | null,
body: string,
txnId?: string,
callback?: Callback,
)
): Promise<ISendEventResponse>;
public sendTextMessage(
roomId: string,
threadId: string | null,
@ -3832,14 +3832,14 @@ export class MatrixClient extends EventEmitter {
body: string,
txnId?: string,
callback?: Callback,
)
): Promise<ISendEventResponse>;
public sendNotice(
roomId: string,
threadId: string | null,
body: string,
txnId?: string,
callback?: Callback,
);
): Promise<ISendEventResponse>;
public sendNotice(
roomId: string,
threadId: string | null,
@ -3871,14 +3871,14 @@ export class MatrixClient extends EventEmitter {
body: string,
txnId?: string,
callback?: Callback,
)
): Promise<ISendEventResponse>;
public sendEmoteMessage(
roomId: string,
threadId: string | null,
body: string,
txnId?: string,
callback?: Callback,
);
): Promise<ISendEventResponse>;
public sendEmoteMessage(
roomId: string,
threadId: string | null,
@ -3912,7 +3912,7 @@ export class MatrixClient extends EventEmitter {
info?: IImageInfo,
text?: string,
callback?: Callback,
);
): Promise<ISendEventResponse>;
public sendImageMessage(
roomId: string,
threadId: string | null,
@ -3920,7 +3920,7 @@ export class MatrixClient extends EventEmitter {
info?: IImageInfo,
text?: string,
callback?: Callback,
);
): Promise<ISendEventResponse>;
public sendImageMessage(
roomId: string,
threadId: string | null,
@ -3965,7 +3965,7 @@ export class MatrixClient extends EventEmitter {
info?: IImageInfo,
text?: string,
callback?: Callback,
);
): Promise<ISendEventResponse>;
public sendStickerMessage(
roomId: string,
threadId: string | null,
@ -3973,7 +3973,7 @@ export class MatrixClient extends EventEmitter {
info?: IImageInfo,
text?: string,
callback?: Callback,
);
): Promise<ISendEventResponse>;
public sendStickerMessage(
roomId: string,
threadId: string | null,
@ -4015,14 +4015,14 @@ export class MatrixClient extends EventEmitter {
body: string,
htmlBody: string,
callback?: Callback,
);
): Promise<ISendEventResponse>;
public sendHtmlMessage(
roomId: string,
threadId: string | null,
body: string,
htmlBody: string,
callback?: Callback,
)
): Promise<ISendEventResponse>;
public sendHtmlMessage(
roomId: string,
threadId: string | null,
@ -4053,14 +4053,14 @@ export class MatrixClient extends EventEmitter {
body: string,
htmlBody: string,
callback?: Callback,
);
): Promise<ISendEventResponse>;
public sendHtmlNotice(
roomId: string,
threadId: string | null,
body: string,
htmlBody: string,
callback?: Callback,
)
): Promise<ISendEventResponse>;
public sendHtmlNotice(
roomId: string,
threadId: string | null,
@ -4092,14 +4092,14 @@ export class MatrixClient extends EventEmitter {
body: string,
htmlBody: string,
callback?: Callback,
);
): Promise<ISendEventResponse>;
public sendHtmlEmote(
roomId: string,
threadId: string | null,
body: string,
htmlBody: string,
callback?: Callback,
)
): Promise<ISendEventResponse>;
public sendHtmlEmote(
roomId: string,
threadId: string | null,
@ -4420,7 +4420,7 @@ export class MatrixClient extends EventEmitter {
errcode: "ORG.MATRIX.JSSDK_MISSING_PARAM",
}));
}
const params = {
const params: Record<string, string> = {
id_server: identityServerUrl,
medium: medium,
address: address,
@ -4478,10 +4478,10 @@ export class MatrixClient extends EventEmitter {
}
}
const populationResults = {}; // {roomId: Error}
const populationResults: Record<string, Error> = {}; // {roomId: Error}
const promises = [];
const doLeave = (roomId) => {
const doLeave = (roomId: string) => {
return this.leave(roomId).then(() => {
populationResults[roomId] = null;
}).catch((err) => {
@ -5065,14 +5065,14 @@ export class MatrixClient extends EventEmitter {
return pendingRequest;
}
let path;
let params;
let path: string;
let params: Record<string, string>;
let promise;
if (isNotifTimeline) {
path = "/notifications";
params = {
limit: ('limit' in opts) ? opts.limit : 30,
limit: (opts.limit ?? 30).toString(),
only: 'highlight',
};
@ -5509,7 +5509,7 @@ export class MatrixClient extends EventEmitter {
* @return {module:http-api.MatrixError} Rejects: with an error response.
*/
public setRoomMutePushRule(scope: string, roomId: string, mute: boolean): Promise<void> | void {
let deferred;
let promise: Promise<void>;
let hasDontNotifyRule;
// Get the existing room-kind push rule if any
@ -5523,17 +5523,17 @@ export class MatrixClient extends EventEmitter {
if (!mute) {
// Remove the rule only if it is a muting rule
if (hasDontNotifyRule) {
deferred = this.deletePushRule(scope, PushRuleKind.RoomSpecific, roomPushRule.rule_id);
promise = this.deletePushRule(scope, PushRuleKind.RoomSpecific, roomPushRule.rule_id);
}
} else {
if (!roomPushRule) {
deferred = this.addPushRule(scope, PushRuleKind.RoomSpecific, roomId, {
promise = this.addPushRule(scope, PushRuleKind.RoomSpecific, roomId, {
actions: ["dont_notify"],
});
} else if (!hasDontNotifyRule) {
// Remove the existing one before setting the mute push rule
// This is a workaround to SYN-590 (Push rule update fails)
deferred = utils.defer();
const deferred = utils.defer();
this.deletePushRule(scope, PushRuleKind.RoomSpecific, roomPushRule.rule_id)
.then(() => {
this.addPushRule(scope, PushRuleKind.RoomSpecific, roomId, {
@ -5547,21 +5547,21 @@ export class MatrixClient extends EventEmitter {
deferred.reject(err);
});
deferred = deferred.promise;
promise = deferred.promise;
}
}
if (deferred) {
if (promise) {
return new Promise<void>((resolve, reject) => {
// Update this.pushRules when the operation completes
deferred.then(() => {
promise.then(() => {
this.getPushRules().then((result) => {
this.pushRules = result;
resolve();
}).catch((err) => {
reject(err);
});
}).catch((err) => {
}).catch((err: Error) => {
// Update it even if the previous operation fails. This can help the
// app to recover when push settings has been modifed from another client
this.getPushRules().then((result) => {
@ -6281,7 +6281,7 @@ export class MatrixClient extends EventEmitter {
fetchedEventType,
opts);
const mapper = this.getEventMapper();
let originalEvent;
let originalEvent: MatrixEvent;
if (result.original_event) {
originalEvent = mapper(result.original_event);
}
@ -6564,7 +6564,7 @@ export class MatrixClient extends EventEmitter {
};
// merge data into loginData
utils.extend(loginData, data);
Object.assign(loginData, data);
return this.http.authedRequest(
(error, response) => {
@ -7544,7 +7544,7 @@ export class MatrixClient extends EventEmitter {
* @return {module:http-api.MatrixError} Rejects: with an error response.
*/
public getPushRules(callback?: Callback): Promise<IPushRules> {
return this.http.authedRequest(callback, "GET", "/pushrules/").then(rules => {
return this.http.authedRequest(callback, "GET", "/pushrules/").then((rules: IPushRules) => {
return PushProcessor.rewriteDefaultRules(rules);
});
}
@ -8018,7 +8018,7 @@ export class MatrixClient extends EventEmitter {
addressPairs: [string, string][],
identityAccessToken: string,
): Promise<{ address: string, mxid: string }[]> {
const params = {
const params: Record<string, string | string[]> = {
// addresses: ["email@example.org", "10005550000"],
// algorithm: "sha256",
// pepper: "abc123"
@ -8032,7 +8032,7 @@ export class MatrixClient extends EventEmitter {
params['pepper'] = hashes['lookup_pepper'];
const localMapping = {
const localMapping: Record<string, string> = {
// hashed identifier => plain text address
// For use in this function's return format
};

View File

@ -53,13 +53,13 @@ export function getHttpUriForMxc(
}
let serverAndMediaId = mxc.slice(6); // strips mxc://
let prefix = "/_matrix/media/r0/download/";
const params = {};
const params: Record<string, string> = {};
if (width) {
params["width"] = Math.round(width);
params["width"] = Math.round(width).toString();
}
if (height) {
params["height"] = Math.round(height);
params["height"] = Math.round(height).toString();
}
if (resizeMethod) {
params["method"] = resizeMethod;

View File

@ -265,8 +265,8 @@ export class DeviceList extends EventEmitter {
* module:crypto/deviceinfo|DeviceInfo}.
*/
public downloadKeys(userIds: string[], forceDownload: boolean): Promise<DeviceInfoMap> {
const usersToDownload = [];
const promises = [];
const usersToDownload: string[] = [];
const promises: Promise<unknown>[] = [];
userIds.forEach((u) => {
const trackingStatus = this.deviceTrackingStatus[u];
@ -633,7 +633,7 @@ export class DeviceList extends EventEmitter {
}
});
const finished = (success) => {
const finished = (success: boolean): void => {
this.emit("crypto.willUpdateDevices", users, !this.hasFetched);
users.forEach((u) => {
this.dirty = true;

View File

@ -37,7 +37,7 @@ export interface ISecretRequest {
export interface IAccountDataClient extends EventEmitter {
// Subset of MatrixClient (which also uses any for the event content)
getAccountDataFromServer: (eventType: string) => Promise<Record<string, any>>;
getAccountDataFromServer: <T>(eventType: string) => Promise<T>;
getAccountData: (eventType: string) => MatrixEvent;
setAccountData: (eventType: string, content: any) => Promise<{}>;
}
@ -76,7 +76,7 @@ export class SecretStorage {
) {}
public async getDefaultKeyId(): Promise<string> {
const defaultKey = await this.accountDataAdapter.getAccountDataFromServer(
const defaultKey = await this.accountDataAdapter.getAccountDataFromServer<{ key: string }>(
'm.secret_storage.default_key',
);
if (!defaultKey) return null;
@ -230,7 +230,7 @@ export class SecretStorage {
* or null/undefined to use the default key.
*/
public async store(name: string, secret: string, keys?: string[]): Promise<void> {
const encrypted = {};
const encrypted: Record<string, IEncryptedPayload> = {};
if (!keys) {
const defaultKeyId = await this.getDefaultKeyId();
@ -246,9 +246,9 @@ export class SecretStorage {
for (const keyId of keys) {
// get key information from key storage
const keyInfo = await this.accountDataAdapter.getAccountDataFromServer(
const keyInfo = await this.accountDataAdapter.getAccountDataFromServer<ISecretStorageKeyInfo>(
"m.secret_storage.key." + keyId,
) as ISecretStorageKeyInfo;
);
if (!keyInfo) {
throw new Error("Unknown key: " + keyId);
}
@ -277,7 +277,7 @@ export class SecretStorage {
* @return {string} the contents of the secret
*/
public async get(name: string): Promise<string> {
const secretInfo = await this.accountDataAdapter.getAccountDataFromServer(name);
const secretInfo = await this.accountDataAdapter.getAccountDataFromServer<any>(name); // TODO types
if (!secretInfo) {
return;
}
@ -286,11 +286,13 @@ export class SecretStorage {
}
// get possible keys to decrypt
const keys = {};
const keys: Record<string, ISecretStorageKeyInfo> = {};
for (const keyId of Object.keys(secretInfo.encrypted)) {
// get key information from key storage
const keyInfo = await this.accountDataAdapter.getAccountDataFromServer(
"m.secret_storage.key." + keyId,
const keyInfo = (
await this.accountDataAdapter.getAccountDataFromServer<ISecretStorageKeyInfo>(
"m.secret_storage.key." + keyId,
)
);
const encInfo = secretInfo.encrypted[keyId];
// only use keys we understand the encryption algorithm of
@ -306,7 +308,7 @@ export class SecretStorage {
`the keys it is encrypted with are for a supported algorithm`);
}
let keyId;
let keyId: string;
let decryption;
try {
// fetch private key from app
@ -337,7 +339,7 @@ export class SecretStorage {
*/
public async isStored(name: string, checkKey: boolean): Promise<Record<string, ISecretStorageKeyInfo>> {
// check if secret exists
const secretInfo = await this.accountDataAdapter.getAccountDataFromServer(name);
const secretInfo = await this.accountDataAdapter.getAccountDataFromServer<any>(name); // TODO types
if (!secretInfo) return null;
if (!secretInfo.encrypted) {
return null;
@ -350,7 +352,7 @@ export class SecretStorage {
// filter secret encryption keys with supported algorithm
for (const keyId of Object.keys(secretInfo.encrypted)) {
// get key information from key storage
const keyInfo = await this.accountDataAdapter.getAccountDataFromServer(
const keyInfo = await this.accountDataAdapter.getAccountDataFromServer<any>( // TODO types
"m.secret_storage.key." + keyId,
);
if (!keyInfo) continue;
@ -375,8 +377,8 @@ export class SecretStorage {
public request(name: string, devices: string[]): ISecretRequest {
const requestId = this.baseApis.makeTxnId();
let resolve: (string) => void;
let reject: (Error) => void;
let resolve: (s: string) => void;
let reject: (e: Error) => void;
const promise = new Promise<string>((res, rej) => {
resolve = res;
reject = rej;

View File

@ -46,7 +46,7 @@ type DecryptionClassParams = Omit<IParams, "deviceId" | "config">;
*/
export const DECRYPTION_CLASSES: Record<string, new (params: DecryptionClassParams) => DecryptionAlgorithm> = {};
interface IParams {
export interface IParams {
userId: string;
deviceId: string;
crypto: Crypto;

View File

@ -26,6 +26,7 @@ import {
DecryptionAlgorithm,
DecryptionError,
EncryptionAlgorithm,
IParams,
registerAlgorithm,
UnknownDeviceError,
} from "./base";
@ -99,6 +100,12 @@ interface IPayload extends Partial<IMessage> {
algorithm?: string;
sender_key?: string;
}
interface IEncryptedContent {
algorithm: string;
sender_key: string;
ciphertext: Record<string, string>;
}
/* eslint-enable camelcase */
interface SharedWithData {
@ -238,7 +245,7 @@ class MegolmEncryption extends EncryptionAlgorithm {
startTime: number;
};
constructor(params) {
constructor(params: IParams) {
super(params);
this.sessionRotationPeriodMsgs = params.config?.rotation_period_msgs ?? 100;
@ -263,7 +270,7 @@ class MegolmEncryption extends EncryptionAlgorithm {
blocked: IBlockedMap,
singleOlmCreationPhase = false,
): Promise<OutboundSessionInfo> {
let session;
let session: OutboundSessionInfo;
// takes the previous OutboundSessionInfo, and considers whether to create
// a new one. Also shares the key with any (new) devices in the room.
@ -302,7 +309,7 @@ class MegolmEncryption extends EncryptionAlgorithm {
}
// now check if we need to share with any devices
const shareMap = {};
const shareMap: Record<string, DeviceInfo[]> = {};
for (const [userId, userDevices] of Object.entries(devicesInRoom)) {
for (const [deviceId, deviceInfo] of Object.entries(userDevices)) {
@ -350,7 +357,7 @@ class MegolmEncryption extends EncryptionAlgorithm {
`Sharing keys (start phase 1) with new Olm sessions in ${this.roomId}`,
devicesWithoutSession,
);
const errorDevices = [];
const errorDevices: IOlmDevice[] = [];
// meanwhile, establish olm sessions for devices that we don't
// already have a session for, and share keys with them. If
@ -358,7 +365,7 @@ class MegolmEncryption extends EncryptionAlgorithm {
// shorter timeout when fetching one-time keys for the first
// phase.
const start = Date.now();
const failedServers = [];
const failedServers: string[] = [];
await this.shareKeyWithDevices(
session, key, payload, devicesWithoutSession, errorDevices,
singleOlmCreationPhase ? 10000 : 2000, failedServers,
@ -374,7 +381,7 @@ class MegolmEncryption extends EncryptionAlgorithm {
// do this in the background and don't block anything else while we
// do this. We only need to retry users from servers that didn't
// respond the first time.
const retryDevices = {};
const retryDevices: Record<string, DeviceInfo[]> = {};
const failedServerMap = new Set;
for (const server of failedServers) {
failedServerMap.add(server);
@ -584,12 +591,12 @@ class MegolmEncryption extends EncryptionAlgorithm {
userDeviceMap: IOlmDevice[],
payload: IPayload,
): Promise<void> {
const contentMap = {};
const contentMap: Record<string, Record<string, IEncryptedContent>> = {};
const deviceInfoByDeviceId = new Map<string, DeviceInfo>();
const promises = [];
const promises: Promise<unknown>[] = [];
for (let i = 0; i < userDeviceMap.length; i++) {
const encryptedContent = {
const encryptedContent: IEncryptedContent = {
algorithm: olmlib.OLM_ALGORITHM,
sender_key: this.olmDevice.deviceCurve25519Key,
ciphertext: {},
@ -679,7 +686,7 @@ class MegolmEncryption extends EncryptionAlgorithm {
userDeviceMap: IOlmDevice<IBlockedDevice>[],
payload: IPayload,
): Promise<void> {
const contentMap = {};
const contentMap: Record<string, Record<string, IPayload>> = {};
for (const val of userDeviceMap) {
const userId = val.userId;
@ -1105,7 +1112,7 @@ class MegolmEncryption extends EncryptionAlgorithm {
* devices we should shared the session with.
*/
private checkForUnknownDevices(devicesInRoom: DeviceInfoMap): void {
const unknownDevices = {};
const unknownDevices: Record<string, Record<string, DeviceInfo>> = {};
Object.keys(devicesInRoom).forEach((userId)=>{
Object.keys(devicesInRoom[userId]).forEach((deviceId)=>{
@ -1304,8 +1311,7 @@ class MegolmDecryption extends DecryptionAlgorithm {
content.sender_key, event.getTs() - 120000,
);
if (problem) {
let problemDescription = PROBLEM_DESCRIPTIONS[problem.type]
|| PROBLEM_DESCRIPTIONS.unknown;
let problemDescription = PROBLEM_DESCRIPTIONS[problem.type as "no_olm"] || PROBLEM_DESCRIPTIONS.unknown;
if (problem.fixed) {
problemDescription +=
" Trying to create a new secure channel and re-requesting the keys.";
@ -1399,14 +1405,14 @@ class MegolmDecryption extends DecryptionAlgorithm {
const senderKey = content.sender_key;
const sessionId = content.session_id;
const senderPendingEvents = this.pendingEvents[senderKey];
const pendingEvents = senderPendingEvents && senderPendingEvents.get(sessionId);
const pendingEvents = senderPendingEvents?.get(sessionId);
if (!pendingEvents) {
return;
}
pendingEvents.delete(event);
if (pendingEvents.size === 0) {
senderPendingEvents.delete(senderKey);
senderPendingEvents.delete(sessionId);
}
if (senderPendingEvents.size === 0) {
delete this.pendingEvents[senderKey];
@ -1760,7 +1766,7 @@ class MegolmDecryption extends DecryptionAlgorithm {
}));
// If decrypted successfully, they'll have been removed from pendingEvents
return !((this.pendingEvents[senderKey] || {})[sessionId]);
return !this.pendingEvents[senderKey]?.has(sessionId);
}
public async retryDecryptionFromSender(senderKey: string): Promise<boolean> {
@ -1794,12 +1800,12 @@ class MegolmDecryption extends DecryptionAlgorithm {
for (const [senderKey, sessionId] of sharedHistorySessions) {
const payload = await this.buildKeyForwardingMessage(this.roomId, senderKey, sessionId);
const promises = [];
const contentMap = {};
const promises: Promise<unknown>[] = [];
const contentMap: Record<string, Record<string, IEncryptedContent>> = {};
for (const [userId, devices] of Object.entries(devicesByUser)) {
contentMap[userId] = {};
for (const deviceInfo of devices) {
const encryptedContent = {
const encryptedContent: IEncryptedContent = {
algorithm: olmlib.OLM_ALGORITHM,
sender_key: this.olmDevice.deviceCurve25519Key,
ciphertext: {},

View File

@ -282,7 +282,7 @@ class OlmDecryption extends DecryptionAlgorithm {
const sessionIds = await this.olmDevice.getSessionIdsForDevice(theirDeviceIdentityKey);
// try each session in turn.
const decryptionErrors = {};
const decryptionErrors: Record<string, string> = {};
for (let i = 0; i < sessionIds.length; i++) {
const sessionId = sessionIds[i];
try {

View File

@ -58,7 +58,7 @@ import { BackupManager } from "./backup";
import { IStore } from "../store";
import { Room } from "../models/room";
import { RoomMember } from "../models/room-member";
import { MatrixEvent, EventStatus } from "../models/event";
import { MatrixEvent, EventStatus, IClearEvent } from "../models/event";
import { MatrixClient, IKeysUploadResponse, SessionStore, ISignedKey, ICrossSigningKey } from "../client";
import type { EncryptionAlgorithm, DecryptionAlgorithm } from "./algorithms/base";
import type { IRoomEncryption, RoomList } from "./RoomList";
@ -172,10 +172,10 @@ interface ISignableObject {
}
export interface IEventDecryptionResult {
clearEvent: object;
clearEvent: IClearEvent;
forwardingCurve25519KeyChain?: string[];
senderCurve25519Key?: string;
claimedEd25519Key?: string;
forwardingCurve25519KeyChain?: string[];
untrusted?: boolean;
}

View File

@ -67,5 +67,5 @@ export interface IKeyBackupRestoreResult {
export interface IKeyBackupRestoreOpts {
cacheCompleteCallback?: () => void;
progressCallback?: ({ stage: string }) => void;
progressCallback?: (progress: { stage: string }) => void;
}

View File

@ -27,7 +27,6 @@ import { Logger } from "loglevel";
import { OlmDevice } from "./OlmDevice";
import { DeviceInfo } from "./deviceinfo";
import { logger } from '../logger';
import * as utils from "../utils";
import { IOneTimeKey } from "./dehydration";
import { MatrixClient } from "../client";
@ -126,7 +125,7 @@ export async function encryptMessageForDevice(
// involved in the session. If we're looking to reduce data transfer in the
// future, we could elide them for subsequent messages.
utils.extend(payload, payloadFields);
Object.assign(payload, payloadFields);
resultsObject[deviceKey] = await olmDevice.encryptMessage(
deviceKey, sessionId, JSON.stringify(payload),

View File

@ -36,7 +36,7 @@ const M_RELATES_TO = "m.relates_to";
* Uses the event id of the initial m.key.verification.request event as a transaction id.
*/
export class InRoomChannel implements IVerificationChannel {
private requestEventId = null;
private requestEventId: string = null;
/**
* @param {MatrixClient} client the matrix client, to send messages with and get current user & device from.

View File

@ -657,7 +657,7 @@ MatrixHttpApi.prototype = {
};
}
const headers = utils.extend({}, opts.headers || {});
const headers = Object.assign({}, opts.headers || {});
const json = opts.json === undefined ? true : opts.json;
let bodyParser = opts.bodyParser;

View File

@ -18,7 +18,6 @@ limitations under the License.
/** @module interactive-auth */
import * as utils from "./utils";
import { logger } from './logger';
import { MatrixClient } from "./client";
import { defer, IDeferred } from "./utils";
@ -68,7 +67,7 @@ export enum AuthType {
export interface IAuthDict {
// [key: string]: any;
type?: string;
// session?: string; // TODO
session?: string;
// TODO: Remove `user` once servers support proper UIA
// See https://github.com/vector-im/element-web/issues/10312
user?: string;
@ -360,12 +359,12 @@ export class InteractiveAuth {
}
// use the sessionid from the last request, if one is present.
let auth;
let auth: IAuthDict;
if (this.data.session) {
auth = {
session: this.data.session,
};
utils.extend(auth, authData);
Object.assign(auth, authData);
} else {
auth = authData;
}

View File

@ -76,7 +76,7 @@ function extendLogger(logger: PrefixedLogger) {
extendLogger(logger);
function getPrefixedLogger(prefix): PrefixedLogger {
function getPrefixedLogger(prefix: string): PrefixedLogger {
const prefixLogger: PrefixedLogger = log.getLogger(`${DEFAULT_NAMESPACE}-${prefix}`);
if (prefixLogger.prefix !== prefix) {
// Only do this setup work the first time through, as loggers are saved by name.

View File

@ -121,7 +121,7 @@ export interface ICryptoCallbacks {
) => Promise<string>;
getDehydrationKey?: (
keyInfo: ISecretStorageKeyInfo,
checkFunc: (Uint8Array) => void,
checkFunc: (key: Uint8Array) => void,
) => Promise<Uint8Array>;
getBackupKey?: () => Promise<Uint8Array>;
}

View File

@ -33,7 +33,7 @@ import { Thread } from "./thread";
// var DEBUG = false;
const DEBUG = true;
let debuglog;
let debuglog: (...args: any[]) => void;
if (DEBUG) {
// using bind means that we get to keep useful line numbers in the console
debuglog = logger.log.bind(logger);

View File

@ -29,7 +29,7 @@ import {
MsgType,
RelationType,
} from "../@types/event";
import { Crypto } from "../crypto";
import { Crypto, IEventDecryptionResult } from "../crypto";
import { deepSortedObjectEntries } from "../utils";
import { RoomMember } from "./room-member";
import { Thread, ThreadEvent } from "./thread";
@ -85,7 +85,7 @@ export interface IUnsigned {
age?: number;
prev_sender?: string;
prev_content?: IContent;
redacted_because?: IEvent;
redacted_because?: IClearEvent;
transaction_id?: string;
invite_room_state?: StrippedState[];
}
@ -124,25 +124,13 @@ export interface IEventRelation {
key?: string;
}
interface IDecryptionResult {
clearEvent: {
room_id?: string;
type: string;
content: IContent;
unsigned?: IUnsigned;
};
forwardingCurve25519KeyChain?: string[];
senderCurve25519Key?: string;
claimedEd25519Key?: string;
untrusted?: boolean;
}
/* eslint-enable camelcase */
export interface IClearEvent {
room_id?: string;
type: string;
content: Omit<IContent, "membership" | "avatar_url" | "displayname" | "m.relates_to">;
unsigned?: IUnsigned;
}
/* eslint-enable camelcase */
interface IKeyRequestRecipient {
userId: string;
@ -215,14 +203,14 @@ export class MatrixEvent extends EventEmitter {
public sender: RoomMember = null;
public target: RoomMember = null;
public status: EventStatus = null;
public error = null;
public error: Error = null;
public forwardLooking = true;
/* If the event is a `m.key.verification.request` (or to_device `m.key.verification.start`) event,
* `Crypto` will set this the `VerificationRequest` for the event
* so it can be easily accessed from the timeline.
*/
public verificationRequest = null;
public verificationRequest: VerificationRequest = null;
private readonly reEmitter: ReEmitter;
@ -690,8 +678,8 @@ export class MatrixEvent extends EventEmitter {
while (true) {
this.retryDecryption = false;
let res;
let err;
let res: IEventDecryptionResult;
let err: Error;
try {
if (!crypto) {
res = this.badEncryptedMessage("Encryption not enabled");
@ -779,7 +767,7 @@ export class MatrixEvent extends EventEmitter {
}
}
private badEncryptedMessage(reason: string): IDecryptionResult {
private badEncryptedMessage(reason: string): IEventDecryptionResult {
return {
clearEvent: {
type: "m.room.message",
@ -803,7 +791,7 @@ export class MatrixEvent extends EventEmitter {
* @param {module:crypto~EventDecryptionResult} decryptionResult
* the decryption result, including the plaintext and some key info
*/
private setClearData(decryptionResult: IDecryptionResult): void {
private setClearData(decryptionResult: IEventDecryptionResult): void {
this.clearEvent = decryptionResult.clearEvent;
this.senderCurve25519Key =
decryptionResult.senderCurve25519Key || null;

View File

@ -48,19 +48,19 @@ const SAFE_ROOM_VERSIONS = ['1', '2', '3', '4', '5', '6'];
function synthesizeReceipt(userId: string, event: MatrixEvent, receiptType: string): MatrixEvent {
// console.log("synthesizing receipt for "+event.getId());
// This is really ugly because JS has no way to express an object literal
// where the name of a key comes from an expression
const fakeReceipt = {
content: {},
return new MatrixEvent({
content: {
[event.getId()]: {
[receiptType]: {
[userId]: {
ts: event.getTs(),
},
},
},
},
type: "m.receipt",
room_id: event.getRoomId(),
};
fakeReceipt.content[event.getId()] = {};
fakeReceipt.content[event.getId()][receiptType] = {};
fakeReceipt.content[event.getId()][receiptType][userId] = {
ts: event.getTs(),
};
return new MatrixEvent(fakeReceipt);
});
}
interface IOpts {
@ -240,7 +240,7 @@ export class Room extends EventEmitter {
const serializedPendingEventList = client.sessionStore.store.getItem(pendingEventsKey(this.roomId));
if (serializedPendingEventList) {
JSON.parse(serializedPendingEventList)
.forEach(async serializedEvent => {
.forEach(async (serializedEvent: Partial<IEvent>) => {
const event = new MatrixEvent(serializedEvent);
if (event.getType() === EventType.RoomMessageEncrypted) {
await event.attemptDecryption(this.client.crypto);
@ -997,14 +997,14 @@ export class Room extends EventEmitter {
* @return {array} The room's alias as an array of strings
*/
public getAliases(): string[] {
const aliasStrings = [];
const aliasStrings: string[] = [];
const aliasEvents = this.currentState.getStateEvents(EventType.RoomAliases);
if (aliasEvents) {
for (let i = 0; i < aliasEvents.length; ++i) {
const aliasEvent = aliasEvents[i];
if (Array.isArray(aliasEvent.getContent().aliases)) {
const filteredAliases = aliasEvent.getContent().aliases.filter(a => {
const filteredAliases = aliasEvent.getContent<{ aliases: string[] }>().aliases.filter(a => {
if (typeof(a) !== "string") return false;
if (a[0] !== '#') return false;
if (!a.endsWith(`:${aliasEvent.getStateKey()}`)) return false;
@ -1992,7 +1992,7 @@ export class Room extends EventEmitter {
* @return {Object} Map of receipts by event ID
*/
private buildReceiptCache(receipts: Receipts): ReceiptCache {
const receiptCacheByEventId = {};
const receiptCacheByEventId: ReceiptCache = {};
Object.keys(receipts).forEach(function(receiptType) {
Object.keys(receipts[receiptType]).forEach(function(userId) {
const receipt = receipts[receiptType][userId];
@ -2185,7 +2185,7 @@ export class Room extends EventEmitter {
}
// get members that are NOT ourselves and are actually in the room.
let otherNames = null;
let otherNames: string[] = null;
if (this.summaryHeroes) {
// if we have a summary, the member state events
// should be in the room state
@ -2266,31 +2266,29 @@ function pendingEventsKey(roomId: string): string {
/* a map from current event status to a list of allowed next statuses
*/
const ALLOWED_TRANSITIONS = {};
ALLOWED_TRANSITIONS[EventStatus.ENCRYPTING] = [
EventStatus.SENDING,
EventStatus.NOT_SENT,
];
ALLOWED_TRANSITIONS[EventStatus.SENDING] = [
EventStatus.ENCRYPTING,
EventStatus.QUEUED,
EventStatus.NOT_SENT,
EventStatus.SENT,
];
ALLOWED_TRANSITIONS[EventStatus.QUEUED] =
[EventStatus.SENDING, EventStatus.CANCELLED];
ALLOWED_TRANSITIONS[EventStatus.SENT] =
[];
ALLOWED_TRANSITIONS[EventStatus.NOT_SENT] =
[EventStatus.SENDING, EventStatus.QUEUED, EventStatus.CANCELLED];
ALLOWED_TRANSITIONS[EventStatus.CANCELLED] =
[];
const ALLOWED_TRANSITIONS: Record<EventStatus, EventStatus[]> = {
[EventStatus.ENCRYPTING]: [
EventStatus.SENDING,
EventStatus.NOT_SENT,
],
[EventStatus.SENDING]: [
EventStatus.ENCRYPTING,
EventStatus.QUEUED,
EventStatus.NOT_SENT,
EventStatus.SENT,
],
[EventStatus.QUEUED]: [
EventStatus.SENDING,
EventStatus.CANCELLED,
],
[EventStatus.SENT]: [],
[EventStatus.NOT_SENT]: [
EventStatus.SENDING,
EventStatus.QUEUED,
EventStatus.CANCELLED,
],
[EventStatus.CANCELLED]: [],
};
// TODO i18n
function memberNamesToRoomName(names: string[], count = (names.length + 1)) {

View File

@ -284,7 +284,7 @@ export class MatrixScheduler<T = ISendEventResponse> {
}
}
function debuglog(...args) {
function debuglog(...args: any[]) {
if (DEBUG) {
logger.log(...args);
}

View File

@ -51,14 +51,14 @@ export interface IStore {
* Set the sync token.
* @param {string} token
*/
setSyncToken(token: string);
setSyncToken(token: string): void;
/**
* No-op.
* @param {Group} group
* @deprecated groups/communities never made it to the spec and support for them is being discontinued.
*/
storeGroup(group: Group);
storeGroup(group: Group): void;
/**
* No-op.
@ -79,7 +79,7 @@ export interface IStore {
* No-op.
* @param {Room} room
*/
storeRoom(room: Room);
storeRoom(room: Room): void;
/**
* No-op.
@ -98,7 +98,7 @@ export interface IStore {
* Permanently delete a room.
* @param {string} roomId
*/
removeRoom(roomId: string);
removeRoom(roomId: string): void;
/**
* No-op.
@ -110,7 +110,7 @@ export interface IStore {
* No-op.
* @param {User} user
*/
storeUser(user: User);
storeUser(user: User): void;
/**
* No-op.
@ -140,13 +140,13 @@ export interface IStore {
* @param {string} token The token associated with these events.
* @param {boolean} toStart True if these are paginated results.
*/
storeEvents(room: Room, events: MatrixEvent[], token: string, toStart: boolean);
storeEvents(room: Room, events: MatrixEvent[], token: string, toStart: boolean): void;
/**
* Store a filter.
* @param {Filter} filter
*/
storeFilter(filter: Filter);
storeFilter(filter: Filter): void;
/**
* Retrieve a filter.
@ -168,13 +168,13 @@ export interface IStore {
* @param {string} filterName
* @param {string} filterId
*/
setFilterIdByName(filterName: string, filterId: string);
setFilterIdByName(filterName: string, filterId: string): void;
/**
* Store user-scoped account data events
* @param {Array<MatrixEvent>} events The events to store.
*/
storeAccountDataEvents(events: MatrixEvent[]);
storeAccountDataEvents(events: MatrixEvent[]): void;
/**
* Get account data event by event type

View File

@ -66,7 +66,7 @@ function selectQuery<T>(
): Promise<T[]> {
const query = store.openCursor(keyRange);
return new Promise((resolve, reject) => {
const results = [];
const results: T[] = [];
query.onerror = () => {
reject(new Error("Query failed: " + query.error));
};
@ -238,7 +238,7 @@ export class LocalIndexedDBStoreBackend implements IIndexedDBBackend {
const range = IDBKeyRange.only(roomId);
const request = roomIndex.openCursor(range);
const membershipEvents = [];
const membershipEvents: IEvent[] = [];
// did we encounter the oob_written marker object
// amongst the results? That means OOB member
// loading already happened for this room

View File

@ -90,23 +90,20 @@ export function removeElement<T>(
array: T[],
fn: (t: T, i?: number, a?: T[]) => boolean,
reverse?: boolean,
) {
let i;
let removed;
): boolean {
let i: number;
if (reverse) {
for (i = array.length - 1; i >= 0; i--) {
if (fn(array[i], i, array)) {
removed = array[i];
array.splice(i, 1);
return removed;
return true;
}
}
} else {
for (i = 0; i < array.length; i++) {
if (fn(array[i], i, array)) {
removed = array[i];
array.splice(i, 1);
return removed;
return true;
}
}
}
@ -276,31 +273,6 @@ export function deepSortedObjectEntries(obj: any): [string, any][] {
return pairs;
}
/**
* Copy properties from one object to another.
*
* All enumerable properties, included inherited ones, are copied.
*
* This is approximately equivalent to ES6's Object.assign, except
* that the latter doesn't copy inherited properties.
*
* @param {Object} target The object that will receive new properties
* @param {...Object} source Objects from which to copy properties
*
* @return {Object} target
*/
export function extend(...restParams) {
const target = restParams[0] || {};
for (let i = 1; i < restParams.length; i++) {
const source = restParams[i];
if (!source) continue;
for (const propName in source) { // eslint-disable-line guard-for-in
target[propName] = source[propName];
}
}
return target;
}
/**
* Inherit the prototype methods from one constructor into another. This is a
* port of the Node.js implementation with an Object.create polyfill.