You've already forked matrix-js-sdk
mirror of
https://github.com/matrix-org/matrix-js-sdk.git
synced 2025-07-31 15:24:23 +03:00
Iterate typing to work towards noImplicitAny (#2061)
This commit is contained in:
committed by
GitHub
parent
aeec4aa4a8
commit
963c7690b6
@ -312,7 +312,7 @@ describe("MSC3089Branch", () => {
|
|||||||
} as MatrixEvent);
|
} as MatrixEvent);
|
||||||
|
|
||||||
const events = [await branch.getFileEvent(), await branch2.getFileEvent(), {
|
const events = [await branch.getFileEvent(), await branch2.getFileEvent(), {
|
||||||
replacingEventId: () => null,
|
replacingEventId: (): string => null,
|
||||||
getId: () => "$unknown",
|
getId: () => "$unknown",
|
||||||
}];
|
}];
|
||||||
staticRoom.getLiveTimeline = () => ({ getEvents: () => events }) as EventTimeline;
|
staticRoom.getLiveTimeline = () => ({ getEvents: () => events }) as EventTimeline;
|
||||||
|
6
src/@types/global.d.ts
vendored
6
src/@types/global.d.ts
vendored
@ -62,12 +62,6 @@ declare global {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
interface HTMLAudioElement {
|
|
||||||
// sinkId & setSinkId are experimental and typescript doesn't know about them
|
|
||||||
sinkId: string;
|
|
||||||
setSinkId(outputId: string);
|
|
||||||
}
|
|
||||||
|
|
||||||
interface DummyInterfaceWeShouldntBeUsingThis {}
|
interface DummyInterfaceWeShouldntBeUsingThis {}
|
||||||
|
|
||||||
interface Navigator {
|
interface Navigator {
|
||||||
|
@ -621,7 +621,7 @@ export interface IMyDevice {
|
|||||||
last_seen_ts?: number;
|
last_seen_ts?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IDownloadKeyResult {
|
export interface IDownloadKeyResult {
|
||||||
failures: { [serverName: string]: object };
|
failures: { [serverName: string]: object };
|
||||||
device_keys: {
|
device_keys: {
|
||||||
[userId: string]: {
|
[userId: string]: {
|
||||||
@ -632,13 +632,42 @@ interface IDownloadKeyResult {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
// the following three fields were added in 1.1
|
||||||
|
master_keys?: {
|
||||||
|
[userId: string]: {
|
||||||
|
keys: { [keyId: string]: string };
|
||||||
|
usage: string[];
|
||||||
|
user_id: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
self_signing_keys?: {
|
||||||
|
[userId: string]: {
|
||||||
|
keys: { [keyId: string]: string };
|
||||||
|
signatures: ISignatures;
|
||||||
|
usage: string[];
|
||||||
|
user_id: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
user_signing_keys?: {
|
||||||
|
[userId: string]: {
|
||||||
|
keys: { [keyId: string]: string };
|
||||||
|
signatures: ISignatures;
|
||||||
|
usage: string[];
|
||||||
|
user_id: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IClaimOTKsResult {
|
export interface IClaimOTKsResult {
|
||||||
failures: { [serverName: string]: object };
|
failures: { [serverName: string]: object };
|
||||||
one_time_keys: {
|
one_time_keys: {
|
||||||
[userId: string]: {
|
[userId: string]: {
|
||||||
[deviceId: string]: string;
|
[deviceId: string]: {
|
||||||
|
[keyId: string]: {
|
||||||
|
key: string;
|
||||||
|
signatures: ISignatures;
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -1421,14 +1450,12 @@ export class MatrixClient extends EventEmitter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// We swallow errors because we need a default object anyhow
|
|
||||||
return this.http.authedRequest(
|
return this.http.authedRequest(
|
||||||
undefined, "GET", "/capabilities",
|
undefined, "GET", "/capabilities",
|
||||||
).catch((e: Error) => {
|
).catch((e: Error): void => {
|
||||||
|
// We swallow errors because we need a default object anyhow
|
||||||
logger.error(e);
|
logger.error(e);
|
||||||
return null; // otherwise consume the error
|
}).then((r: { capabilities?: ICapabilities } = {}) => {
|
||||||
}).then((r) => {
|
|
||||||
if (!r) r = {};
|
|
||||||
const capabilities: ICapabilities = r["capabilities"] || {};
|
const capabilities: ICapabilities = r["capabilities"] || {};
|
||||||
|
|
||||||
// If the capabilities missed the cache, cache it for a shorter amount
|
// If the capabilities missed the cache, cache it for a shorter amount
|
||||||
@ -2836,7 +2863,7 @@ export class MatrixClient extends EventEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let totalKeyCount = 0;
|
let totalKeyCount = 0;
|
||||||
let keys = [];
|
let keys: IMegolmSessionData[] = [];
|
||||||
|
|
||||||
const path = this.makeKeyBackupPath(targetRoomId, targetSessionId, backupInfo.version);
|
const path = this.makeKeyBackupPath(targetRoomId, targetSessionId, backupInfo.version);
|
||||||
|
|
||||||
@ -5692,18 +5719,14 @@ export class MatrixClient extends EventEmitter {
|
|||||||
searchResults.count = roomEvents.count;
|
searchResults.count = roomEvents.count;
|
||||||
searchResults.next_batch = roomEvents.next_batch;
|
searchResults.next_batch = roomEvents.next_batch;
|
||||||
|
|
||||||
// combine the highlight list with our existing list; build an object
|
// combine the highlight list with our existing list;
|
||||||
// to avoid O(N^2) fail
|
const highlights = new Set<string>(roomEvents.highlights);
|
||||||
const highlights = {};
|
|
||||||
roomEvents.highlights.forEach((hl) => {
|
|
||||||
highlights[hl] = 1;
|
|
||||||
});
|
|
||||||
searchResults.highlights.forEach((hl) => {
|
searchResults.highlights.forEach((hl) => {
|
||||||
highlights[hl] = 1;
|
highlights.add(hl);
|
||||||
});
|
});
|
||||||
|
|
||||||
// turn it back into a list.
|
// turn it back into a list.
|
||||||
searchResults.highlights = Object.keys(highlights);
|
searchResults.highlights = Array.from(highlights);
|
||||||
|
|
||||||
// append the new results to our existing results
|
// append the new results to our existing results
|
||||||
const resultsLength = roomEvents.results ? roomEvents.results.length : 0;
|
const resultsLength = roomEvents.results ? roomEvents.results.length : 0;
|
||||||
@ -5794,11 +5817,9 @@ export class MatrixClient extends EventEmitter {
|
|||||||
|
|
||||||
return this.http.authedRequest(
|
return this.http.authedRequest(
|
||||||
undefined, "GET", path, undefined, undefined,
|
undefined, "GET", path, undefined, undefined,
|
||||||
).then((response) => {
|
).then((response: IFilterDefinition) => {
|
||||||
// persist the filter
|
// persist the filter
|
||||||
const filter = Filter.fromJson(
|
const filter = Filter.fromJson(userId, filterId, response);
|
||||||
userId, filterId, response,
|
|
||||||
);
|
|
||||||
this.store.storeFilter(filter);
|
this.store.storeFilter(filter);
|
||||||
return filter;
|
return filter;
|
||||||
});
|
});
|
||||||
@ -6096,7 +6117,7 @@ export class MatrixClient extends EventEmitter {
|
|||||||
{
|
{
|
||||||
prefix: '',
|
prefix: '',
|
||||||
},
|
},
|
||||||
).catch((e) => {
|
).catch((e: Error) => {
|
||||||
// Need to unset this if it fails, otherwise we'll never retry
|
// Need to unset this if it fails, otherwise we'll never retry
|
||||||
this.serverVersionsPromise = null;
|
this.serverVersionsPromise = null;
|
||||||
// but rethrow the exception to anything that was waiting
|
// but rethrow the exception to anything that was waiting
|
||||||
@ -6420,7 +6441,7 @@ export class MatrixClient extends EventEmitter {
|
|||||||
public isUsernameAvailable(username: string): Promise<true> {
|
public isUsernameAvailable(username: string): Promise<true> {
|
||||||
return this.http.authedRequest(
|
return this.http.authedRequest(
|
||||||
undefined, "GET", '/register/available', { username: username },
|
undefined, "GET", '/register/available', { username: username },
|
||||||
).then((response) => {
|
).then((response: { available: boolean }) => {
|
||||||
return response.available;
|
return response.available;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -7741,11 +7762,11 @@ export class MatrixClient extends EventEmitter {
|
|||||||
* an error response ({@link module:http-api.MatrixError}).
|
* an error response ({@link module:http-api.MatrixError}).
|
||||||
*/
|
*/
|
||||||
public claimOneTimeKeys(
|
public claimOneTimeKeys(
|
||||||
devices: string[],
|
devices: [string, string][],
|
||||||
keyAlgorithm = "signed_curve25519",
|
keyAlgorithm = "signed_curve25519",
|
||||||
timeout?: number,
|
timeout?: number,
|
||||||
): Promise<IClaimOTKsResult> {
|
): Promise<IClaimOTKsResult> {
|
||||||
const queries = {};
|
const queries: Record<string, Record<string, string>> = {};
|
||||||
|
|
||||||
if (keyAlgorithm === undefined) {
|
if (keyAlgorithm === undefined) {
|
||||||
keyAlgorithm = "signed_curve25519";
|
keyAlgorithm = "signed_curve25519";
|
||||||
|
@ -33,6 +33,7 @@ import { OlmDevice } from "./OlmDevice";
|
|||||||
import { ICryptoCallbacks } from "../matrix";
|
import { ICryptoCallbacks } from "../matrix";
|
||||||
import { ISignatures } from "../@types/signed";
|
import { ISignatures } from "../@types/signed";
|
||||||
import { CryptoStore } from "./store/base";
|
import { CryptoStore } from "./store/base";
|
||||||
|
import { ISecretStorageKeyInfo } from "./api";
|
||||||
|
|
||||||
const KEY_REQUEST_TIMEOUT_MS = 1000 * 60;
|
const KEY_REQUEST_TIMEOUT_MS = 1000 * 60;
|
||||||
|
|
||||||
@ -175,7 +176,7 @@ export class CrossSigningInfo extends EventEmitter {
|
|||||||
// check what SSSS keys have encrypted the master key (if any)
|
// check what SSSS keys have encrypted the master key (if any)
|
||||||
const stored = await secretStorage.isStored("m.cross_signing.master", false) || {};
|
const stored = await secretStorage.isStored("m.cross_signing.master", false) || {};
|
||||||
// then check which of those SSSS keys have also encrypted the SSK and USK
|
// then check which of those SSSS keys have also encrypted the SSK and USK
|
||||||
function intersect(s) {
|
function intersect(s: Record<string, ISecretStorageKeyInfo>) {
|
||||||
for (const k of Object.keys(stored)) {
|
for (const k of Object.keys(stored)) {
|
||||||
if (!s[k]) {
|
if (!s[k]) {
|
||||||
delete stored[k];
|
delete stored[k];
|
||||||
|
@ -28,7 +28,7 @@ import { CrossSigningInfo, ICrossSigningInfo } from './CrossSigning';
|
|||||||
import * as olmlib from './olmlib';
|
import * as olmlib from './olmlib';
|
||||||
import { IndexedDBCryptoStore } from './store/indexeddb-crypto-store';
|
import { IndexedDBCryptoStore } from './store/indexeddb-crypto-store';
|
||||||
import { chunkPromises, defer, IDeferred, sleep } from '../utils';
|
import { chunkPromises, defer, IDeferred, sleep } from '../utils';
|
||||||
import { MatrixClient } from "../client";
|
import { IDownloadKeyResult, MatrixClient } from "../client";
|
||||||
import { OlmDevice } from "./OlmDevice";
|
import { OlmDevice } from "./OlmDevice";
|
||||||
import { CryptoStore } from "./store/base";
|
import { CryptoStore } from "./store/base";
|
||||||
|
|
||||||
@ -756,17 +756,21 @@ class DeviceListUpdateSerialiser {
|
|||||||
opts.token = this.syncToken;
|
opts.token = this.syncToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
const factories = [];
|
const factories: Array<() => Promise<IDownloadKeyResult>> = [];
|
||||||
for (let i = 0; i < downloadUsers.length; i += this.deviceList.keyDownloadChunkSize) {
|
for (let i = 0; i < downloadUsers.length; i += this.deviceList.keyDownloadChunkSize) {
|
||||||
const userSlice = downloadUsers.slice(i, i + this.deviceList.keyDownloadChunkSize);
|
const userSlice = downloadUsers.slice(i, i + this.deviceList.keyDownloadChunkSize);
|
||||||
factories.push(() => this.baseApis.downloadKeysForUsers(userSlice, opts));
|
factories.push(() => this.baseApis.downloadKeysForUsers(userSlice, opts));
|
||||||
}
|
}
|
||||||
|
|
||||||
chunkPromises(factories, 3).then(async (responses: any[]) => {
|
chunkPromises(factories, 3).then(async (responses: IDownloadKeyResult[]) => {
|
||||||
const dk = Object.assign({}, ...(responses.map(res => res.device_keys || {})));
|
const dk: IDownloadKeyResult["device_keys"]
|
||||||
const masterKeys = Object.assign({}, ...(responses.map(res => res.master_keys || {})));
|
= Object.assign({}, ...(responses.map(res => res.device_keys || {})));
|
||||||
const ssks = Object.assign({}, ...(responses.map(res => res.self_signing_keys || {})));
|
const masterKeys: IDownloadKeyResult["master_keys"]
|
||||||
const usks = Object.assign({}, ...(responses.map(res => res.user_signing_keys || {})));
|
= Object.assign({}, ...(responses.map(res => res.master_keys || {})));
|
||||||
|
const ssks: IDownloadKeyResult["self_signing_keys"]
|
||||||
|
= Object.assign({}, ...(responses.map(res => res.self_signing_keys || {})));
|
||||||
|
const usks: IDownloadKeyResult["user_signing_keys"]
|
||||||
|
= Object.assign({}, ...(responses.map(res => res.user_signing_keys || {})));
|
||||||
|
|
||||||
// yield to other things that want to execute in between users, to
|
// yield to other things that want to execute in between users, to
|
||||||
// avoid wedging the CPU
|
// avoid wedging the CPU
|
||||||
@ -811,8 +815,12 @@ class DeviceListUpdateSerialiser {
|
|||||||
|
|
||||||
private async processQueryResponseForUser(
|
private async processQueryResponseForUser(
|
||||||
userId: string,
|
userId: string,
|
||||||
dkResponse: object,
|
dkResponse: IDownloadKeyResult["device_keys"]["user_id"],
|
||||||
crossSigningResponse: any, // TODO types
|
crossSigningResponse: {
|
||||||
|
master: IDownloadKeyResult["master_keys"]["user_id"];
|
||||||
|
self_signing: IDownloadKeyResult["master_keys"]["user_id"]; // eslint-disable-line camelcase
|
||||||
|
user_signing: IDownloadKeyResult["user_signing_keys"]["user_id"]; // eslint-disable-line camelcase
|
||||||
|
},
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
logger.log('got device keys for ' + userId + ':', dkResponse);
|
logger.log('got device keys for ' + userId + ':', dkResponse);
|
||||||
logger.log('got cross-signing keys for ' + userId + ':', crossSigningResponse);
|
logger.log('got cross-signing keys for ' + userId + ':', crossSigningResponse);
|
||||||
@ -869,7 +877,7 @@ async function updateStoredDeviceKeysForUser(
|
|||||||
olmDevice: OlmDevice,
|
olmDevice: OlmDevice,
|
||||||
userId: string,
|
userId: string,
|
||||||
userStore: Record<string, DeviceInfo>,
|
userStore: Record<string, DeviceInfo>,
|
||||||
userResult: object,
|
userResult: IDownloadKeyResult["device_keys"]["user_id"],
|
||||||
localUserId: string,
|
localUserId: string,
|
||||||
localDeviceId: string,
|
localDeviceId: string,
|
||||||
): Promise<boolean> {
|
): Promise<boolean> {
|
||||||
|
@ -33,6 +33,7 @@ import { encryptAES, decryptAES, calculateKeyCheck } from './aes';
|
|||||||
import { getCrypto } from '../utils';
|
import { getCrypto } from '../utils';
|
||||||
import { ICurve25519AuthData, IAes256AuthData, IKeyBackupInfo, IKeyBackupSession } from "./keybackup";
|
import { ICurve25519AuthData, IAes256AuthData, IKeyBackupInfo, IKeyBackupSession } from "./keybackup";
|
||||||
import { UnstableValue } from "../NamespacedValue";
|
import { UnstableValue } from "../NamespacedValue";
|
||||||
|
import { IMegolmSessionData } from "./index";
|
||||||
|
|
||||||
const KEY_BACKUP_KEYS_PER_REQUEST = 200;
|
const KEY_BACKUP_KEYS_PER_REQUEST = 200;
|
||||||
|
|
||||||
@ -87,7 +88,7 @@ interface BackupAlgorithmClass {
|
|||||||
interface BackupAlgorithm {
|
interface BackupAlgorithm {
|
||||||
untrusted: boolean;
|
untrusted: boolean;
|
||||||
encryptSession(data: Record<string, any>): Promise<any>;
|
encryptSession(data: Record<string, any>): Promise<any>;
|
||||||
decryptSessions(ciphertexts: Record<string, IKeyBackupSession>): Promise<Record<string, any>[]>;
|
decryptSessions(ciphertexts: Record<string, IKeyBackupSession>): Promise<IMegolmSessionData[]>;
|
||||||
authData: AuthData;
|
authData: AuthData;
|
||||||
keyMatches(key: ArrayLike<number>): Promise<boolean>;
|
keyMatches(key: ArrayLike<number>): Promise<boolean>;
|
||||||
free(): void;
|
free(): void;
|
||||||
@ -300,7 +301,7 @@ export class BackupManager {
|
|||||||
const ret = {
|
const ret = {
|
||||||
usable: false,
|
usable: false,
|
||||||
trusted_locally: false,
|
trusted_locally: false,
|
||||||
sigs: [],
|
sigs: [] as SigInfo[],
|
||||||
};
|
};
|
||||||
|
|
||||||
if (
|
if (
|
||||||
@ -320,7 +321,7 @@ export class BackupManager {
|
|||||||
ret.trusted_locally = true;
|
ret.trusted_locally = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const mySigs = backupInfo.auth_data.signatures[this.baseApis.getUserId()] || [];
|
const mySigs = backupInfo.auth_data.signatures[this.baseApis.getUserId()] || {};
|
||||||
|
|
||||||
for (const keyId of Object.keys(mySigs)) {
|
for (const keyId of Object.keys(mySigs)) {
|
||||||
const keyIdParts = keyId.split(':');
|
const keyIdParts = keyId.split(':');
|
||||||
@ -645,9 +646,7 @@ export class Curve25519 implements BackupAlgorithm {
|
|||||||
return this.publicKey.encrypt(JSON.stringify(plainText));
|
return this.publicKey.encrypt(JSON.stringify(plainText));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async decryptSessions(
|
public async decryptSessions(sessions: Record<string, IKeyBackupSession>): Promise<IMegolmSessionData[]> {
|
||||||
sessions: Record<string, IKeyBackupSession>,
|
|
||||||
): Promise<Record<string, any>[]> {
|
|
||||||
const privKey = await this.getKey();
|
const privKey = await this.getKey();
|
||||||
const decryption = new global.Olm.PkDecryption();
|
const decryption = new global.Olm.PkDecryption();
|
||||||
try {
|
try {
|
||||||
@ -658,7 +657,7 @@ export class Curve25519 implements BackupAlgorithm {
|
|||||||
throw { errcode: MatrixClient.RESTORE_BACKUP_ERROR_BAD_KEY };
|
throw { errcode: MatrixClient.RESTORE_BACKUP_ERROR_BAD_KEY };
|
||||||
}
|
}
|
||||||
|
|
||||||
const keys = [];
|
const keys: IMegolmSessionData[] = [];
|
||||||
|
|
||||||
for (const [sessionId, sessionData] of Object.entries(sessions)) {
|
for (const [sessionId, sessionData] of Object.entries(sessions)) {
|
||||||
try {
|
try {
|
||||||
@ -777,8 +776,8 @@ export class Aes256 implements BackupAlgorithm {
|
|||||||
return await encryptAES(JSON.stringify(plainText), this.key, data.session_id);
|
return await encryptAES(JSON.stringify(plainText), this.key, data.session_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
async decryptSessions(sessions: Record<string, IKeyBackupSession>): Promise<Record<string, any>[]> {
|
async decryptSessions(sessions: Record<string, IKeyBackupSession>): Promise<IMegolmSessionData[]> {
|
||||||
const keys = [];
|
const keys: IMegolmSessionData[] = [];
|
||||||
|
|
||||||
for (const [sessionId, sessionData] of Object.entries(sessions)) {
|
for (const [sessionId, sessionData] of Object.entries(sessions)) {
|
||||||
try {
|
try {
|
||||||
|
@ -22,9 +22,7 @@ import { decryptAES, encryptAES } from './aes';
|
|||||||
import { logger } from '../logger';
|
import { logger } from '../logger';
|
||||||
import { ISecretStorageKeyInfo } from "./api";
|
import { ISecretStorageKeyInfo } from "./api";
|
||||||
import { Crypto } from "./index";
|
import { Crypto } from "./index";
|
||||||
|
import { ISignatures } from "../@types/signed";
|
||||||
// FIXME: these types should eventually go in a different file
|
|
||||||
type Signatures = Record<string, Record<string, string>>;
|
|
||||||
|
|
||||||
export interface IDehydratedDevice {
|
export interface IDehydratedDevice {
|
||||||
device_id: string; // eslint-disable-line camelcase
|
device_id: string; // eslint-disable-line camelcase
|
||||||
@ -43,13 +41,13 @@ export interface IDeviceKeys {
|
|||||||
device_id: string; // eslint-disable-line camelcase
|
device_id: string; // eslint-disable-line camelcase
|
||||||
user_id: string; // eslint-disable-line camelcase
|
user_id: string; // eslint-disable-line camelcase
|
||||||
keys: Record<string, string>;
|
keys: Record<string, string>;
|
||||||
signatures?: Signatures;
|
signatures?: ISignatures;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IOneTimeKey {
|
export interface IOneTimeKey {
|
||||||
key: string;
|
key: string;
|
||||||
fallback?: boolean;
|
fallback?: boolean;
|
||||||
signatures?: Signatures;
|
signatures?: ISignatures;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const DEHYDRATION_ALGORITHM = "org.matrix.msc2697.v1.olm.libolm_pickle";
|
export const DEHYDRATION_ALGORITHM = "org.matrix.msc2697.v1.olm.libolm_pickle";
|
||||||
@ -244,7 +242,7 @@ export class DehydrationManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
logger.log("Preparing one-time keys");
|
logger.log("Preparing one-time keys");
|
||||||
const oneTimeKeys = {};
|
const oneTimeKeys: Record<string, IOneTimeKey> = {};
|
||||||
for (const [keyId, key] of Object.entries(otks.curve25519)) {
|
for (const [keyId, key] of Object.entries(otks.curve25519)) {
|
||||||
const k: IOneTimeKey = { key };
|
const k: IOneTimeKey = { key };
|
||||||
const signature = account.sign(anotherjson.stringify(k));
|
const signature = account.sign(anotherjson.stringify(k));
|
||||||
|
@ -179,6 +179,13 @@ export interface IEventDecryptionResult {
|
|||||||
untrusted?: boolean;
|
untrusted?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface IRequestsMap {
|
||||||
|
getRequest(event: MatrixEvent): VerificationRequest;
|
||||||
|
getRequestByChannel(channel: IVerificationChannel): VerificationRequest;
|
||||||
|
setRequest(event: MatrixEvent, request: VerificationRequest): void;
|
||||||
|
setRequestByChannel(channel: IVerificationChannel, request: VerificationRequest): void;
|
||||||
|
}
|
||||||
|
|
||||||
export class Crypto extends EventEmitter {
|
export class Crypto extends EventEmitter {
|
||||||
/**
|
/**
|
||||||
* @return {string} The version of Olm.
|
* @return {string} The version of Olm.
|
||||||
@ -808,7 +815,7 @@ export class Crypto extends EventEmitter {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const signKeyBackupWithCrossSigning = async (keyBackupAuthData) => {
|
const signKeyBackupWithCrossSigning = async (keyBackupAuthData: IKeyBackupInfo["auth_data"]) => {
|
||||||
if (
|
if (
|
||||||
this.crossSigningInfo.getId() &&
|
this.crossSigningInfo.getId() &&
|
||||||
await this.crossSigningInfo.isStoredInKeyCache("master")
|
await this.crossSigningInfo.isStoredInKeyCache("master")
|
||||||
@ -1148,7 +1155,7 @@ export class Crypto extends EventEmitter {
|
|||||||
const signedDevice = await this.crossSigningInfo.signDevice(this.userId, device);
|
const signedDevice = await this.crossSigningInfo.signDevice(this.userId, device);
|
||||||
logger.info(`Starting background key sig upload for ${this.deviceId}`);
|
logger.info(`Starting background key sig upload for ${this.deviceId}`);
|
||||||
|
|
||||||
const upload = ({ shouldEmit }) => {
|
const upload = ({ shouldEmit = false }) => {
|
||||||
return this.baseApis.uploadKeySignatures({
|
return this.baseApis.uploadKeySignatures({
|
||||||
[this.userId]: {
|
[this.userId]: {
|
||||||
[this.deviceId]: signedDevice,
|
[this.deviceId]: signedDevice,
|
||||||
@ -1184,7 +1191,7 @@ export class Crypto extends EventEmitter {
|
|||||||
|
|
||||||
// Check all users for signatures if upgrade callback present
|
// Check all users for signatures if upgrade callback present
|
||||||
// FIXME: do this in batches
|
// FIXME: do this in batches
|
||||||
const users = {};
|
const users: Record<string, IDeviceVerificationUpgrade> = {};
|
||||||
for (const [userId, crossSigningInfo]
|
for (const [userId, crossSigningInfo]
|
||||||
of Object.entries(this.deviceList.crossSigningInfo)) {
|
of Object.entries(this.deviceList.crossSigningInfo)) {
|
||||||
const upgradeInfo = await this.checkForDeviceVerificationUpgrade(
|
const upgradeInfo = await this.checkForDeviceVerificationUpgrade(
|
||||||
@ -1482,7 +1489,7 @@ export class Crypto extends EventEmitter {
|
|||||||
!crossSigningPrivateKeys.has("user_signing")
|
!crossSigningPrivateKeys.has("user_signing")
|
||||||
);
|
);
|
||||||
|
|
||||||
const keySignatures = {};
|
const keySignatures: Record<string, ISignedKey> = {};
|
||||||
|
|
||||||
if (selfSigningChanged) {
|
if (selfSigningChanged) {
|
||||||
logger.info("Got new self-signing key", newCrossSigning.getId("self_signing"));
|
logger.info("Got new self-signing key", newCrossSigning.getId("self_signing"));
|
||||||
@ -1537,7 +1544,7 @@ export class Crypto extends EventEmitter {
|
|||||||
// We may have existing signatures from deleted devices, which will cause
|
// We may have existing signatures from deleted devices, which will cause
|
||||||
// the entire upload to fail.
|
// the entire upload to fail.
|
||||||
keySignatures[this.crossSigningInfo.getId()] = Object.assign(
|
keySignatures[this.crossSigningInfo.getId()] = Object.assign(
|
||||||
{},
|
{} as ISignedKey,
|
||||||
masterKey,
|
masterKey,
|
||||||
{
|
{
|
||||||
signatures: {
|
signatures: {
|
||||||
@ -1551,7 +1558,7 @@ export class Crypto extends EventEmitter {
|
|||||||
|
|
||||||
const keysToUpload = Object.keys(keySignatures);
|
const keysToUpload = Object.keys(keySignatures);
|
||||||
if (keysToUpload.length) {
|
if (keysToUpload.length) {
|
||||||
const upload = ({ shouldEmit }) => {
|
const upload = ({ shouldEmit = false }) => {
|
||||||
logger.info(`Starting background key sig upload for ${keysToUpload}`);
|
logger.info(`Starting background key sig upload for ${keysToUpload}`);
|
||||||
return this.baseApis.uploadKeySignatures({ [this.userId]: keySignatures })
|
return this.baseApis.uploadKeySignatures({ [this.userId]: keySignatures })
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
@ -1927,7 +1934,7 @@ export class Crypto extends EventEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const oneTimeKeys = await this.olmDevice.getOneTimeKeys();
|
const oneTimeKeys = await this.olmDevice.getOneTimeKeys();
|
||||||
const oneTimeJson = {};
|
const oneTimeJson: Record<string, { key: string }> = {};
|
||||||
|
|
||||||
for (const keyId in oneTimeKeys.curve25519) {
|
for (const keyId in oneTimeKeys.curve25519) {
|
||||||
if (oneTimeKeys.curve25519.hasOwnProperty(keyId)) {
|
if (oneTimeKeys.curve25519.hasOwnProperty(keyId)) {
|
||||||
@ -2076,7 +2083,7 @@ export class Crypto extends EventEmitter {
|
|||||||
);
|
);
|
||||||
const device = await this.crossSigningInfo.signUser(xsk);
|
const device = await this.crossSigningInfo.signUser(xsk);
|
||||||
if (device) {
|
if (device) {
|
||||||
const upload = async ({ shouldEmit }) => {
|
const upload = async ({ shouldEmit = false }) => {
|
||||||
logger.info("Uploading signature for " + userId + "...");
|
logger.info("Uploading signature for " + userId + "...");
|
||||||
const response = await this.baseApis.uploadKeySignatures({
|
const response = await this.baseApis.uploadKeySignatures({
|
||||||
[userId]: {
|
[userId]: {
|
||||||
@ -2149,7 +2156,7 @@ export class Crypto extends EventEmitter {
|
|||||||
logger.info("Own device " + deviceId + " marked verified: signing");
|
logger.info("Own device " + deviceId + " marked verified: signing");
|
||||||
|
|
||||||
// Signing only needed if other device not already signed
|
// Signing only needed if other device not already signed
|
||||||
let device;
|
let device: ISignedKey;
|
||||||
const deviceTrust = this.checkDeviceTrust(userId, deviceId);
|
const deviceTrust = this.checkDeviceTrust(userId, deviceId);
|
||||||
if (deviceTrust.isCrossSigningVerified()) {
|
if (deviceTrust.isCrossSigningVerified()) {
|
||||||
logger.log(`Own device ${deviceId} already cross-signing verified`);
|
logger.log(`Own device ${deviceId} already cross-signing verified`);
|
||||||
@ -2160,7 +2167,7 @@ export class Crypto extends EventEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (device) {
|
if (device) {
|
||||||
const upload = async ({ shouldEmit }) => {
|
const upload = async ({ shouldEmit = false }) => {
|
||||||
logger.info("Uploading signature for " + deviceId);
|
logger.info("Uploading signature for " + deviceId);
|
||||||
const response = await this.baseApis.uploadKeySignatures({
|
const response = await this.baseApis.uploadKeySignatures({
|
||||||
[userId]: {
|
[userId]: {
|
||||||
@ -2204,11 +2211,7 @@ export class Crypto extends EventEmitter {
|
|||||||
return Promise.resolve(existingRequest);
|
return Promise.resolve(existingRequest);
|
||||||
}
|
}
|
||||||
const channel = new InRoomChannel(this.baseApis, roomId, userId);
|
const channel = new InRoomChannel(this.baseApis, roomId, userId);
|
||||||
return this.requestVerificationWithChannel(
|
return this.requestVerificationWithChannel(userId, channel, this.inRoomVerificationRequests);
|
||||||
userId,
|
|
||||||
channel,
|
|
||||||
this.inRoomVerificationRequests,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public requestVerification(userId: string, devices: string[]): Promise<VerificationRequest> {
|
public requestVerification(userId: string, devices: string[]): Promise<VerificationRequest> {
|
||||||
@ -2220,17 +2223,13 @@ export class Crypto extends EventEmitter {
|
|||||||
return Promise.resolve(existingRequest);
|
return Promise.resolve(existingRequest);
|
||||||
}
|
}
|
||||||
const channel = new ToDeviceChannel(this.baseApis, userId, devices, ToDeviceChannel.makeTransactionId());
|
const channel = new ToDeviceChannel(this.baseApis, userId, devices, ToDeviceChannel.makeTransactionId());
|
||||||
return this.requestVerificationWithChannel(
|
return this.requestVerificationWithChannel(userId, channel, this.toDeviceVerificationRequests);
|
||||||
userId,
|
|
||||||
channel,
|
|
||||||
this.toDeviceVerificationRequests,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async requestVerificationWithChannel(
|
private async requestVerificationWithChannel(
|
||||||
userId: string,
|
userId: string,
|
||||||
channel: IVerificationChannel,
|
channel: IVerificationChannel,
|
||||||
requestsMap: any, // TODO types
|
requestsMap: IRequestsMap,
|
||||||
): Promise<VerificationRequest> {
|
): Promise<VerificationRequest> {
|
||||||
let request = new VerificationRequest(channel, this.verificationMethods, this.baseApis);
|
let request = new VerificationRequest(channel, this.verificationMethods, this.baseApis);
|
||||||
// if transaction id is already known, add request
|
// if transaction id is already known, add request
|
||||||
@ -2618,7 +2617,7 @@ export class Crypto extends EventEmitter {
|
|||||||
users: string[],
|
users: string[],
|
||||||
force?: boolean,
|
force?: boolean,
|
||||||
): Promise<Record<string, Record<string, olmlib.IOlmSessionResult>>> {
|
): Promise<Record<string, Record<string, olmlib.IOlmSessionResult>>> {
|
||||||
const devicesByUser = {};
|
const devicesByUser: Record<string, DeviceInfo[]> = {};
|
||||||
|
|
||||||
for (let i = 0; i < users.length; ++i) {
|
for (let i = 0; i < users.length; ++i) {
|
||||||
const userId = users[i];
|
const userId = users[i];
|
||||||
@ -2651,7 +2650,7 @@ export class Crypto extends EventEmitter {
|
|||||||
* @return {module:crypto/OlmDevice.MegolmSessionData[]} a list of session export objects
|
* @return {module:crypto/OlmDevice.MegolmSessionData[]} a list of session export objects
|
||||||
*/
|
*/
|
||||||
public async exportRoomKeys(): Promise<IMegolmSessionData[]> {
|
public async exportRoomKeys(): Promise<IMegolmSessionData[]> {
|
||||||
const exportedSessions = [];
|
const exportedSessions: IMegolmSessionData[] = [];
|
||||||
await this.cryptoStore.doTxn(
|
await this.cryptoStore.doTxn(
|
||||||
'readonly', [IndexedDBCryptoStore.STORE_INBOUND_GROUP_SESSIONS], (txn) => {
|
'readonly', [IndexedDBCryptoStore.STORE_INBOUND_GROUP_SESSIONS], (txn) => {
|
||||||
this.cryptoStore.getAllEndToEndInboundGroupSessions(txn, (s) => {
|
this.cryptoStore.getAllEndToEndInboundGroupSessions(txn, (s) => {
|
||||||
@ -2783,8 +2782,7 @@ export class Crypto extends EventEmitter {
|
|||||||
delete content['io.element.performance_metrics'];
|
delete content['io.element.performance_metrics'];
|
||||||
}
|
}
|
||||||
|
|
||||||
const encryptedContent = await alg.encryptMessage(
|
const encryptedContent = await alg.encryptMessage(room, event.getType(), content);
|
||||||
room, event.getType(), content);
|
|
||||||
|
|
||||||
if (mRelatesTo) {
|
if (mRelatesTo) {
|
||||||
encryptedContent['m.relates_to'] = mRelatesTo;
|
encryptedContent['m.relates_to'] = mRelatesTo;
|
||||||
@ -3154,7 +3152,7 @@ export class Crypto extends EventEmitter {
|
|||||||
if (!ToDeviceChannel.validateEvent(event, this.baseApis)) {
|
if (!ToDeviceChannel.validateEvent(event, this.baseApis)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const createRequest = event => {
|
const createRequest = (event: MatrixEvent) => {
|
||||||
if (!ToDeviceChannel.canCreateRequest(ToDeviceChannel.getEventType(event))) {
|
if (!ToDeviceChannel.canCreateRequest(ToDeviceChannel.getEventType(event))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -3172,11 +3170,7 @@ export class Crypto extends EventEmitter {
|
|||||||
return new VerificationRequest(
|
return new VerificationRequest(
|
||||||
channel, this.verificationMethods, this.baseApis);
|
channel, this.verificationMethods, this.baseApis);
|
||||||
};
|
};
|
||||||
this.handleVerificationEvent(
|
this.handleVerificationEvent(event, this.toDeviceVerificationRequests, createRequest);
|
||||||
event,
|
|
||||||
this.toDeviceVerificationRequests,
|
|
||||||
createRequest,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -3199,7 +3193,7 @@ export class Crypto extends EventEmitter {
|
|||||||
if (!InRoomChannel.validateEvent(event, this.baseApis)) {
|
if (!InRoomChannel.validateEvent(event, this.baseApis)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const createRequest = event => {
|
const createRequest = (event: MatrixEvent) => {
|
||||||
const channel = new InRoomChannel(
|
const channel = new InRoomChannel(
|
||||||
this.baseApis,
|
this.baseApis,
|
||||||
event.getRoomId(),
|
event.getRoomId(),
|
||||||
@ -3207,18 +3201,13 @@ export class Crypto extends EventEmitter {
|
|||||||
return new VerificationRequest(
|
return new VerificationRequest(
|
||||||
channel, this.verificationMethods, this.baseApis);
|
channel, this.verificationMethods, this.baseApis);
|
||||||
};
|
};
|
||||||
this.handleVerificationEvent(
|
this.handleVerificationEvent(event, this.inRoomVerificationRequests, createRequest, liveEvent);
|
||||||
event,
|
|
||||||
this.inRoomVerificationRequests,
|
|
||||||
createRequest,
|
|
||||||
liveEvent,
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
private async handleVerificationEvent(
|
private async handleVerificationEvent(
|
||||||
event: MatrixEvent,
|
event: MatrixEvent,
|
||||||
requestsMap: any, // TODO types
|
requestsMap: IRequestsMap,
|
||||||
createRequest: any, // TODO types
|
createRequest: (event: MatrixEvent) => VerificationRequest,
|
||||||
isLiveEvent = true,
|
isLiveEvent = true,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
// Wait for event to get its final ID with pendingEventOrdering: "chronological", since DM channels depend on it.
|
// Wait for event to get its final ID with pendingEventOrdering: "chronological", since DM channels depend on it.
|
||||||
@ -3332,7 +3321,7 @@ export class Crypto extends EventEmitter {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const devicesByUser = {};
|
const devicesByUser: Record<string, DeviceInfo[]> = {};
|
||||||
devicesByUser[sender] = [device];
|
devicesByUser[sender] = [device];
|
||||||
await olmlib.ensureOlmSessionsForDevices(this.olmDevice, this.baseApis, devicesByUser, true);
|
await olmlib.ensureOlmSessionsForDevices(this.olmDevice, this.baseApis, devicesByUser, true);
|
||||||
|
|
||||||
|
@ -28,7 +28,8 @@ import { OlmDevice } from "./OlmDevice";
|
|||||||
import { DeviceInfo } from "./deviceinfo";
|
import { DeviceInfo } from "./deviceinfo";
|
||||||
import { logger } from '../logger';
|
import { logger } from '../logger';
|
||||||
import { IOneTimeKey } from "./dehydration";
|
import { IOneTimeKey } from "./dehydration";
|
||||||
import { MatrixClient } from "../client";
|
import { IClaimOTKsResult, MatrixClient } from "../client";
|
||||||
|
import { ISignatures } from "../@types/signed";
|
||||||
|
|
||||||
enum Algorithm {
|
enum Algorithm {
|
||||||
Olm = "m.olm.v1.curve25519-aes-sha2",
|
Olm = "m.olm.v1.curve25519-aes-sha2",
|
||||||
@ -132,6 +133,11 @@ export async function encryptMessageForDevice(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface IExistingOlmSession {
|
||||||
|
device: DeviceInfo;
|
||||||
|
sessionId?: string;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the existing olm sessions for the given devices, and the devices that
|
* Get the existing olm sessions for the given devices, and the devices that
|
||||||
* don't have olm sessions.
|
* don't have olm sessions.
|
||||||
@ -152,11 +158,11 @@ export async function getExistingOlmSessions(
|
|||||||
olmDevice: OlmDevice,
|
olmDevice: OlmDevice,
|
||||||
baseApis: MatrixClient,
|
baseApis: MatrixClient,
|
||||||
devicesByUser: Record<string, DeviceInfo[]>,
|
devicesByUser: Record<string, DeviceInfo[]>,
|
||||||
) {
|
): Promise<[Record<string, DeviceInfo[]>, Record<string, Record<string, IExistingOlmSession>>]> {
|
||||||
const devicesWithoutSession = {};
|
const devicesWithoutSession: {[userId: string]: DeviceInfo[]} = {};
|
||||||
const sessions = {};
|
const sessions: {[userId: string]: {[deviceId: string]: IExistingOlmSession}} = {};
|
||||||
|
|
||||||
const promises = [];
|
const promises: Promise<void>[] = [];
|
||||||
|
|
||||||
for (const [userId, devices] of Object.entries(devicesByUser)) {
|
for (const [userId, devices] of Object.entries(devicesByUser)) {
|
||||||
for (const deviceInfo of devices) {
|
for (const deviceInfo of devices) {
|
||||||
@ -230,10 +236,10 @@ export async function ensureOlmSessionsForDevices(
|
|||||||
force = false;
|
force = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const devicesWithoutSession = [
|
const devicesWithoutSession: [string, string][] = [
|
||||||
// [userId, deviceId], ...
|
// [userId, deviceId], ...
|
||||||
];
|
];
|
||||||
const result = {};
|
const result: {[userId: string]: {[deviceId: string]: IExistingOlmSession}} = {};
|
||||||
const resolveSession: Record<string, (sessionId?: string) => void> = {};
|
const resolveSession: Record<string, (sessionId?: string) => void> = {};
|
||||||
|
|
||||||
// Mark all sessions this task intends to update as in progress. It is
|
// Mark all sessions this task intends to update as in progress. It is
|
||||||
@ -321,9 +327,7 @@ export async function ensureOlmSessionsForDevices(
|
|||||||
let taskDetail = `one-time keys for ${devicesWithoutSession.length} devices`;
|
let taskDetail = `one-time keys for ${devicesWithoutSession.length} devices`;
|
||||||
try {
|
try {
|
||||||
log.debug(`Claiming ${taskDetail}`);
|
log.debug(`Claiming ${taskDetail}`);
|
||||||
res = await baseApis.claimOneTimeKeys(
|
res = await baseApis.claimOneTimeKeys(devicesWithoutSession, oneTimeKeyAlgorithm, otkTimeout);
|
||||||
devicesWithoutSession, oneTimeKeyAlgorithm, otkTimeout,
|
|
||||||
);
|
|
||||||
log.debug(`Claimed ${taskDetail}`);
|
log.debug(`Claimed ${taskDetail}`);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
for (const resolver of Object.values(resolveSession)) {
|
for (const resolver of Object.values(resolveSession)) {
|
||||||
@ -337,8 +341,8 @@ export async function ensureOlmSessionsForDevices(
|
|||||||
failedServers.push(...Object.keys(res.failures));
|
failedServers.push(...Object.keys(res.failures));
|
||||||
}
|
}
|
||||||
|
|
||||||
const otkResult = res.one_time_keys || {};
|
const otkResult = res.one_time_keys || {} as IClaimOTKsResult["one_time_keys"];
|
||||||
const promises = [];
|
const promises: Promise<void>[] = [];
|
||||||
for (const [userId, devices] of Object.entries(devicesByUser)) {
|
for (const [userId, devices] of Object.entries(devicesByUser)) {
|
||||||
const userRes = otkResult[userId] || {};
|
const userRes = otkResult[userId] || {};
|
||||||
for (let j = 0; j < devices.length; j++) {
|
for (let j = 0; j < devices.length; j++) {
|
||||||
@ -359,7 +363,7 @@ export async function ensureOlmSessionsForDevices(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const deviceRes = userRes[deviceId] || {};
|
const deviceRes = userRes[deviceId] || {};
|
||||||
let oneTimeKey = null;
|
let oneTimeKey: IOneTimeKey = null;
|
||||||
for (const keyId in deviceRes) {
|
for (const keyId in deviceRes) {
|
||||||
if (keyId.indexOf(oneTimeKeyAlgorithm + ":") === 0) {
|
if (keyId.indexOf(oneTimeKeyAlgorithm + ":") === 0) {
|
||||||
oneTimeKey = deviceRes[keyId];
|
oneTimeKey = deviceRes[keyId];
|
||||||
@ -441,7 +445,7 @@ async function _verifyKeyAndStartSession(
|
|||||||
|
|
||||||
export interface IObject {
|
export interface IObject {
|
||||||
unsigned?: object;
|
unsigned?: object;
|
||||||
signatures?: object;
|
signatures?: ISignatures;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -200,10 +200,10 @@ export class Backend implements CryptoStore {
|
|||||||
|
|
||||||
// index into the wantedStates array
|
// index into the wantedStates array
|
||||||
let stateIndex = 0;
|
let stateIndex = 0;
|
||||||
let result;
|
let result: OutgoingRoomKeyRequest;
|
||||||
|
|
||||||
function onsuccess(ev) {
|
function onsuccess(this: IDBRequest<IDBCursorWithValue>) {
|
||||||
const cursor = ev.target.result;
|
const cursor = this.result;
|
||||||
if (cursor) {
|
if (cursor) {
|
||||||
// got a match
|
// got a match
|
||||||
result = cursor.value;
|
result = cursor.value;
|
||||||
@ -218,7 +218,7 @@ export class Backend implements CryptoStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const wantedState = wantedStates[stateIndex];
|
const wantedState = wantedStates[stateIndex];
|
||||||
const cursorReq = ev.target.source.openCursor(wantedState);
|
const cursorReq = (this.source as IDBIndex).openCursor(wantedState);
|
||||||
cursorReq.onsuccess = onsuccess;
|
cursorReq.onsuccess = onsuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -255,10 +255,10 @@ export class Backend implements CryptoStore {
|
|||||||
wantedStates: number[],
|
wantedStates: number[],
|
||||||
): Promise<OutgoingRoomKeyRequest[]> {
|
): Promise<OutgoingRoomKeyRequest[]> {
|
||||||
let stateIndex = 0;
|
let stateIndex = 0;
|
||||||
const results = [];
|
const results: OutgoingRoomKeyRequest[] = [];
|
||||||
|
|
||||||
function onsuccess(ev) {
|
function onsuccess(this: IDBRequest<IDBCursorWithValue>) {
|
||||||
const cursor = ev.target.result;
|
const cursor = this.result;
|
||||||
if (cursor) {
|
if (cursor) {
|
||||||
const keyReq = cursor.value;
|
const keyReq = cursor.value;
|
||||||
if (keyReq.recipients.includes({ userId, deviceId })) {
|
if (keyReq.recipients.includes({ userId, deviceId })) {
|
||||||
@ -274,7 +274,7 @@ export class Backend implements CryptoStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const wantedState = wantedStates[stateIndex];
|
const wantedState = wantedStates[stateIndex];
|
||||||
const cursorReq = ev.target.source.openCursor(wantedState);
|
const cursorReq = (this.source as IDBIndex).openCursor(wantedState);
|
||||||
cursorReq.onsuccess = onsuccess;
|
cursorReq.onsuccess = onsuccess;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -306,10 +306,10 @@ export class Backend implements CryptoStore {
|
|||||||
expectedState: number,
|
expectedState: number,
|
||||||
updates: Partial<OutgoingRoomKeyRequest>,
|
updates: Partial<OutgoingRoomKeyRequest>,
|
||||||
): Promise<OutgoingRoomKeyRequest | null> {
|
): Promise<OutgoingRoomKeyRequest | null> {
|
||||||
let result = null;
|
let result: OutgoingRoomKeyRequest = null;
|
||||||
|
|
||||||
function onsuccess(ev) {
|
function onsuccess(this: IDBRequest<IDBCursorWithValue>) {
|
||||||
const cursor = ev.target.result;
|
const cursor = this.result;
|
||||||
if (!cursor) {
|
if (!cursor) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -444,7 +444,7 @@ export class Backend implements CryptoStore {
|
|||||||
const objectStore = txn.objectStore("sessions");
|
const objectStore = txn.objectStore("sessions");
|
||||||
const idx = objectStore.index("deviceKey");
|
const idx = objectStore.index("deviceKey");
|
||||||
const getReq = idx.openCursor(deviceKey);
|
const getReq = idx.openCursor(deviceKey);
|
||||||
const results = {};
|
const results: Parameters<Parameters<Backend["getEndToEndSessions"]>[2]>[0] = {};
|
||||||
getReq.onsuccess = function() {
|
getReq.onsuccess = function() {
|
||||||
const cursor = getReq.result;
|
const cursor = getReq.result;
|
||||||
if (cursor) {
|
if (cursor) {
|
||||||
@ -734,7 +734,7 @@ export class Backend implements CryptoStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public getEndToEndRooms(txn: IDBTransaction, func: (rooms: Record<string, IRoomEncryption>) => void): void {
|
public getEndToEndRooms(txn: IDBTransaction, func: (rooms: Record<string, IRoomEncryption>) => void): void {
|
||||||
const rooms = {};
|
const rooms: Parameters<Parameters<Backend["getEndToEndRooms"]>[1]>[0] = {};
|
||||||
const objectStore = txn.objectStore("rooms");
|
const objectStore = txn.objectStore("rooms");
|
||||||
const getReq = objectStore.openCursor();
|
const getReq = objectStore.openCursor();
|
||||||
getReq.onsuccess = function() {
|
getReq.onsuccess = function() {
|
||||||
@ -756,7 +756,7 @@ export class Backend implements CryptoStore {
|
|||||||
|
|
||||||
public getSessionsNeedingBackup(limit: number): Promise<ISession[]> {
|
public getSessionsNeedingBackup(limit: number): Promise<ISession[]> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const sessions = [];
|
const sessions: ISession[] = [];
|
||||||
|
|
||||||
const txn = this.db.transaction(
|
const txn = this.db.transaction(
|
||||||
["sessions_needing_backup", "inbound_group_sessions"],
|
["sessions_needing_backup", "inbound_group_sessions"],
|
||||||
@ -877,8 +877,8 @@ export class Backend implements CryptoStore {
|
|||||||
func: (txn: IDBTransaction) => T,
|
func: (txn: IDBTransaction) => T,
|
||||||
log: PrefixedLogger = logger,
|
log: PrefixedLogger = logger,
|
||||||
): Promise<T> {
|
): Promise<T> {
|
||||||
let startTime;
|
let startTime: number;
|
||||||
let description;
|
let description: string;
|
||||||
if (PROFILE_TRANSACTIONS) {
|
if (PROFILE_TRANSACTIONS) {
|
||||||
const txnId = this.nextTxnId++;
|
const txnId = this.nextTxnId++;
|
||||||
startTime = Date.now();
|
startTime = Date.now();
|
||||||
|
@ -175,8 +175,10 @@ export class LocalStorageCryptoStore extends MemoryCryptoStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async filterOutNotifiedErrorDevices(devices: IOlmDevice[]): Promise<IOlmDevice[]> {
|
public async filterOutNotifiedErrorDevices(devices: IOlmDevice[]): Promise<IOlmDevice[]> {
|
||||||
const notifiedErrorDevices = getJsonItem<string[]>(this.store, KEY_NOTIFIED_ERROR_DEVICES) || {};
|
const notifiedErrorDevices = getJsonItem<MemoryCryptoStore["notifiedErrorDevices"]>(
|
||||||
const ret = [];
|
this.store, KEY_NOTIFIED_ERROR_DEVICES,
|
||||||
|
) || {};
|
||||||
|
const ret: IOlmDevice[] = [];
|
||||||
|
|
||||||
for (const device of devices) {
|
for (const device of devices) {
|
||||||
const { userId, deviceInfo } = device;
|
const { userId, deviceInfo } = device;
|
||||||
@ -291,7 +293,7 @@ export class LocalStorageCryptoStore extends MemoryCryptoStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public getEndToEndRooms(txn: unknown, func: (rooms: Record<string, IRoomEncryption>) => void): void {
|
public getEndToEndRooms(txn: unknown, func: (rooms: Record<string, IRoomEncryption>) => void): void {
|
||||||
const result = {};
|
const result: Record<string, IRoomEncryption> = {};
|
||||||
const prefix = keyEndToEndRoomsPrefix('');
|
const prefix = keyEndToEndRoomsPrefix('');
|
||||||
|
|
||||||
for (let i = 0; i < this.store.length; ++i) {
|
for (let i = 0; i < this.store.length; ++i) {
|
||||||
@ -306,7 +308,7 @@ export class LocalStorageCryptoStore extends MemoryCryptoStore {
|
|||||||
|
|
||||||
public getSessionsNeedingBackup(limit: number): Promise<ISession[]> {
|
public getSessionsNeedingBackup(limit: number): Promise<ISession[]> {
|
||||||
const sessionsNeedingBackup = getJsonItem<string[]>(this.store, KEY_SESSIONS_NEEDING_BACKUP) || {};
|
const sessionsNeedingBackup = getJsonItem<string[]>(this.store, KEY_SESSIONS_NEEDING_BACKUP) || {};
|
||||||
const sessions = [];
|
const sessions: ISession[] = [];
|
||||||
|
|
||||||
for (const session in sessionsNeedingBackup) {
|
for (const session in sessionsNeedingBackup) {
|
||||||
if (Object.prototype.hasOwnProperty.call(sessionsNeedingBackup, session)) {
|
if (Object.prototype.hasOwnProperty.call(sessionsNeedingBackup, session)) {
|
||||||
|
@ -30,4 +30,5 @@ export interface IVerificationChannel {
|
|||||||
sendCompleted(type: string, content: Record<string, any>): Promise<void>;
|
sendCompleted(type: string, content: Record<string, any>): Promise<void>;
|
||||||
completedContentFromEvent(event: MatrixEvent): Record<string, any>;
|
completedContentFromEvent(event: MatrixEvent): Record<string, any>;
|
||||||
canCreateRequest(type: string): boolean;
|
canCreateRequest(type: string): boolean;
|
||||||
|
handleEvent(event: MatrixEvent, request: VerificationRequest, isLiveEvent: boolean): Promise<void>;
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,7 @@ import { IVerificationChannel } from "./Channel";
|
|||||||
import { EventType } from "../../../@types/event";
|
import { EventType } from "../../../@types/event";
|
||||||
import { MatrixClient } from "../../../client";
|
import { MatrixClient } from "../../../client";
|
||||||
import { MatrixEvent } from "../../../models/event";
|
import { MatrixEvent } from "../../../models/event";
|
||||||
|
import { IRequestsMap } from "../..";
|
||||||
|
|
||||||
const MESSAGE_TYPE = EventType.RoomMessage;
|
const MESSAGE_TYPE = EventType.RoomMessage;
|
||||||
const M_REFERENCE = "m.reference";
|
const M_REFERENCE = "m.reference";
|
||||||
@ -304,7 +305,7 @@ export class InRoomChannel implements IVerificationChannel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class InRoomRequests {
|
export class InRoomRequests implements IRequestsMap {
|
||||||
private requestsByRoomId = new Map<string, Map<string, VerificationRequest>>();
|
private requestsByRoomId = new Map<string, Map<string, VerificationRequest>>();
|
||||||
|
|
||||||
public getRequest(event: MatrixEvent): VerificationRequest {
|
public getRequest(event: MatrixEvent): VerificationRequest {
|
||||||
@ -328,7 +329,7 @@ export class InRoomRequests {
|
|||||||
this.doSetRequest(event.getRoomId(), InRoomChannel.getTransactionId(event), request);
|
this.doSetRequest(event.getRoomId(), InRoomChannel.getTransactionId(event), request);
|
||||||
}
|
}
|
||||||
|
|
||||||
public setRequestByChannel(channel: InRoomChannel, request: VerificationRequest): void {
|
public setRequestByChannel(channel: IVerificationChannel, request: VerificationRequest): void {
|
||||||
this.doSetRequest(channel.roomId, channel.transactionId, request);
|
this.doSetRequest(channel.roomId, channel.transactionId, request);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,8 +30,9 @@ import { errorFromEvent, newUnexpectedMessageError } from "../Error";
|
|||||||
import { MatrixEvent } from "../../../models/event";
|
import { MatrixEvent } from "../../../models/event";
|
||||||
import { IVerificationChannel } from "./Channel";
|
import { IVerificationChannel } from "./Channel";
|
||||||
import { MatrixClient } from "../../../client";
|
import { MatrixClient } from "../../../client";
|
||||||
|
import { IRequestsMap } from '../..';
|
||||||
|
|
||||||
type Request = VerificationRequest<ToDeviceChannel>;
|
export type Request = VerificationRequest<ToDeviceChannel>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A key verification channel that sends verification events over to_device messages.
|
* A key verification channel that sends verification events over to_device messages.
|
||||||
@ -276,7 +277,7 @@ export class ToDeviceChannel implements IVerificationChannel {
|
|||||||
|
|
||||||
private async sendToDevices(type: string, content: Record<string, any>, devices: string[]): Promise<void> {
|
private async sendToDevices(type: string, content: Record<string, any>, devices: string[]): Promise<void> {
|
||||||
if (devices.length) {
|
if (devices.length) {
|
||||||
const msgMap = {};
|
const msgMap: Record<string, Record<string, any>> = {};
|
||||||
for (const deviceId of devices) {
|
for (const deviceId of devices) {
|
||||||
msgMap[deviceId] = content;
|
msgMap[deviceId] = content;
|
||||||
}
|
}
|
||||||
@ -294,7 +295,7 @@ export class ToDeviceChannel implements IVerificationChannel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ToDeviceRequests {
|
export class ToDeviceRequests implements IRequestsMap {
|
||||||
private requestsByUserId = new Map<string, Map<string, Request>>();
|
private requestsByUserId = new Map<string, Map<string, Request>>();
|
||||||
|
|
||||||
public getRequest(event: MatrixEvent): Request {
|
public getRequest(event: MatrixEvent): Request {
|
||||||
|
@ -582,7 +582,9 @@ export class VerificationRequest<C extends IVerificationChannel = IVerificationC
|
|||||||
// get common methods
|
// get common methods
|
||||||
if (phase === PHASE_REQUESTED || phase === PHASE_READY) {
|
if (phase === PHASE_REQUESTED || phase === PHASE_READY) {
|
||||||
if (!this.wasSentByOwnDevice(event)) {
|
if (!this.wasSentByOwnDevice(event)) {
|
||||||
const content = event.getContent();
|
const content = event.getContent<{
|
||||||
|
methods: string[];
|
||||||
|
}>();
|
||||||
this.commonMethods =
|
this.commonMethods =
|
||||||
content.methods.filter(m => this.verificationMethods.has(m));
|
content.methods.filter(m => this.verificationMethods.has(m));
|
||||||
}
|
}
|
||||||
|
@ -282,7 +282,7 @@ export class MSC3089TreeSpace {
|
|||||||
const members = this.room.currentState.getStateEvents(EventType.RoomMember);
|
const members = this.room.currentState.getStateEvents(EventType.RoomMember);
|
||||||
for (const member of members) {
|
for (const member of members) {
|
||||||
const isNotUs = member.getStateKey() !== this.client.getUserId();
|
const isNotUs = member.getStateKey() !== this.client.getUserId();
|
||||||
if (isNotUs && kickMemberships.includes(member.getContent<string>()['membership'])) {
|
if (isNotUs && kickMemberships.includes(member.getContent().membership)) {
|
||||||
const stateKey = member.getStateKey();
|
const stateKey = member.getStateKey();
|
||||||
if (!stateKey) {
|
if (!stateKey) {
|
||||||
throw new Error("State key not found for branch");
|
throw new Error("State key not found for branch");
|
||||||
|
Reference in New Issue
Block a user