1
0
mirror of https://github.com/matrix-org/matrix-js-sdk.git synced 2025-11-25 05:23:13 +03:00

Merge pull request #1777 from matrix-org/t3chguy/ts/c1

This commit is contained in:
Michael Telatynski
2021-07-14 17:19:03 +01:00
committed by GitHub
32 changed files with 1001 additions and 524 deletions

View File

@@ -20,6 +20,12 @@ import "@matrix-org/olm";
export {}; export {};
declare global { declare global {
// use `number` as the return type in all cases for global.set{Interval,Timeout},
// so we don't accidentally use the methods on NodeJS.Timeout - they only exist in a subset of environments.
// The overload for clear{Interval,Timeout} is resolved as expected.
function setInterval(handler: TimerHandler, timeout: number, ...arguments: any[]): number;
function setTimeout(handler: TimerHandler, timeout: number, ...arguments: any[]): number;
namespace NodeJS { namespace NodeJS {
interface Global { interface Global {
localStorage: Storage; localStorage: Storage;

View File

@@ -39,3 +39,10 @@ export enum Preset {
} }
export type ResizeMethod = "crop" | "scale"; export type ResizeMethod = "crop" | "scale";
// TODO move to http-api after TSification
export interface IAbortablePromise<T> extends Promise<T> {
abort(): void;
}
export type IdServerUnbindResult = "no-support" | "success";

View File

@@ -16,6 +16,8 @@ limitations under the License.
import { Callback } from "../client"; import { Callback } from "../client";
import { Preset, Visibility } from "./partials"; import { Preset, Visibility } from "./partials";
import { SearchKey } from "./search";
import { IRoomEventFilter } from "../filter";
// allow camelcase as these are things go onto the wire // allow camelcase as these are things go onto the wire
/* eslint-disable camelcase */ /* eslint-disable camelcase */
@@ -63,12 +65,12 @@ export interface IGuestAccessOpts {
} }
export interface ISearchOpts { export interface ISearchOpts {
keys?: string[]; keys?: SearchKey[];
query: string; query: string;
} }
export interface IEventSearchOpts { export interface IEventSearchOpts {
filter: any; // TODO: Types filter?: IRoomEventFilter;
term: string; term: string;
} }
@@ -104,9 +106,11 @@ export interface IRoomDirectoryOptions {
server?: string; server?: string;
limit?: number; limit?: number;
since?: string; since?: string;
filter?: {
// TODO: Proper types generic_search_term: string;
filter?: any & {generic_search_term: string}; };
include_all_networks?: boolean;
third_party_instance_id?: string;
} }
export interface IUploadOpts { export interface IUploadOpts {
@@ -119,4 +123,19 @@ export interface IUploadOpts {
progressHandler?: (state: {loaded: number, total: number}) => void; progressHandler?: (state: {loaded: number, total: number}) => void;
} }
export interface IAddThreePidOnlyBody {
auth?: {
type: string;
session?: string;
};
client_secret: string;
sid: string;
}
export interface IBindThreePidBody {
client_secret: string;
id_server: string;
id_access_token: string;
sid: string;
}
/* eslint-enable camelcase */ /* eslint-enable camelcase */

118
src/@types/search.ts Normal file
View File

@@ -0,0 +1,118 @@
/*
Copyright 2021 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Types relating to the /search API
import { IRoomEvent, IStateEvent } from "../sync-accumulator";
import { IRoomEventFilter } from "../filter";
import { SearchResult } from "../models/search-result";
/* eslint-disable camelcase */
export interface IEventWithRoomId extends IRoomEvent {
room_id: string;
}
export interface IStateEventWithRoomId extends IStateEvent {
room_id: string;
}
export interface IMatrixProfile {
avatar_url?: string;
displayname?: string;
}
export interface IResultContext {
events_before: IEventWithRoomId[];
events_after: IEventWithRoomId[];
profile_info: Record<string, IMatrixProfile>;
start?: string;
end?: string;
}
export interface ISearchResult {
rank: number;
result: IEventWithRoomId;
context: IResultContext;
}
enum GroupKey {
RoomId = "room_id",
Sender = "sender",
}
export interface IResultRoomEvents {
count: number;
highlights: string[];
results: ISearchResult[];
state?: { [roomId: string]: IStateEventWithRoomId[] };
groups?: {
[groupKey in GroupKey]: {
[value: string]: {
next_batch?: string;
order: number;
results: string[];
};
};
};
next_batch?: string;
}
interface IResultCategories {
room_events: IResultRoomEvents;
}
export type SearchKey = "content.body" | "content.name" | "content.topic";
export enum SearchOrderBy {
Recent = "recent",
Rank = "rank",
}
export interface ISearchRequestBody {
search_categories: {
room_events: {
search_term: string;
keys?: SearchKey[];
filter?: IRoomEventFilter;
order_by?: SearchOrderBy;
event_context?: {
before_limit?: number;
after_limit?: number;
include_profile?: boolean;
};
include_state?: boolean;
groupings?: {
group_by: {
key: GroupKey;
}[];
};
};
};
}
export interface ISearchResponse {
search_categories: IResultCategories;
}
export interface ISearchResults {
_query?: ISearchRequestBody;
results: SearchResult[];
highlights: string[];
count?: number;
next_batch?: string;
pendingRequest?: Promise<ISearchResults>;
}
/* eslint-enable camelcase */

40
src/@types/spaces.ts Normal file
View File

@@ -0,0 +1,40 @@
/*
Copyright 2021 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import { IPublicRoomsChunkRoom } from "../client";
// Types relating to Rooms of type `m.space` and related APIs
/* eslint-disable camelcase */
export interface ISpaceSummaryRoom extends IPublicRoomsChunkRoom {
num_refs: number;
room_type: string;
}
export interface ISpaceSummaryEvent {
room_id: string;
event_id: string;
origin_server_ts: number;
type: string;
state_key: string;
content: {
order?: string;
suggested?: boolean;
auto_join?: boolean;
via?: string[];
};
}
/* eslint-enable camelcase */

40
src/@types/synapse.ts Normal file
View File

@@ -0,0 +1,40 @@
/*
Copyright 2021 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import { IdServerUnbindResult } from "./partials";
// Types relating to Synapse Admin APIs
/* eslint-disable camelcase */
export interface ISynapseAdminWhoisResponse {
user_id: string;
devices: {
[deviceId: string]: {
sessions: {
connections: {
ip: string;
last_seen: number; // millis since epoch
user_agent: string;
}[];
}[];
};
};
}
export interface ISynapseAdminDeactivateResponse {
id_server_unbind_result: IdServerUnbindResult;
}
/* eslint-enable camelcase */

File diff suppressed because it is too large Load Diff

View File

@@ -17,6 +17,8 @@ limitations under the License.
/** @module ContentHelpers */ /** @module ContentHelpers */
import { MsgType } from "./@types/event";
/** /**
* Generates the content for a HTML Message event * Generates the content for a HTML Message event
* @param {string} body the plaintext body of the message * @param {string} body the plaintext body of the message
@@ -25,7 +27,7 @@ limitations under the License.
*/ */
export function makeHtmlMessage(body: string, htmlBody: string) { export function makeHtmlMessage(body: string, htmlBody: string) {
return { return {
msgtype: "m.text", msgtype: MsgType.Text,
format: "org.matrix.custom.html", format: "org.matrix.custom.html",
body: body, body: body,
formatted_body: htmlBody, formatted_body: htmlBody,
@@ -40,7 +42,7 @@ export function makeHtmlMessage(body: string, htmlBody: string) {
*/ */
export function makeHtmlNotice(body: string, htmlBody: string) { export function makeHtmlNotice(body: string, htmlBody: string) {
return { return {
msgtype: "m.notice", msgtype: MsgType.Notice,
format: "org.matrix.custom.html", format: "org.matrix.custom.html",
body: body, body: body,
formatted_body: htmlBody, formatted_body: htmlBody,
@@ -55,7 +57,7 @@ export function makeHtmlNotice(body: string, htmlBody: string) {
*/ */
export function makeHtmlEmote(body: string, htmlBody: string) { export function makeHtmlEmote(body: string, htmlBody: string) {
return { return {
msgtype: "m.emote", msgtype: MsgType.Emote,
format: "org.matrix.custom.html", format: "org.matrix.custom.html",
body: body, body: body,
formatted_body: htmlBody, formatted_body: htmlBody,
@@ -69,7 +71,7 @@ export function makeHtmlEmote(body: string, htmlBody: string) {
*/ */
export function makeTextMessage(body: string) { export function makeTextMessage(body: string) {
return { return {
msgtype: "m.text", msgtype: MsgType.Text,
body: body, body: body,
}; };
} }
@@ -81,7 +83,7 @@ export function makeTextMessage(body: string) {
*/ */
export function makeNotice(body: string) { export function makeNotice(body: string) {
return { return {
msgtype: "m.notice", msgtype: MsgType.Notice,
body: body, body: body,
}; };
} }
@@ -93,7 +95,7 @@ export function makeNotice(body: string) {
*/ */
export function makeEmoteMessage(body: string) { export function makeEmoteMessage(body: string) {
return { return {
msgtype: "m.emote", msgtype: MsgType.Emote,
body: body, body: body,
}; };
} }

View File

@@ -102,7 +102,7 @@ export class DeviceList extends EventEmitter {
// The time the save is scheduled for // The time the save is scheduled for
private savePromiseTime: number = null; private savePromiseTime: number = null;
// The timer used to delay the save // The timer used to delay the save
private saveTimer: NodeJS.Timeout = null; private saveTimer: number = null;
// True if we have fetched data from the server or loaded a non-empty // True if we have fetched data from the server or loaded a non-empty
// set of device data from the store // set of device data from the store
private hasFetched: boolean = null; private hasFetched: boolean = null;

View File

@@ -1,3 +1,19 @@
/*
Copyright 2021 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import { logger } from "../logger"; import { logger } from "../logger";
import { MatrixEvent } from "../models/event"; import { MatrixEvent } from "../models/event";
import { EventEmitter } from "events"; import { EventEmitter } from "events";
@@ -109,8 +125,8 @@ export class EncryptionSetupBuilder {
* @param {Object} content * @param {Object} content
* @return {Promise} * @return {Promise}
*/ */
public setAccountData(type: string, content: object): Promise<void> { public async setAccountData(type: string, content: object): Promise<void> {
return this.accountDataClientAdapter.setAccountData(type, content); await this.accountDataClientAdapter.setAccountData(type, content);
} }
/** /**
@@ -284,7 +300,7 @@ class AccountDataClientAdapter extends EventEmitter {
* @param {Object} content * @param {Object} content
* @return {Promise} * @return {Promise}
*/ */
public setAccountData(type: string, content: any): Promise<void> { public setAccountData(type: string, content: any): Promise<{}> {
const lastEvent = this.values.get(type); const lastEvent = this.values.get(type);
this.values.set(type, content); this.values.set(type, content);
// ensure accountData is emitted on the next tick, // ensure accountData is emitted on the next tick,
@@ -293,6 +309,7 @@ class AccountDataClientAdapter extends EventEmitter {
return Promise.resolve().then(() => { return Promise.resolve().then(() => {
const event = new MatrixEvent({ type, content }); const event = new MatrixEvent({ type, content });
this.emit("accountData", event, lastEvent); this.emit("accountData", event, lastEvent);
return {};
}); });
} }
} }

View File

@@ -78,7 +78,7 @@ export enum RoomKeyRequestState {
export class OutgoingRoomKeyRequestManager { export class OutgoingRoomKeyRequestManager {
// handle for the delayed call to sendOutgoingRoomKeyRequests. Non-null // handle for the delayed call to sendOutgoingRoomKeyRequests. Non-null
// if the callback has been set, or if it is still running. // if the callback has been set, or if it is still running.
private sendOutgoingRoomKeyRequestsTimer: NodeJS.Timeout = null; private sendOutgoingRoomKeyRequestsTimer: number = null;
// sanity check to ensure that we don't end up with two concurrent runs // sanity check to ensure that we don't end up with two concurrent runs
// of sendOutgoingRoomKeyRequests // of sendOutgoingRoomKeyRequests
@@ -366,7 +366,7 @@ export class OutgoingRoomKeyRequestManager {
}); });
}; };
this.sendOutgoingRoomKeyRequestsTimer = global.setTimeout( this.sendOutgoingRoomKeyRequestsTimer = setTimeout(
startSendingOutgoingRoomKeyRequests, startSendingOutgoingRoomKeyRequests,
SEND_KEY_REQUESTS_DELAY_MS, SEND_KEY_REQUESTS_DELAY_MS,
); );

View File

@@ -24,10 +24,10 @@ import { IndexedDBCryptoStore } from './store/indexeddb-crypto-store';
import { CryptoStore } from "../client"; import { CryptoStore } from "../client";
/* eslint-disable camelcase */ /* eslint-disable camelcase */
interface IRoomEncryption { export interface IRoomEncryption {
algorithm: string; algorithm: string;
rotation_period_ms: number; rotation_period_ms?: number;
rotation_period_msgs: number; rotation_period_msgs?: number;
} }
/* eslint-enable camelcase */ /* eslint-enable camelcase */

View File

@@ -37,9 +37,9 @@ export interface ISecretRequest {
export interface IAccountDataClient extends EventEmitter { export interface IAccountDataClient extends EventEmitter {
// Subset of MatrixClient (which also uses any for the event content) // Subset of MatrixClient (which also uses any for the event content)
getAccountDataFromServer: (eventType: string) => Promise<any>; getAccountDataFromServer: (eventType: string) => Promise<Record<string, any>>;
getAccountData: (eventType: string) => MatrixEvent; getAccountData: (eventType: string) => MatrixEvent;
setAccountData: (eventType: string, content: any) => Promise<void>; setAccountData: (eventType: string, content: any) => Promise<{}>;
} }
interface ISecretRequestInternal { interface ISecretRequestInternal {
@@ -174,7 +174,7 @@ export class SecretStorage {
* the form [keyId, keyInfo]. Otherwise, null is returned. * the form [keyId, keyInfo]. Otherwise, null is returned.
* XXX: why is this an array when addKey returns an object? * XXX: why is this an array when addKey returns an object?
*/ */
public async getKey(keyId: string): Promise<SecretStorageKeyTuple> { public async getKey(keyId: string): Promise<SecretStorageKeyTuple | null> {
if (!keyId) { if (!keyId) {
keyId = await this.getDefaultKeyId(); keyId = await this.getDefaultKeyId();
} }
@@ -184,7 +184,7 @@ export class SecretStorage {
const keyInfo = await this.accountDataAdapter.getAccountDataFromServer( const keyInfo = await this.accountDataAdapter.getAccountDataFromServer(
"m.secret_storage.key." + keyId, "m.secret_storage.key." + keyId,
); ) as ISecretStorageKeyInfo;
return keyInfo ? [keyId, keyInfo] : null; return keyInfo ? [keyId, keyInfo] : null;
} }
@@ -248,7 +248,7 @@ export class SecretStorage {
// get key information from key storage // get key information from key storage
const keyInfo = await this.accountDataAdapter.getAccountDataFromServer( const keyInfo = await this.accountDataAdapter.getAccountDataFromServer(
"m.secret_storage.key." + keyId, "m.secret_storage.key." + keyId,
); ) as ISecretStorageKeyInfo;
if (!keyInfo) { if (!keyInfo) {
throw new Error("Unknown key: " + keyId); throw new Error("Unknown key: " + keyId);
} }

View File

@@ -26,6 +26,7 @@ import { OlmDevice } from "../OlmDevice";
import { MatrixEvent, RoomMember } from "../.."; import { MatrixEvent, RoomMember } from "../..";
import { Crypto, IEventDecryptionResult, IMegolmSessionData, IncomingRoomKeyRequest } from ".."; import { Crypto, IEventDecryptionResult, IMegolmSessionData, IncomingRoomKeyRequest } from "..";
import { DeviceInfo } from "../deviceinfo"; import { DeviceInfo } from "../deviceinfo";
import { IRoomEncryption } from "../RoomList";
/** /**
* map of registered encryption algorithm classes. A map from string to {@link * map of registered encryption algorithm classes. A map from string to {@link
@@ -52,7 +53,7 @@ interface IParams {
olmDevice: OlmDevice; olmDevice: OlmDevice;
baseApis: MatrixClient; baseApis: MatrixClient;
roomId: string; roomId: string;
config: object; config: IRoomEncryption & object;
} }
/** /**

View File

@@ -31,7 +31,7 @@ import { IndexedDBCryptoStore } from './store/indexeddb-crypto-store';
import { encodeRecoveryKey } from './recoverykey'; import { encodeRecoveryKey } from './recoverykey';
import { encryptAES, decryptAES, calculateKeyCheck } from './aes'; import { encryptAES, decryptAES, calculateKeyCheck } from './aes';
import { getCrypto } from '../utils'; import { getCrypto } from '../utils';
import { ICurve25519AuthData, IAes256AuthData, IKeyBackupInfo } from "./keybackup"; import { ICurve25519AuthData, IAes256AuthData, IKeyBackupInfo, IKeyBackupSession } from "./keybackup";
import { UnstableValue } from "../NamespacedValue"; import { UnstableValue } from "../NamespacedValue";
const KEY_BACKUP_KEYS_PER_REQUEST = 200; const KEY_BACKUP_KEYS_PER_REQUEST = 200;
@@ -85,12 +85,22 @@ 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, any>): Promise<Record<string, any>[]>; decryptSessions(ciphertexts: Record<string, IKeyBackupSession>): Promise<Record<string, any>[]>;
authData: AuthData; authData: AuthData;
keyMatches(key: ArrayLike<number>): Promise<boolean>; keyMatches(key: ArrayLike<number>): Promise<boolean>;
free(): void; free(): void;
} }
export interface IKeyBackup {
rooms: {
[roomId: string]: {
sessions: {
[sessionId: string]: IKeyBackupSession;
};
};
};
}
/** /**
* Manages the key backup. * Manages the key backup.
*/ */
@@ -464,11 +474,11 @@ export class BackupManager {
let remaining = await this.baseApis.crypto.cryptoStore.countSessionsNeedingBackup(); let remaining = await this.baseApis.crypto.cryptoStore.countSessionsNeedingBackup();
this.baseApis.crypto.emit("crypto.keyBackupSessionsRemaining", remaining); this.baseApis.crypto.emit("crypto.keyBackupSessionsRemaining", remaining);
const data = {}; const rooms: IKeyBackup["rooms"] = {};
for (const session of sessions) { for (const session of sessions) {
const roomId = session.sessionData.room_id; const roomId = session.sessionData.room_id;
if (data[roomId] === undefined) { if (rooms[roomId] === undefined) {
data[roomId] = { sessions: {} }; rooms[roomId] = { sessions: {} };
} }
const sessionData = await this.baseApis.crypto.olmDevice.exportInboundGroupSession( const sessionData = await this.baseApis.crypto.olmDevice.exportInboundGroupSession(
@@ -487,7 +497,7 @@ export class BackupManager {
); );
const verified = this.baseApis.crypto.checkDeviceInfoTrust(userId, device).isVerified(); const verified = this.baseApis.crypto.checkDeviceInfoTrust(userId, device).isVerified();
data[roomId]['sessions'][session.sessionId] = { rooms[roomId]['sessions'][session.sessionId] = {
first_message_index: sessionData.first_known_index, first_message_index: sessionData.first_known_index,
forwarded_count: forwardedCount, forwarded_count: forwardedCount,
is_verified: verified, is_verified: verified,
@@ -495,10 +505,7 @@ export class BackupManager {
}; };
} }
await this.baseApis.sendKeyBackup( await this.baseApis.sendKeyBackup(undefined, undefined, this.backupInfo.version, { rooms });
undefined, undefined, this.backupInfo.version,
{ rooms: data },
);
await this.baseApis.crypto.cryptoStore.unmarkSessionsNeedingBackup(sessions); await this.baseApis.crypto.cryptoStore.unmarkSessionsNeedingBackup(sessions);
remaining = await this.baseApis.crypto.cryptoStore.countSessionsNeedingBackup(); remaining = await this.baseApis.crypto.cryptoStore.countSessionsNeedingBackup();
@@ -636,7 +643,9 @@ export class Curve25519 implements BackupAlgorithm {
return this.publicKey.encrypt(JSON.stringify(plainText)); return this.publicKey.encrypt(JSON.stringify(plainText));
} }
public async decryptSessions(sessions: Record<string, Record<string, any>>): Promise<Record<string, any>[]> { public async decryptSessions(
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 {
@@ -766,14 +775,12 @@ 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, any>): Promise<Record<string, any>[]> { async decryptSessions(sessions: Record<string, IKeyBackupSession>): Promise<Record<string, any>[]> {
const keys = []; const keys = [];
for (const [sessionId, sessionData] of Object.entries(sessions)) { for (const [sessionId, sessionData] of Object.entries(sessions)) {
try { try {
const decrypted = JSON.parse(await decryptAES( const decrypted = JSON.parse(await decryptAES(sessionData.session_data, this.key, sessionId));
sessionData.session_data, this.key, sessionId,
));
decrypted.session_id = sessionId; decrypted.session_id = sessionId;
keys.push(decrypted); keys.push(decrypted);
} catch (e) { } catch (e) {

View File

@@ -36,7 +36,7 @@ export interface IDehydratedDeviceKeyInfo {
passphrase?: string; passphrase?: string;
} }
interface DeviceKeys { export interface IDeviceKeys {
algorithms: Array<string>; algorithms: Array<string>;
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
@@ -44,7 +44,7 @@ interface DeviceKeys {
signatures?: Signatures; signatures?: Signatures;
} }
export interface OneTimeKey { export interface IOneTimeKey {
key: string; key: string;
fallback?: boolean; fallback?: boolean;
signatures?: Signatures; signatures?: Signatures;
@@ -222,7 +222,7 @@ export class DehydrationManager {
// send the keys to the server // send the keys to the server
const deviceId = dehydrateResult.device_id; const deviceId = dehydrateResult.device_id;
logger.log("Preparing device keys", deviceId); logger.log("Preparing device keys", deviceId);
const deviceKeys: DeviceKeys = { const deviceKeys: IDeviceKeys = {
algorithms: this.crypto.supportedAlgorithms, algorithms: this.crypto.supportedAlgorithms,
device_id: deviceId, device_id: deviceId,
user_id: this.crypto.userId, user_id: this.crypto.userId,
@@ -244,7 +244,7 @@ export class DehydrationManager {
logger.log("Preparing one-time keys"); logger.log("Preparing one-time keys");
const oneTimeKeys = {}; const oneTimeKeys = {};
for (const [keyId, key] of Object.entries(otks.curve25519)) { for (const [keyId, key] of Object.entries(otks.curve25519)) {
const k: OneTimeKey = { key }; const k: IOneTimeKey = { key };
const signature = account.sign(anotherjson.stringify(k)); const signature = account.sign(anotherjson.stringify(k));
k.signatures = { k.signatures = {
[this.crypto.userId]: { [this.crypto.userId]: {
@@ -257,7 +257,7 @@ export class DehydrationManager {
logger.log("Preparing fallback keys"); logger.log("Preparing fallback keys");
const fallbackKeys = {}; const fallbackKeys = {};
for (const [keyId, key] of Object.entries(fallbacks.curve25519)) { for (const [keyId, key] of Object.entries(fallbacks.curve25519)) {
const k: OneTimeKey = { key, fallback: true }; const k: IOneTimeKey = { key, fallback: true };
const signature = account.sign(anotherjson.stringify(k)); const signature = account.sign(anotherjson.stringify(k));
k.signatures = { k.signatures = {
[this.crypto.userId]: { [this.crypto.userId]: {

View File

@@ -44,7 +44,7 @@ import { IAddSecretStorageKeyOpts, ISecretStorageKeyInfo } from "./api";
import { OutgoingRoomKeyRequestManager } from './OutgoingRoomKeyRequestManager'; import { OutgoingRoomKeyRequestManager } from './OutgoingRoomKeyRequestManager';
import { IndexedDBCryptoStore } from './store/indexeddb-crypto-store'; import { IndexedDBCryptoStore } from './store/indexeddb-crypto-store';
import { ReciprocateQRCode, SCAN_QR_CODE_METHOD, SHOW_QR_CODE_METHOD } from './verification/QRCode'; import { ReciprocateQRCode, SCAN_QR_CODE_METHOD, SHOW_QR_CODE_METHOD } from './verification/QRCode';
import { SAS } from './verification/SAS'; import { SAS as SASVerification } from './verification/SAS';
import { keyFromPassphrase } from './key_passphrase'; import { keyFromPassphrase } from './key_passphrase';
import { decodeRecoveryKey, encodeRecoveryKey } from './recoverykey'; import { decodeRecoveryKey, encodeRecoveryKey } from './recoverykey';
import { VerificationRequest } from "./verification/request/VerificationRequest"; import { VerificationRequest } from "./verification/request/VerificationRequest";
@@ -53,7 +53,7 @@ import { ToDeviceChannel, ToDeviceRequests } from "./verification/request/ToDevi
import { IllegalMethod } from "./verification/IllegalMethod"; import { IllegalMethod } from "./verification/IllegalMethod";
import { KeySignatureUploadError } from "../errors"; import { KeySignatureUploadError } from "../errors";
import { decryptAES, encryptAES, calculateKeyCheck } from './aes'; import { decryptAES, encryptAES, calculateKeyCheck } from './aes';
import { DehydrationManager } from './dehydration'; import { DehydrationManager, IDeviceKeys, IOneTimeKey } from './dehydration';
import { BackupManager } from "./backup"; import { BackupManager } from "./backup";
import { IStore } from "../store"; import { IStore } from "../store";
import { Room } from "../models/room"; import { Room } from "../models/room";
@@ -61,7 +61,7 @@ import { RoomMember } from "../models/room-member";
import { MatrixEvent } from "../models/event"; import { MatrixEvent } from "../models/event";
import { MatrixClient, IKeysUploadResponse, SessionStore, CryptoStore, ISignedKey } from "../client"; import { MatrixClient, IKeysUploadResponse, SessionStore, CryptoStore, ISignedKey } from "../client";
import type { EncryptionAlgorithm, DecryptionAlgorithm } from "./algorithms/base"; import type { EncryptionAlgorithm, DecryptionAlgorithm } from "./algorithms/base";
import type { RoomList } from "./RoomList"; import type { IRoomEncryption, RoomList } from "./RoomList";
import { IRecoveryKey, IEncryptedEventInfo } from "./api"; import { IRecoveryKey, IEncryptedEventInfo } from "./api";
import { IKeyBackupInfo } from "./keybackup"; import { IKeyBackupInfo } from "./keybackup";
import { ISyncStateData } from "../sync"; import { ISyncStateData } from "../sync";
@@ -70,7 +70,7 @@ const DeviceVerification = DeviceInfo.DeviceVerification;
const defaultVerificationMethods = { const defaultVerificationMethods = {
[ReciprocateQRCode.NAME]: ReciprocateQRCode, [ReciprocateQRCode.NAME]: ReciprocateQRCode,
[SAS.NAME]: SAS, [SASVerification.NAME]: SASVerification,
// These two can't be used for actual verification, but we do // These two can't be used for actual verification, but we do
// need to be able to define them here for the verification flows // need to be able to define them here for the verification flows
@@ -82,10 +82,13 @@ const defaultVerificationMethods = {
/** /**
* verification method names * verification method names
*/ */
export const verificationMethods = { // legacy export identifier
RECIPROCATE_QR_CODE: ReciprocateQRCode.NAME, export enum verificationMethods {
SAS: SAS.NAME, RECIPROCATE_QR_CODE = ReciprocateQRCode.NAME,
}; SAS = SASVerification.NAME,
}
export type VerificationMethod = verificationMethods;
export function isCryptoAvailable(): boolean { export function isCryptoAvailable(): boolean {
return Boolean(global.Olm); return Boolean(global.Olm);
@@ -142,6 +145,10 @@ interface IDeviceVerificationUpgrade {
crossSigningInfo: CrossSigningInfo; crossSigningInfo: CrossSigningInfo;
} }
export interface ICheckOwnCrossSigningTrustOpts {
allowPrivateKeyRequests?: boolean;
}
/** /**
* @typedef {Object} module:crypto~OlmSessionResult * @typedef {Object} module:crypto~OlmSessionResult
* @property {module:crypto/deviceinfo} device device info * @property {module:crypto/deviceinfo} device device info
@@ -1418,7 +1425,7 @@ export class Crypto extends EventEmitter {
*/ */
async checkOwnCrossSigningTrust({ async checkOwnCrossSigningTrust({
allowPrivateKeyRequests = false, allowPrivateKeyRequests = false,
} = {}) { }: ICheckOwnCrossSigningTrustOpts = {}): Promise<void> {
const userId = this.userId; const userId = this.userId;
// Before proceeding, ensure our cross-signing public keys have been // Before proceeding, ensure our cross-signing public keys have been
@@ -1772,7 +1779,7 @@ export class Crypto extends EventEmitter {
return this.signObject(deviceKeys).then(() => { return this.signObject(deviceKeys).then(() => {
return this.baseApis.uploadKeysRequest({ return this.baseApis.uploadKeysRequest({
device_keys: deviceKeys, device_keys: deviceKeys as Required<IDeviceKeys>,
}); });
}); });
} }
@@ -1904,9 +1911,9 @@ export class Crypto extends EventEmitter {
private async uploadOneTimeKeys() { private async uploadOneTimeKeys() {
const promises = []; const promises = [];
const fallbackJson = {}; const fallbackJson: Record<string, IOneTimeKey> = {};
if (this.getNeedsNewFallback()) { if (this.getNeedsNewFallback()) {
const fallbackKeys = await this.olmDevice.getFallbackKey(); const fallbackKeys = await this.olmDevice.getFallbackKey() as Record<string, Record<string, string>>;
for (const [keyId, key] of Object.entries(fallbackKeys.curve25519)) { for (const [keyId, key] of Object.entries(fallbackKeys.curve25519)) {
const k = { key, fallback: true }; const k = { key, fallback: true };
fallbackJson["signed_curve25519:" + keyId] = k; fallbackJson["signed_curve25519:" + keyId] = k;
@@ -2252,7 +2259,7 @@ export class Crypto extends EventEmitter {
public async legacyDeviceVerification( public async legacyDeviceVerification(
userId: string, userId: string,
deviceId: string, deviceId: string,
method: string, method: VerificationMethod,
): VerificationRequest { ): VerificationRequest {
const transactionId = ToDeviceChannel.makeTransactionId(); const transactionId = ToDeviceChannel.makeTransactionId();
const channel = new ToDeviceChannel( const channel = new ToDeviceChannel(
@@ -2465,7 +2472,7 @@ export class Crypto extends EventEmitter {
*/ */
public async setRoomEncryption( public async setRoomEncryption(
roomId: string, roomId: string,
config: any, // TODO types config: IRoomEncryption,
inhibitDeviceQuery?: boolean, inhibitDeviceQuery?: boolean,
): Promise<void> { ): Promise<void> {
// ignore crypto events with no algorithm defined // ignore crypto events with no algorithm defined
@@ -2522,8 +2529,8 @@ export class Crypto extends EventEmitter {
crypto: this, crypto: this,
olmDevice: this.olmDevice, olmDevice: this.olmDevice,
baseApis: this.baseApis, baseApis: this.baseApis,
roomId: roomId, roomId,
config: config, config,
}); });
this.roomEncryptors[roomId] = alg; this.roomEncryptors[roomId] = alg;
@@ -2878,7 +2885,7 @@ export class Crypto extends EventEmitter {
*/ */
public async onCryptoEvent(event: MatrixEvent): Promise<void> { public async onCryptoEvent(event: MatrixEvent): Promise<void> {
const roomId = event.getRoomId(); const roomId = event.getRoomId();
const content = event.getContent(); const content = event.getContent<IRoomEncryption>();
try { try {
// inhibit the device list refresh for now - it will happen once we've // inhibit the device list refresh for now - it will happen once we've

View File

@@ -24,6 +24,7 @@ export interface IKeyBackupSession {
ciphertext: string; ciphertext: string;
ephemeral: string; ephemeral: string;
mac: string; mac: string;
iv: string;
}; };
} }

View File

@@ -28,7 +28,7 @@ import OlmDevice from "./OlmDevice";
import { DeviceInfo } from "./deviceinfo"; import { DeviceInfo } from "./deviceinfo";
import { logger } from '../logger'; import { logger } from '../logger';
import * as utils from "../utils"; import * as utils from "../utils";
import { OneTimeKey } from "./dehydration"; import { IOneTimeKey } from "./dehydration";
import { MatrixClient } from "../client"; import { MatrixClient } from "../client";
enum Algorithm { enum Algorithm {
@@ -407,7 +407,7 @@ export async function ensureOlmSessionsForDevices(
async function _verifyKeyAndStartSession( async function _verifyKeyAndStartSession(
olmDevice: OlmDevice, olmDevice: OlmDevice,
oneTimeKey: OneTimeKey, oneTimeKey: IOneTimeKey,
userId: string, userId: string,
deviceInfo: DeviceInfo, deviceInfo: DeviceInfo,
): Promise<string> { ): Promise<string> {
@@ -465,7 +465,7 @@ export interface IObject {
*/ */
export async function verifySignature( export async function verifySignature(
olmDevice: OlmDevice, olmDevice: OlmDevice,
obj: OneTimeKey | IObject, obj: IOneTimeKey | IObject,
signingUserId: string, signingUserId: string,
signingDeviceId: string, signingDeviceId: string,
signingKey: string, signingKey: string,

View File

@@ -15,9 +15,9 @@ limitations under the License.
*/ */
import { MatrixClient } from "./client"; import { MatrixClient } from "./client";
import { MatrixEvent } from "./models/event"; import { IEvent, MatrixEvent } from "./models/event";
export type EventMapper = (obj: any) => MatrixEvent; export type EventMapper = (obj: Partial<IEvent>) => MatrixEvent;
export interface MapperOpts { export interface MapperOpts {
preventReEmit?: boolean; preventReEmit?: boolean;
@@ -28,7 +28,7 @@ export function eventMapperFor(client: MatrixClient, options: MapperOpts): Event
const preventReEmit = Boolean(options.preventReEmit); const preventReEmit = Boolean(options.preventReEmit);
const decrypt = options.decrypt !== false; const decrypt = options.decrypt !== false;
function mapper(plainOldJsObject) { function mapper(plainOldJsObject: Partial<IEvent>) {
const event = new MatrixEvent(plainOldJsObject); const event = new MatrixEvent(plainOldJsObject);
if (event.isEncrypted()) { if (event.isEncrypted()) {
if (!preventReEmit) { if (!preventReEmit) {

View File

@@ -39,7 +39,7 @@ function setProp(obj: object, keyNesting: string, val: any) {
} }
/* eslint-disable camelcase */ /* eslint-disable camelcase */
interface IFilterDefinition { export interface IFilterDefinition {
event_fields?: string[]; event_fields?: string[];
event_format?: "client" | "federation"; event_format?: "client" | "federation";
presence?: IFilterComponent; presence?: IFilterComponent;
@@ -47,7 +47,7 @@ interface IFilterDefinition {
room?: IRoomFilter; room?: IRoomFilter;
} }
interface IRoomEventFilter extends IFilterComponent { export interface IRoomEventFilter extends IFilterComponent {
lazy_load_members?: boolean; lazy_load_members?: boolean;
include_redundant_members?: boolean; include_redundant_members?: boolean;
} }
@@ -86,7 +86,7 @@ export class Filter {
* @param {Object} jsonObj * @param {Object} jsonObj
* @return {Filter} * @return {Filter}
*/ */
static fromJson(userId: string, filterId: string, jsonObj: IFilterDefinition): Filter { public static fromJson(userId: string, filterId: string, jsonObj: IFilterDefinition): Filter {
const filter = new Filter(userId, filterId); const filter = new Filter(userId, filterId);
filter.setDefinition(jsonObj); filter.setDefinition(jsonObj);
return filter; return filter;

View File

@@ -70,8 +70,8 @@ export class MSC3089Branch {
* @param {string} name The new name for this file. * @param {string} name The new name for this file.
* @returns {Promise<void>} Resolves when complete. * @returns {Promise<void>} Resolves when complete.
*/ */
public setName(name: string): Promise<void> { public async setName(name: string): Promise<void> {
return this.client.sendStateEvent(this.roomId, UNSTABLE_MSC3089_BRANCH.name, { await this.client.sendStateEvent(this.roomId, UNSTABLE_MSC3089_BRANCH.name, {
...this.indexEvent.getContent(), ...this.indexEvent.getContent(),
name: name, name: name,
}, this.id); }, this.id);

View File

@@ -111,8 +111,8 @@ export class MSC3089TreeSpace {
* @param {string} name The new name for the space. * @param {string} name The new name for the space.
* @returns {Promise<void>} Resolves when complete. * @returns {Promise<void>} Resolves when complete.
*/ */
public setName(name: string): Promise<void> { public async setName(name: string): Promise<void> {
return this.client.sendStateEvent(this.roomId, EventType.RoomName, { name }, ""); await this.client.sendStateEvent(this.roomId, EventType.RoomName, { name }, "");
} }
/** /**
@@ -190,7 +190,7 @@ export class MSC3089TreeSpace {
} }
pls['users'] = users; pls['users'] = users;
return this.client.sendStateEvent(this.roomId, EventType.RoomPowerLevels, pls, ""); await this.client.sendStateEvent(this.roomId, EventType.RoomPowerLevels, pls, "");
} }
/** /**

View File

@@ -25,13 +25,13 @@ import { EventTimeline } from "./event-timeline";
import { getHttpUriForMxc } from "../content-repo"; import { getHttpUriForMxc } from "../content-repo";
import * as utils from "../utils"; import * as utils from "../utils";
import { normalize } from "../utils"; import { normalize } from "../utils";
import { EventStatus, MatrixEvent } from "./event"; import { EventStatus, IEvent, MatrixEvent } from "./event";
import { RoomMember } from "./room-member"; import { RoomMember } from "./room-member";
import { IRoomSummary, RoomSummary } from "./room-summary"; import { IRoomSummary, RoomSummary } from "./room-summary";
import { logger } from '../logger'; import { logger } from '../logger';
import { ReEmitter } from '../ReEmitter'; import { ReEmitter } from '../ReEmitter';
import { EventType, RoomCreateTypeField, RoomType } from "../@types/event"; import { EventType, RoomCreateTypeField, RoomType } from "../@types/event";
import { IRoomVersionsCapability, MatrixClient, RoomVersionStability } from "../client"; import { IRoomVersionsCapability, MatrixClient, PendingEventOrdering, RoomVersionStability } from "../client";
import { ResizeMethod } from "../@types/partials"; import { ResizeMethod } from "../@types/partials";
import { Filter } from "../filter"; import { Filter } from "../filter";
import { RoomState } from "./room-state"; import { RoomState } from "./room-state";
@@ -64,7 +64,7 @@ function synthesizeReceipt(userId: string, event: MatrixEvent, receiptType: stri
interface IOpts { interface IOpts {
storageToken?: string; storageToken?: string;
pendingEventOrdering?: "chronological" | "detached"; pendingEventOrdering?: PendingEventOrdering;
timelineSupport?: boolean; timelineSupport?: boolean;
unstableClientRelationAggregation?: boolean; unstableClientRelationAggregation?: boolean;
lazyLoadMembers?: boolean; lazyLoadMembers?: boolean;
@@ -218,7 +218,7 @@ export class Room extends EventEmitter {
this.setMaxListeners(100); this.setMaxListeners(100);
this.reEmitter = new ReEmitter(this); this.reEmitter = new ReEmitter(this);
opts.pendingEventOrdering = opts.pendingEventOrdering || "chronological"; opts.pendingEventOrdering = opts.pendingEventOrdering || PendingEventOrdering.Chronological;
if (["chronological", "detached"].indexOf(opts.pendingEventOrdering) === -1) { if (["chronological", "detached"].indexOf(opts.pendingEventOrdering) === -1) {
throw new Error( throw new Error(
"opts.pendingEventOrdering MUST be either 'chronological' or " + "opts.pendingEventOrdering MUST be either 'chronological' or " +
@@ -649,7 +649,7 @@ export class Room extends EventEmitter {
} }
} }
private async loadMembersFromServer(): Promise<object[]> { private async loadMembersFromServer(): Promise<IEvent[]> {
const lastSyncToken = this.client.store.getSyncToken(); const lastSyncToken = this.client.store.getSyncToken();
const queryString = utils.encodeParams({ const queryString = utils.encodeParams({
not_membership: "leave", not_membership: "leave",
@@ -665,8 +665,7 @@ export class Room extends EventEmitter {
private async loadMembers(): Promise<{ memberEvents: MatrixEvent[], fromServer: boolean }> { private async loadMembers(): Promise<{ memberEvents: MatrixEvent[], fromServer: boolean }> {
// were the members loaded from the server? // were the members loaded from the server?
let fromServer = false; let fromServer = false;
let rawMembersEvents = let rawMembersEvents = await this.client.store.getOutOfBandMembers(this.roomId);
await this.client.store.getOutOfBandMembers(this.roomId);
if (rawMembersEvents === null) { if (rawMembersEvents === null) {
fromServer = true; fromServer = true;
rawMembersEvents = await this.loadMembersFromServer(); rawMembersEvents = await this.loadMembersFromServer();
@@ -713,7 +712,7 @@ export class Room extends EventEmitter {
if (fromServer) { if (fromServer) {
const oobMembers = this.currentState.getMembers() const oobMembers = this.currentState.getMembers()
.filter((m) => m.isOutOfBand()) .filter((m) => m.isOutOfBand())
.map((m) => m.events.member.event); .map((m) => m.events.member.event as IEvent);
logger.log(`LL: telling store to write ${oobMembers.length}` logger.log(`LL: telling store to write ${oobMembers.length}`
+ ` members for room ${this.roomId}`); + ` members for room ${this.roomId}`);
const store = this.client.store; const store = this.client.store;

View File

@@ -1,60 +0,0 @@
/*
Copyright 2015, 2016 OpenMarket Ltd
Copyright 2019 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @module models/search-result
*/
import { EventContext } from "./event-context";
/**
* Construct a new SearchResult
*
* @param {number} rank where this SearchResult ranks in the results
* @param {event-context.EventContext} eventContext the matching event and its
* context
*
* @constructor
*/
export function SearchResult(rank, eventContext) {
this.rank = rank;
this.context = eventContext;
}
/**
* Create a SearchResponse from the response to /search
* @static
* @param {Object} jsonObj
* @param {function} eventMapper
* @return {SearchResult}
*/
SearchResult.fromJson = function(jsonObj, eventMapper) {
const jsonContext = jsonObj.context || {};
const events_before = jsonContext.events_before || [];
const events_after = jsonContext.events_after || [];
const context = new EventContext(eventMapper(jsonObj.result));
context.setPaginateToken(jsonContext.start, true);
context.addEvents(events_before.map(eventMapper), true);
context.addEvents(events_after.map(eventMapper), false);
context.setPaginateToken(jsonContext.end, false);
return new SearchResult(jsonObj.rank, context);
};

View File

@@ -0,0 +1,60 @@
/*
Copyright 2015 - 2021 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @module models/search-result
*/
import { EventContext } from "./event-context";
import { EventMapper } from "../event-mapper";
import { IResultContext, ISearchResult } from "../@types/search";
export class SearchResult {
/**
* Create a SearchResponse from the response to /search
* @static
* @param {Object} jsonObj
* @param {function} eventMapper
* @return {SearchResult}
*/
static fromJson(jsonObj: ISearchResult, eventMapper: EventMapper): SearchResult {
const jsonContext = jsonObj.context || {} as IResultContext;
const eventsBefore = jsonContext.events_before || [];
const eventsAfter = jsonContext.events_after || [];
const context = new EventContext(eventMapper(jsonObj.result));
context.setPaginateToken(jsonContext.start, true);
context.addEvents(eventsBefore.map(eventMapper), true);
context.addEvents(eventsAfter.map(eventMapper), false);
context.setPaginateToken(jsonContext.end, false);
return new SearchResult(jsonObj.rank, context);
}
/**
* Construct a new SearchResult
*
* @param {number} rank where this SearchResult ranks in the results
* @param {event-context.EventContext} context the matching event and its
* context
*
* @constructor
*/
constructor(public readonly rank: number, public readonly context: EventContext) {}
}

View File

@@ -18,10 +18,11 @@ import { EventType } from "../@types/event";
import { Group } from "../models/group"; import { Group } from "../models/group";
import { Room } from "../models/room"; import { Room } from "../models/room";
import { User } from "../models/user"; import { User } from "../models/user";
import { MatrixEvent } from "../models/event"; import { IEvent, MatrixEvent } from "../models/event";
import { Filter } from "../filter"; import { Filter } from "../filter";
import { RoomSummary } from "../models/room-summary"; import { RoomSummary } from "../models/room-summary";
import { IMinimalEvent, IGroups, IRooms } from "../sync-accumulator"; import { IMinimalEvent, IGroups, IRooms } from "../sync-accumulator";
import { IStartClientOpts } from "../client";
export interface ISavedSync { export interface ISavedSync {
nextBatch: string; nextBatch: string;
@@ -35,6 +36,8 @@ export interface ISavedSync {
* @constructor * @constructor
*/ */
export interface IStore { export interface IStore {
readonly accountData: Record<string, MatrixEvent>; // type : content
/** @return {Promise<bool>} whether or not the database was newly created in this session. */ /** @return {Promise<bool>} whether or not the database was newly created in this session. */
isNewlyCreated(): Promise<boolean>; isNewlyCreated(): Promise<boolean>;
@@ -194,7 +197,7 @@ export interface IStore {
/** /**
* Save does nothing as there is no backing data store. * Save does nothing as there is no backing data store.
*/ */
save(force: boolean): void; save(force?: boolean): void;
/** /**
* Startup does nothing. * Startup does nothing.
@@ -222,13 +225,13 @@ export interface IStore {
*/ */
deleteAllData(): Promise<void>; deleteAllData(): Promise<void>;
getOutOfBandMembers(roomId: string): Promise<MatrixEvent[] | null>; getOutOfBandMembers(roomId: string): Promise<IEvent[] | null>;
setOutOfBandMembers(roomId: string, membershipEvents: MatrixEvent[]): Promise<void>; setOutOfBandMembers(roomId: string, membershipEvents: IEvent[]): Promise<void>;
clearOutOfBandMembers(roomId: string): Promise<void>; clearOutOfBandMembers(roomId: string): Promise<void>;
getClientOptions(): Promise<object>; getClientOptions(): Promise<IStartClientOpts>;
storeClientOptions(options: object): Promise<void>; storeClientOptions(options: object): Promise<void>;
} }

View File

@@ -22,7 +22,7 @@ import { MemoryStore, IOpts as IBaseOpts } from "./memory";
import { LocalIndexedDBStoreBackend } from "./indexeddb-local-backend.js"; import { LocalIndexedDBStoreBackend } from "./indexeddb-local-backend.js";
import { RemoteIndexedDBStoreBackend } from "./indexeddb-remote-backend.js"; import { RemoteIndexedDBStoreBackend } from "./indexeddb-remote-backend.js";
import { User } from "../models/user"; import { User } from "../models/user";
import { MatrixEvent } from "../models/event"; import { IEvent, MatrixEvent } from "../models/event";
import { logger } from '../logger'; import { logger } from '../logger';
import { ISavedSync } from "./index"; import { ISavedSync } from "./index";
@@ -247,7 +247,7 @@ export class IndexedDBStore extends MemoryStore {
* @returns {event[]} the events, potentially an empty array if OOB loading didn't yield any new members * @returns {event[]} the events, potentially an empty array if OOB loading didn't yield any new members
* @returns {null} in case the members for this room haven't been stored yet * @returns {null} in case the members for this room haven't been stored yet
*/ */
public getOutOfBandMembers = this.degradable((roomId: string): Promise<MatrixEvent[]> => { public getOutOfBandMembers = this.degradable((roomId: string): Promise<IEvent[]> => {
return this.backend.getOutOfBandMembers(roomId); return this.backend.getOutOfBandMembers(roomId);
}, "getOutOfBandMembers"); }, "getOutOfBandMembers");
@@ -259,7 +259,7 @@ export class IndexedDBStore extends MemoryStore {
* @param {event[]} membershipEvents the membership events to store * @param {event[]} membershipEvents the membership events to store
* @returns {Promise} when all members have been stored * @returns {Promise} when all members have been stored
*/ */
public setOutOfBandMembers = this.degradable((roomId: string, membershipEvents: MatrixEvent[]): Promise<void> => { public setOutOfBandMembers = this.degradable((roomId: string, membershipEvents: IEvent[]): Promise<void> => {
super.setOutOfBandMembers(roomId, membershipEvents); super.setOutOfBandMembers(roomId, membershipEvents);
return this.backend.setOutOfBandMembers(roomId, membershipEvents); return this.backend.setOutOfBandMembers(roomId, membershipEvents);
}, "setOutOfBandMembers"); }, "setOutOfBandMembers");

View File

@@ -23,7 +23,7 @@ import { EventType } from "../@types/event";
import { Group } from "../models/group"; import { Group } from "../models/group";
import { Room } from "../models/room"; import { Room } from "../models/room";
import { User } from "../models/user"; import { User } from "../models/user";
import { MatrixEvent } from "../models/event"; import { IEvent, MatrixEvent } from "../models/event";
import { RoomState } from "../models/room-state"; import { RoomState } from "../models/room-state";
import { RoomMember } from "../models/room-member"; import { RoomMember } from "../models/room-member";
import { Filter } from "../filter"; import { Filter } from "../filter";
@@ -59,9 +59,9 @@ export class MemoryStore implements IStore {
// filterId: Filter // filterId: Filter
// } // }
private filters: Record<string, Record<string, Filter>> = {}; private filters: Record<string, Record<string, Filter>> = {};
private accountData: Record<string, MatrixEvent> = {}; // type : content public accountData: Record<string, MatrixEvent> = {}; // type : content
private readonly localStorage: Storage; private readonly localStorage: Storage;
private oobMembers: Record<string, MatrixEvent[]> = {}; // roomId: [member events] private oobMembers: Record<string, IEvent[]> = {}; // roomId: [member events]
private clientOptions = {}; private clientOptions = {};
constructor(opts: IOpts = {}) { constructor(opts: IOpts = {}) {
@@ -415,7 +415,7 @@ export class MemoryStore implements IStore {
* @returns {event[]} the events, potentially an empty array if OOB loading didn't yield any new members * @returns {event[]} the events, potentially an empty array if OOB loading didn't yield any new members
* @returns {null} in case the members for this room haven't been stored yet * @returns {null} in case the members for this room haven't been stored yet
*/ */
public getOutOfBandMembers(roomId: string): Promise<MatrixEvent[] | null> { public getOutOfBandMembers(roomId: string): Promise<IEvent[] | null> {
return Promise.resolve(this.oobMembers[roomId] || null); return Promise.resolve(this.oobMembers[roomId] || null);
} }
@@ -427,7 +427,7 @@ export class MemoryStore implements IStore {
* @param {event[]} membershipEvents the membership events to store * @param {event[]} membershipEvents the membership events to store
* @returns {Promise} when all members have been stored * @returns {Promise} when all members have been stored
*/ */
public setOutOfBandMembers(roomId: string, membershipEvents: MatrixEvent[]): Promise<void> { public setOutOfBandMembers(roomId: string, membershipEvents: IEvent[]): Promise<void> {
this.oobMembers[roomId] = membershipEvents; this.oobMembers[roomId] = membershipEvents;
return Promise.resolve(); return Promise.resolve();
} }

View File

@@ -23,7 +23,7 @@ import { EventType } from "../@types/event";
import { Group } from "../models/group"; import { Group } from "../models/group";
import { Room } from "../models/room"; import { Room } from "../models/room";
import { User } from "../models/user"; import { User } from "../models/user";
import { MatrixEvent } from "../models/event"; import { IEvent, MatrixEvent } from "../models/event";
import { Filter } from "../filter"; import { Filter } from "../filter";
import { ISavedSync, IStore } from "./index"; import { ISavedSync, IStore } from "./index";
import { RoomSummary } from "../models/room-summary"; import { RoomSummary } from "../models/room-summary";
@@ -33,9 +33,10 @@ import { RoomSummary } from "../models/room-summary";
* @constructor * @constructor
*/ */
export class StubStore implements IStore { export class StubStore implements IStore {
public readonly accountData = {}; // stub
private fromToken: string = null; private fromToken: string = null;
/** @return {Promise<bool>} whether or not the database was newly created in this session. */ /** @return {Promise<boolean>} whether or not the database was newly created in this session. */
public isNewlyCreated(): Promise<boolean> { public isNewlyCreated(): Promise<boolean> {
return Promise.resolve(true); return Promise.resolve(true);
} }
@@ -264,11 +265,11 @@ export class StubStore implements IStore {
return Promise.resolve(); return Promise.resolve();
} }
public getOutOfBandMembers(): Promise<MatrixEvent[]> { public getOutOfBandMembers(): Promise<IEvent[]> {
return Promise.resolve(null); return Promise.resolve(null);
} }
public setOutOfBandMembers(roomId: string, membershipEvents: MatrixEvent[]): Promise<void> { public setOutOfBandMembers(roomId: string, membershipEvents: IEvent[]): Promise<void> {
return Promise.resolve(); return Promise.resolve();
} }

View File

@@ -135,7 +135,7 @@ export class SyncApi {
private syncStateData: ISyncStateData = null; // additional data (eg. error object for failed sync) private syncStateData: ISyncStateData = null; // additional data (eg. error object for failed sync)
private catchingUp = false; private catchingUp = false;
private running = false; private running = false;
private keepAliveTimer: NodeJS.Timeout = null; private keepAliveTimer: number = null;
private connectionReturnedDefer: IDeferred<boolean> = null; private connectionReturnedDefer: IDeferred<boolean> = null;
private notifEvents: MatrixEvent[] = []; // accumulator of sync events in the current sync response private notifEvents: MatrixEvent[] = []; // accumulator of sync events in the current sync response
private failedSyncCount = 0; // Number of consecutive failed /sync requests private failedSyncCount = 0; // Number of consecutive failed /sync requests
@@ -318,7 +318,7 @@ export class SyncApi {
this._peekRoom = this.createRoom(roomId); this._peekRoom = this.createRoom(roomId);
return this.client.roomInitialSync(roomId, 20).then((response) => { return this.client.roomInitialSync(roomId, 20).then((response) => {
// make sure things are init'd // make sure things are init'd
response.messages = response.messages || {}; response.messages = response.messages || { chunk: [] };
response.messages.chunk = response.messages.chunk || []; response.messages.chunk = response.messages.chunk || [];
response.state = response.state || []; response.state = response.state || [];
@@ -329,8 +329,7 @@ export class SyncApi {
const stateEvents = response.state.map(client.getEventMapper()); const stateEvents = response.state.map(client.getEventMapper());
const messages = response.messages.chunk.map(client.getEventMapper()); const messages = response.messages.chunk.map(client.getEventMapper());
// XXX: copypasted from /sync until we kill off this // XXX: copypasted from /sync until we kill off this minging v1 API stuff)
// minging v1 API stuff)
// handle presence events (User objects) // handle presence events (User objects)
if (response.presence && Array.isArray(response.presence)) { if (response.presence && Array.isArray(response.presence)) {
response.presence.map(client.getEventMapper()).forEach( response.presence.map(client.getEventMapper()).forEach(

View File

@@ -288,7 +288,7 @@ export class MatrixCall extends EventEmitter {
// yet, null if we have but they didn't send a party ID. // yet, null if we have but they didn't send a party ID.
private opponentPartyId: string; private opponentPartyId: string;
private opponentCaps: CallCapabilities; private opponentCaps: CallCapabilities;
private inviteTimeout: NodeJS.Timeout; // in the browser it's 'number' private inviteTimeout: number;
// The logic of when & if a call is on hold is nontrivial and explained in is*OnHold // The logic of when & if a call is on hold is nontrivial and explained in is*OnHold
// This flag represents whether we want the other party to be on hold // This flag represents whether we want the other party to be on hold