Apply strictNullChecks to src/async-components/* (#10251
* Apply strictNullChecks to src/async-components/* * Iteratepull/28788/head^2
parent
629e5cb01f
commit
8ad21e6492
src
async-components/views/dialogs
utils
|
@ -38,7 +38,7 @@ interface IState {
|
||||||
eventCount: number;
|
eventCount: number;
|
||||||
crawlingRoomsCount: number;
|
crawlingRoomsCount: number;
|
||||||
roomCount: number;
|
roomCount: number;
|
||||||
currentRoom: string;
|
currentRoom: string | null;
|
||||||
crawlerSleepTime: number;
|
crawlerSleepTime: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,7 +61,8 @@ export default class ManageEventIndexDialog extends React.Component<IProps, ISta
|
||||||
|
|
||||||
public updateCurrentRoom = async (room: Room): Promise<void> => {
|
public updateCurrentRoom = async (room: Room): Promise<void> => {
|
||||||
const eventIndex = EventIndexPeg.get();
|
const eventIndex = EventIndexPeg.get();
|
||||||
let stats: IIndexStats;
|
if (!eventIndex) return;
|
||||||
|
let stats: IIndexStats | undefined;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
stats = await eventIndex.getStats();
|
stats = await eventIndex.getStats();
|
||||||
|
@ -71,7 +72,7 @@ export default class ManageEventIndexDialog extends React.Component<IProps, ISta
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let currentRoom = null;
|
let currentRoom: string | null = null;
|
||||||
|
|
||||||
if (room) currentRoom = room.name;
|
if (room) currentRoom = room.name;
|
||||||
const roomStats = eventIndex.crawlingRooms();
|
const roomStats = eventIndex.crawlingRooms();
|
||||||
|
@ -79,8 +80,8 @@ export default class ManageEventIndexDialog extends React.Component<IProps, ISta
|
||||||
const roomCount = roomStats.totalRooms.size;
|
const roomCount = roomStats.totalRooms.size;
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
eventIndexSize: stats.size,
|
eventIndexSize: stats?.size ?? 0,
|
||||||
eventCount: stats.eventCount,
|
eventCount: stats?.eventCount ?? 0,
|
||||||
crawlingRoomsCount: crawlingRoomsCount,
|
crawlingRoomsCount: crawlingRoomsCount,
|
||||||
roomCount: roomCount,
|
roomCount: roomCount,
|
||||||
currentRoom: currentRoom,
|
currentRoom: currentRoom,
|
||||||
|
@ -100,7 +101,7 @@ export default class ManageEventIndexDialog extends React.Component<IProps, ISta
|
||||||
let crawlingRoomsCount = 0;
|
let crawlingRoomsCount = 0;
|
||||||
let roomCount = 0;
|
let roomCount = 0;
|
||||||
let eventCount = 0;
|
let eventCount = 0;
|
||||||
let currentRoom = null;
|
let currentRoom: string | null = null;
|
||||||
|
|
||||||
const eventIndex = EventIndexPeg.get();
|
const eventIndex = EventIndexPeg.get();
|
||||||
|
|
||||||
|
@ -109,8 +110,10 @@ export default class ManageEventIndexDialog extends React.Component<IProps, ISta
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const stats = await eventIndex.getStats();
|
const stats = await eventIndex.getStats();
|
||||||
eventIndexSize = stats.size;
|
if (stats) {
|
||||||
eventCount = stats.eventCount;
|
eventIndexSize = stats.size;
|
||||||
|
eventCount = stats.eventCount;
|
||||||
|
}
|
||||||
} catch {
|
} catch {
|
||||||
// This call may fail if sporadically, not a huge issue as we
|
// This call may fail if sporadically, not a huge issue as we
|
||||||
// will try later again in the updateCurrentRoom call and
|
// will try later again in the updateCurrentRoom call and
|
||||||
|
@ -136,7 +139,7 @@ export default class ManageEventIndexDialog extends React.Component<IProps, ISta
|
||||||
|
|
||||||
private onDisable = async (): Promise<void> => {
|
private onDisable = async (): Promise<void> => {
|
||||||
const DisableEventIndexDialog = (await import("./DisableEventIndexDialog")).default;
|
const DisableEventIndexDialog = (await import("./DisableEventIndexDialog")).default;
|
||||||
Modal.createDialog(DisableEventIndexDialog, null, null, /* priority = */ false, /* static = */ true);
|
Modal.createDialog(DisableEventIndexDialog, undefined, undefined, /* priority = */ false, /* static = */ true);
|
||||||
};
|
};
|
||||||
|
|
||||||
private onCrawlerSleepTimeChange = (e: ChangeEvent<HTMLInputElement>): void => {
|
private onCrawlerSleepTimeChange = (e: ChangeEvent<HTMLInputElement>): void => {
|
||||||
|
|
|
@ -49,7 +49,7 @@ interface IProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IState {
|
interface IState {
|
||||||
secureSecretStorage: boolean;
|
secureSecretStorage: boolean | null;
|
||||||
phase: Phase;
|
phase: Phase;
|
||||||
passPhrase: string;
|
passPhrase: string;
|
||||||
passPhraseValid: boolean;
|
passPhraseValid: boolean;
|
||||||
|
@ -121,7 +121,7 @@ export default class CreateKeyBackupDialog extends React.PureComponent<IProps, I
|
||||||
const { secureSecretStorage } = this.state;
|
const { secureSecretStorage } = this.state;
|
||||||
this.setState({
|
this.setState({
|
||||||
phase: Phase.BackingUp,
|
phase: Phase.BackingUp,
|
||||||
error: null,
|
error: undefined,
|
||||||
});
|
});
|
||||||
let info;
|
let info;
|
||||||
try {
|
try {
|
||||||
|
@ -219,7 +219,7 @@ export default class CreateKeyBackupDialog extends React.PureComponent<IProps, I
|
||||||
|
|
||||||
private onPassPhraseValidate = (result: IValidationResult): void => {
|
private onPassPhraseValidate = (result: IValidationResult): void => {
|
||||||
this.setState({
|
this.setState({
|
||||||
passPhraseValid: result.valid,
|
passPhraseValid: !!result.valid,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -306,7 +306,7 @@ export default class CreateKeyBackupDialog extends React.PureComponent<IProps, I
|
||||||
changeText = _t("Go back to set it again.");
|
changeText = _t("Go back to set it again.");
|
||||||
}
|
}
|
||||||
|
|
||||||
let passPhraseMatch = null;
|
let passPhraseMatch: JSX.Element | undefined;
|
||||||
if (matchText) {
|
if (matchText) {
|
||||||
passPhraseMatch = (
|
passPhraseMatch = (
|
||||||
<div className="mx_CreateKeyBackupDialog_passPhraseMatch">
|
<div className="mx_CreateKeyBackupDialog_passPhraseMatch">
|
||||||
|
|
|
@ -81,13 +81,13 @@ interface IState {
|
||||||
copied: boolean;
|
copied: boolean;
|
||||||
downloaded: boolean;
|
downloaded: boolean;
|
||||||
setPassphrase: boolean;
|
setPassphrase: boolean;
|
||||||
backupInfo: IKeyBackupInfo;
|
backupInfo: IKeyBackupInfo | null;
|
||||||
backupSigStatus: TrustInfo;
|
backupSigStatus: TrustInfo | null;
|
||||||
// does the server offer a UI auth flow with just m.login.password
|
// does the server offer a UI auth flow with just m.login.password
|
||||||
// for /keys/device_signing/upload?
|
// for /keys/device_signing/upload?
|
||||||
canUploadKeysWithPasswordOnly: boolean;
|
canUploadKeysWithPasswordOnly: boolean | null;
|
||||||
accountPassword: string;
|
accountPassword: string;
|
||||||
accountPasswordCorrect: boolean;
|
accountPasswordCorrect: boolean | null;
|
||||||
canSkip: boolean;
|
canSkip: boolean;
|
||||||
passPhraseKeySelected: string;
|
passPhraseKeySelected: string;
|
||||||
error?: string;
|
error?: string;
|
||||||
|
@ -119,7 +119,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
|
||||||
}
|
}
|
||||||
|
|
||||||
const accountPassword = props.accountPassword || "";
|
const accountPassword = props.accountPassword || "";
|
||||||
let canUploadKeysWithPasswordOnly = null;
|
let canUploadKeysWithPasswordOnly: boolean | null = null;
|
||||||
if (accountPassword) {
|
if (accountPassword) {
|
||||||
// If we have an account password in memory, let's simplify and
|
// If we have an account password in memory, let's simplify and
|
||||||
// assume it means password auth is also supported for device
|
// assume it means password auth is also supported for device
|
||||||
|
@ -172,12 +172,14 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
|
||||||
this.fetchBackupInfo();
|
this.fetchBackupInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async fetchBackupInfo(): Promise<{ backupInfo: IKeyBackupInfo; backupSigStatus: TrustInfo }> {
|
private async fetchBackupInfo(): Promise<{ backupInfo?: IKeyBackupInfo; backupSigStatus?: TrustInfo }> {
|
||||||
try {
|
try {
|
||||||
const backupInfo = await MatrixClientPeg.get().getKeyBackupVersion();
|
const backupInfo = await MatrixClientPeg.get().getKeyBackupVersion();
|
||||||
const backupSigStatus =
|
const backupSigStatus =
|
||||||
// we may not have started crypto yet, in which case we definitely don't trust the backup
|
// we may not have started crypto yet, in which case we definitely don't trust the backup
|
||||||
MatrixClientPeg.get().isCryptoEnabled() && (await MatrixClientPeg.get().isKeyBackupTrusted(backupInfo));
|
backupInfo && MatrixClientPeg.get().isCryptoEnabled()
|
||||||
|
? await MatrixClientPeg.get().isKeyBackupTrusted(backupInfo)
|
||||||
|
: null;
|
||||||
|
|
||||||
const { forceReset } = this.props;
|
const { forceReset } = this.props;
|
||||||
const phase = backupInfo && !forceReset ? Phase.Migrate : Phase.ChooseKeyPassphrase;
|
const phase = backupInfo && !forceReset ? Phase.Migrate : Phase.ChooseKeyPassphrase;
|
||||||
|
@ -189,17 +191,18 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
backupInfo,
|
backupInfo: backupInfo ?? undefined,
|
||||||
backupSigStatus,
|
backupSigStatus: backupSigStatus ?? undefined,
|
||||||
};
|
};
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.setState({ phase: Phase.LoadError });
|
this.setState({ phase: Phase.LoadError });
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async queryKeyUploadAuth(): Promise<void> {
|
private async queryKeyUploadAuth(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
await MatrixClientPeg.get().uploadDeviceSigningKeys(null, {} as CrossSigningKeys);
|
await MatrixClientPeg.get().uploadDeviceSigningKeys(undefined, {} as CrossSigningKeys);
|
||||||
// We should never get here: the server should always require
|
// We should never get here: the server should always require
|
||||||
// UI auth to upload device signing keys. If we do, we upload
|
// UI auth to upload device signing keys. If we do, we upload
|
||||||
// no keys which would be a no-op.
|
// no keys which would be a no-op.
|
||||||
|
@ -248,7 +251,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
|
||||||
|
|
||||||
private onMigrateFormSubmit = (e: React.FormEvent): void => {
|
private onMigrateFormSubmit = (e: React.FormEvent): void => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (this.state.backupSigStatus.usable) {
|
if (this.state.backupSigStatus?.usable) {
|
||||||
this.bootstrapSecretStorage();
|
this.bootstrapSecretStorage();
|
||||||
} else {
|
} else {
|
||||||
this.restoreBackup();
|
this.restoreBackup();
|
||||||
|
@ -265,7 +268,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
|
||||||
};
|
};
|
||||||
|
|
||||||
private onDownloadClick = (): void => {
|
private onDownloadClick = (): void => {
|
||||||
const blob = new Blob([this.recoveryKey.encodedPrivateKey], {
|
const blob = new Blob([this.recoveryKey.encodedPrivateKey!], {
|
||||||
type: "text/plain;charset=us-ascii",
|
type: "text/plain;charset=us-ascii",
|
||||||
});
|
});
|
||||||
FileSaver.saveAs(blob, "security-key.txt");
|
FileSaver.saveAs(blob, "security-key.txt");
|
||||||
|
@ -323,7 +326,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
|
||||||
private bootstrapSecretStorage = async (): Promise<void> => {
|
private bootstrapSecretStorage = async (): Promise<void> => {
|
||||||
this.setState({
|
this.setState({
|
||||||
phase: Phase.Storing,
|
phase: Phase.Storing,
|
||||||
error: null,
|
error: undefined,
|
||||||
});
|
});
|
||||||
|
|
||||||
const cli = MatrixClientPeg.get();
|
const cli = MatrixClientPeg.get();
|
||||||
|
@ -351,7 +354,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
|
||||||
});
|
});
|
||||||
await cli.bootstrapSecretStorage({
|
await cli.bootstrapSecretStorage({
|
||||||
createSecretStorageKey: async () => this.recoveryKey,
|
createSecretStorageKey: async () => this.recoveryKey,
|
||||||
keyBackupInfo: this.state.backupInfo,
|
keyBackupInfo: this.state.backupInfo!,
|
||||||
setupNewKeyBackup: !this.state.backupInfo,
|
setupNewKeyBackup: !this.state.backupInfo,
|
||||||
getKeyBackupPassphrase: async (): Promise<Uint8Array> => {
|
getKeyBackupPassphrase: async (): Promise<Uint8Array> => {
|
||||||
// We may already have the backup key if we earlier went
|
// We may already have the backup key if we earlier went
|
||||||
|
@ -399,14 +402,14 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
|
||||||
showSummary: false,
|
showSummary: false,
|
||||||
keyCallback,
|
keyCallback,
|
||||||
},
|
},
|
||||||
null,
|
undefined,
|
||||||
/* priority = */ false,
|
/* priority = */ false,
|
||||||
/* static = */ false,
|
/* static = */ false,
|
||||||
);
|
);
|
||||||
|
|
||||||
await finished;
|
await finished;
|
||||||
const { backupSigStatus } = await this.fetchBackupInfo();
|
const { backupSigStatus } = await this.fetchBackupInfo();
|
||||||
if (backupSigStatus.usable && this.state.canUploadKeysWithPasswordOnly && this.state.accountPassword) {
|
if (backupSigStatus?.usable && this.state.canUploadKeysWithPasswordOnly && this.state.accountPassword) {
|
||||||
this.bootstrapSecretStorage();
|
this.bootstrapSecretStorage();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -467,7 +470,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
|
||||||
|
|
||||||
private onPassPhraseValidate = (result: IValidationResult): void => {
|
private onPassPhraseValidate = (result: IValidationResult): void => {
|
||||||
this.setState({
|
this.setState({
|
||||||
passPhraseValid: result.valid,
|
passPhraseValid: !!result.valid,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -581,13 +584,13 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
|
||||||
label={_t("Password")}
|
label={_t("Password")}
|
||||||
value={this.state.accountPassword}
|
value={this.state.accountPassword}
|
||||||
onChange={this.onAccountPasswordChange}
|
onChange={this.onAccountPasswordChange}
|
||||||
forceValidity={this.state.accountPasswordCorrect === false ? false : null}
|
forceValidity={this.state.accountPasswordCorrect === false ? false : undefined}
|
||||||
autoFocus={true}
|
autoFocus={true}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
} else if (!this.state.backupSigStatus.usable) {
|
} else if (!this.state.backupSigStatus?.usable) {
|
||||||
authPrompt = (
|
authPrompt = (
|
||||||
<div>
|
<div>
|
||||||
<div>{_t("Restore your key backup to upgrade your encryption")}</div>
|
<div>{_t("Restore your key backup to upgrade your encryption")}</div>
|
||||||
|
@ -612,7 +615,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
|
||||||
primaryButton={nextCaption}
|
primaryButton={nextCaption}
|
||||||
onPrimaryButtonClick={this.onMigrateFormSubmit}
|
onPrimaryButtonClick={this.onMigrateFormSubmit}
|
||||||
hasCancel={false}
|
hasCancel={false}
|
||||||
primaryDisabled={this.state.canUploadKeysWithPasswordOnly && !this.state.accountPassword}
|
primaryDisabled={!!this.state.canUploadKeysWithPasswordOnly && !this.state.accountPassword}
|
||||||
>
|
>
|
||||||
<button type="button" className="danger" onClick={this.onCancelClick}>
|
<button type="button" className="danger" onClick={this.onCancelClick}>
|
||||||
{_t("Skip")}
|
{_t("Skip")}
|
||||||
|
@ -680,7 +683,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
|
||||||
changeText = _t("Go back to set it again.");
|
changeText = _t("Go back to set it again.");
|
||||||
}
|
}
|
||||||
|
|
||||||
let passPhraseMatch = null;
|
let passPhraseMatch: JSX.Element | undefined;
|
||||||
if (matchText) {
|
if (matchText) {
|
||||||
passPhraseMatch = (
|
passPhraseMatch = (
|
||||||
<div>
|
<div>
|
||||||
|
@ -721,7 +724,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
|
||||||
}
|
}
|
||||||
|
|
||||||
private renderPhaseShowKey(): JSX.Element {
|
private renderPhaseShowKey(): JSX.Element {
|
||||||
let continueButton;
|
let continueButton: JSX.Element;
|
||||||
if (this.state.phase === Phase.ShowKey) {
|
if (this.state.phase === Phase.ShowKey) {
|
||||||
continueButton = (
|
continueButton = (
|
||||||
<DialogButtons
|
<DialogButtons
|
||||||
|
@ -928,7 +931,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let titleClass = null;
|
let titleClass: string | string[] | undefined;
|
||||||
switch (this.state.phase) {
|
switch (this.state.phase) {
|
||||||
case Phase.Passphrase:
|
case Phase.Passphrase:
|
||||||
case Phase.PassphraseConfirm:
|
case Phase.PassphraseConfirm:
|
||||||
|
|
|
@ -38,7 +38,7 @@ interface IProps {
|
||||||
|
|
||||||
interface IState {
|
interface IState {
|
||||||
phase: Phase;
|
phase: Phase;
|
||||||
errStr: string;
|
errStr: string | null;
|
||||||
passphrase1: string;
|
passphrase1: string;
|
||||||
passphrase2: string;
|
passphrase2: string;
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,11 @@ function readFileAsArrayBuffer(file: File): Promise<ArrayBuffer> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const reader = new FileReader();
|
const reader = new FileReader();
|
||||||
reader.onload = (e) => {
|
reader.onload = (e) => {
|
||||||
resolve(e.target.result as ArrayBuffer);
|
if (e.target?.result) {
|
||||||
|
resolve(e.target.result as ArrayBuffer);
|
||||||
|
} else {
|
||||||
|
reject(new Error("Failed to read file due to unknown error"));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
reader.onerror = reject;
|
reader.onerror = reject;
|
||||||
|
|
||||||
|
@ -49,7 +53,7 @@ interface IProps {
|
||||||
interface IState {
|
interface IState {
|
||||||
enableSubmit: boolean;
|
enableSubmit: boolean;
|
||||||
phase: Phase;
|
phase: Phase;
|
||||||
errStr: string;
|
errStr: string | null;
|
||||||
passphrase: string;
|
passphrase: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,7 +77,7 @@ export default class ImportE2eKeysDialog extends React.Component<IProps, IState>
|
||||||
}
|
}
|
||||||
|
|
||||||
private onFormChange = (): void => {
|
private onFormChange = (): void => {
|
||||||
const files = this.file.current.files;
|
const files = this.file.current?.files;
|
||||||
this.setState({
|
this.setState({
|
||||||
enableSubmit: this.state.passphrase !== "" && !!files?.length,
|
enableSubmit: this.state.passphrase !== "" && !!files?.length,
|
||||||
});
|
});
|
||||||
|
@ -87,7 +91,10 @@ export default class ImportE2eKeysDialog extends React.Component<IProps, IState>
|
||||||
private onFormSubmit = (ev: React.FormEvent): boolean => {
|
private onFormSubmit = (ev: React.FormEvent): boolean => {
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
// noinspection JSIgnoredPromiseFromCall
|
// noinspection JSIgnoredPromiseFromCall
|
||||||
this.startImport(this.file.current.files[0], this.state.passphrase);
|
const file = this.file.current?.files?.[0];
|
||||||
|
if (file) {
|
||||||
|
this.startImport(file, this.state.passphrase);
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -39,7 +39,7 @@ export default class RecoveryMethodRemovedDialog extends React.PureComponent<IPr
|
||||||
Modal.createDialogAsync(
|
Modal.createDialogAsync(
|
||||||
import("./CreateKeyBackupDialog") as unknown as Promise<ComponentType<{}>>,
|
import("./CreateKeyBackupDialog") as unknown as Promise<ComponentType<{}>>,
|
||||||
undefined,
|
undefined,
|
||||||
null,
|
undefined,
|
||||||
/* priority = */ false,
|
/* priority = */ false,
|
||||||
/* static = */ true,
|
/* static = */ true,
|
||||||
);
|
);
|
||||||
|
|
|
@ -70,7 +70,8 @@ export function selectText(target: Element): void {
|
||||||
* In certain browsers it may only work if triggered by a user action or may ask user for permissions
|
* In certain browsers it may only work if triggered by a user action or may ask user for permissions
|
||||||
* @param ref pointer to the node to copy
|
* @param ref pointer to the node to copy
|
||||||
*/
|
*/
|
||||||
export function copyNode(ref: Element): boolean {
|
export function copyNode(ref?: Element | null): boolean {
|
||||||
|
if (!ref) return false;
|
||||||
selectText(ref);
|
selectText(ref);
|
||||||
return document.execCommand("copy");
|
return document.execCommand("copy");
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue