mirror of https://github.com/vector-im/riot-web
Apply strictNullChecks to src/async-components/* (#10251
* Apply strictNullChecks to src/async-components/* * Iteratepull/28217/head
parent
629e5cb01f
commit
8ad21e6492
|
@ -38,7 +38,7 @@ interface IState {
|
|||
eventCount: number;
|
||||
crawlingRoomsCount: number;
|
||||
roomCount: number;
|
||||
currentRoom: string;
|
||||
currentRoom: string | null;
|
||||
crawlerSleepTime: number;
|
||||
}
|
||||
|
||||
|
@ -61,7 +61,8 @@ export default class ManageEventIndexDialog extends React.Component<IProps, ISta
|
|||
|
||||
public updateCurrentRoom = async (room: Room): Promise<void> => {
|
||||
const eventIndex = EventIndexPeg.get();
|
||||
let stats: IIndexStats;
|
||||
if (!eventIndex) return;
|
||||
let stats: IIndexStats | undefined;
|
||||
|
||||
try {
|
||||
stats = await eventIndex.getStats();
|
||||
|
@ -71,7 +72,7 @@ export default class ManageEventIndexDialog extends React.Component<IProps, ISta
|
|||
return;
|
||||
}
|
||||
|
||||
let currentRoom = null;
|
||||
let currentRoom: string | null = null;
|
||||
|
||||
if (room) currentRoom = room.name;
|
||||
const roomStats = eventIndex.crawlingRooms();
|
||||
|
@ -79,8 +80,8 @@ export default class ManageEventIndexDialog extends React.Component<IProps, ISta
|
|||
const roomCount = roomStats.totalRooms.size;
|
||||
|
||||
this.setState({
|
||||
eventIndexSize: stats.size,
|
||||
eventCount: stats.eventCount,
|
||||
eventIndexSize: stats?.size ?? 0,
|
||||
eventCount: stats?.eventCount ?? 0,
|
||||
crawlingRoomsCount: crawlingRoomsCount,
|
||||
roomCount: roomCount,
|
||||
currentRoom: currentRoom,
|
||||
|
@ -100,7 +101,7 @@ export default class ManageEventIndexDialog extends React.Component<IProps, ISta
|
|||
let crawlingRoomsCount = 0;
|
||||
let roomCount = 0;
|
||||
let eventCount = 0;
|
||||
let currentRoom = null;
|
||||
let currentRoom: string | null = null;
|
||||
|
||||
const eventIndex = EventIndexPeg.get();
|
||||
|
||||
|
@ -109,8 +110,10 @@ export default class ManageEventIndexDialog extends React.Component<IProps, ISta
|
|||
|
||||
try {
|
||||
const stats = await eventIndex.getStats();
|
||||
eventIndexSize = stats.size;
|
||||
eventCount = stats.eventCount;
|
||||
if (stats) {
|
||||
eventIndexSize = stats.size;
|
||||
eventCount = stats.eventCount;
|
||||
}
|
||||
} catch {
|
||||
// This call may fail if sporadically, not a huge issue as we
|
||||
// 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> => {
|
||||
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 => {
|
||||
|
|
|
@ -49,7 +49,7 @@ interface IProps {
|
|||
}
|
||||
|
||||
interface IState {
|
||||
secureSecretStorage: boolean;
|
||||
secureSecretStorage: boolean | null;
|
||||
phase: Phase;
|
||||
passPhrase: string;
|
||||
passPhraseValid: boolean;
|
||||
|
@ -121,7 +121,7 @@ export default class CreateKeyBackupDialog extends React.PureComponent<IProps, I
|
|||
const { secureSecretStorage } = this.state;
|
||||
this.setState({
|
||||
phase: Phase.BackingUp,
|
||||
error: null,
|
||||
error: undefined,
|
||||
});
|
||||
let info;
|
||||
try {
|
||||
|
@ -219,7 +219,7 @@ export default class CreateKeyBackupDialog extends React.PureComponent<IProps, I
|
|||
|
||||
private onPassPhraseValidate = (result: IValidationResult): void => {
|
||||
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.");
|
||||
}
|
||||
|
||||
let passPhraseMatch = null;
|
||||
let passPhraseMatch: JSX.Element | undefined;
|
||||
if (matchText) {
|
||||
passPhraseMatch = (
|
||||
<div className="mx_CreateKeyBackupDialog_passPhraseMatch">
|
||||
|
|
|
@ -81,13 +81,13 @@ interface IState {
|
|||
copied: boolean;
|
||||
downloaded: boolean;
|
||||
setPassphrase: boolean;
|
||||
backupInfo: IKeyBackupInfo;
|
||||
backupSigStatus: TrustInfo;
|
||||
backupInfo: IKeyBackupInfo | null;
|
||||
backupSigStatus: TrustInfo | null;
|
||||
// does the server offer a UI auth flow with just m.login.password
|
||||
// for /keys/device_signing/upload?
|
||||
canUploadKeysWithPasswordOnly: boolean;
|
||||
canUploadKeysWithPasswordOnly: boolean | null;
|
||||
accountPassword: string;
|
||||
accountPasswordCorrect: boolean;
|
||||
accountPasswordCorrect: boolean | null;
|
||||
canSkip: boolean;
|
||||
passPhraseKeySelected: string;
|
||||
error?: string;
|
||||
|
@ -119,7 +119,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
|
|||
}
|
||||
|
||||
const accountPassword = props.accountPassword || "";
|
||||
let canUploadKeysWithPasswordOnly = null;
|
||||
let canUploadKeysWithPasswordOnly: boolean | null = null;
|
||||
if (accountPassword) {
|
||||
// If we have an account password in memory, let's simplify and
|
||||
// assume it means password auth is also supported for device
|
||||
|
@ -172,12 +172,14 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
|
|||
this.fetchBackupInfo();
|
||||
}
|
||||
|
||||
private async fetchBackupInfo(): Promise<{ backupInfo: IKeyBackupInfo; backupSigStatus: TrustInfo }> {
|
||||
private async fetchBackupInfo(): Promise<{ backupInfo?: IKeyBackupInfo; backupSigStatus?: TrustInfo }> {
|
||||
try {
|
||||
const backupInfo = await MatrixClientPeg.get().getKeyBackupVersion();
|
||||
const backupSigStatus =
|
||||
// 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 phase = backupInfo && !forceReset ? Phase.Migrate : Phase.ChooseKeyPassphrase;
|
||||
|
@ -189,17 +191,18 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
|
|||
});
|
||||
|
||||
return {
|
||||
backupInfo,
|
||||
backupSigStatus,
|
||||
backupInfo: backupInfo ?? undefined,
|
||||
backupSigStatus: backupSigStatus ?? undefined,
|
||||
};
|
||||
} catch (e) {
|
||||
this.setState({ phase: Phase.LoadError });
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
private async queryKeyUploadAuth(): Promise<void> {
|
||||
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
|
||||
// UI auth to upload device signing keys. If we do, we upload
|
||||
// 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 => {
|
||||
e.preventDefault();
|
||||
if (this.state.backupSigStatus.usable) {
|
||||
if (this.state.backupSigStatus?.usable) {
|
||||
this.bootstrapSecretStorage();
|
||||
} else {
|
||||
this.restoreBackup();
|
||||
|
@ -265,7 +268,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
|
|||
};
|
||||
|
||||
private onDownloadClick = (): void => {
|
||||
const blob = new Blob([this.recoveryKey.encodedPrivateKey], {
|
||||
const blob = new Blob([this.recoveryKey.encodedPrivateKey!], {
|
||||
type: "text/plain;charset=us-ascii",
|
||||
});
|
||||
FileSaver.saveAs(blob, "security-key.txt");
|
||||
|
@ -323,7 +326,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
|
|||
private bootstrapSecretStorage = async (): Promise<void> => {
|
||||
this.setState({
|
||||
phase: Phase.Storing,
|
||||
error: null,
|
||||
error: undefined,
|
||||
});
|
||||
|
||||
const cli = MatrixClientPeg.get();
|
||||
|
@ -351,7 +354,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
|
|||
});
|
||||
await cli.bootstrapSecretStorage({
|
||||
createSecretStorageKey: async () => this.recoveryKey,
|
||||
keyBackupInfo: this.state.backupInfo,
|
||||
keyBackupInfo: this.state.backupInfo!,
|
||||
setupNewKeyBackup: !this.state.backupInfo,
|
||||
getKeyBackupPassphrase: async (): Promise<Uint8Array> => {
|
||||
// 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,
|
||||
keyCallback,
|
||||
},
|
||||
null,
|
||||
undefined,
|
||||
/* priority = */ false,
|
||||
/* static = */ false,
|
||||
);
|
||||
|
||||
await finished;
|
||||
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();
|
||||
}
|
||||
};
|
||||
|
@ -467,7 +470,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
|
|||
|
||||
private onPassPhraseValidate = (result: IValidationResult): void => {
|
||||
this.setState({
|
||||
passPhraseValid: result.valid,
|
||||
passPhraseValid: !!result.valid,
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -581,13 +584,13 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
|
|||
label={_t("Password")}
|
||||
value={this.state.accountPassword}
|
||||
onChange={this.onAccountPasswordChange}
|
||||
forceValidity={this.state.accountPasswordCorrect === false ? false : null}
|
||||
forceValidity={this.state.accountPasswordCorrect === false ? false : undefined}
|
||||
autoFocus={true}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
} else if (!this.state.backupSigStatus.usable) {
|
||||
} else if (!this.state.backupSigStatus?.usable) {
|
||||
authPrompt = (
|
||||
<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}
|
||||
onPrimaryButtonClick={this.onMigrateFormSubmit}
|
||||
hasCancel={false}
|
||||
primaryDisabled={this.state.canUploadKeysWithPasswordOnly && !this.state.accountPassword}
|
||||
primaryDisabled={!!this.state.canUploadKeysWithPasswordOnly && !this.state.accountPassword}
|
||||
>
|
||||
<button type="button" className="danger" onClick={this.onCancelClick}>
|
||||
{_t("Skip")}
|
||||
|
@ -680,7 +683,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
|
|||
changeText = _t("Go back to set it again.");
|
||||
}
|
||||
|
||||
let passPhraseMatch = null;
|
||||
let passPhraseMatch: JSX.Element | undefined;
|
||||
if (matchText) {
|
||||
passPhraseMatch = (
|
||||
<div>
|
||||
|
@ -721,7 +724,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
|
|||
}
|
||||
|
||||
private renderPhaseShowKey(): JSX.Element {
|
||||
let continueButton;
|
||||
let continueButton: JSX.Element;
|
||||
if (this.state.phase === Phase.ShowKey) {
|
||||
continueButton = (
|
||||
<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) {
|
||||
case Phase.Passphrase:
|
||||
case Phase.PassphraseConfirm:
|
||||
|
|
|
@ -38,7 +38,7 @@ interface IProps {
|
|||
|
||||
interface IState {
|
||||
phase: Phase;
|
||||
errStr: string;
|
||||
errStr: string | null;
|
||||
passphrase1: string;
|
||||
passphrase2: string;
|
||||
}
|
||||
|
|
|
@ -28,7 +28,11 @@ function readFileAsArrayBuffer(file: File): Promise<ArrayBuffer> {
|
|||
return new Promise((resolve, reject) => {
|
||||
const reader = new FileReader();
|
||||
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;
|
||||
|
||||
|
@ -49,7 +53,7 @@ interface IProps {
|
|||
interface IState {
|
||||
enableSubmit: boolean;
|
||||
phase: Phase;
|
||||
errStr: string;
|
||||
errStr: string | null;
|
||||
passphrase: string;
|
||||
}
|
||||
|
||||
|
@ -73,7 +77,7 @@ export default class ImportE2eKeysDialog extends React.Component<IProps, IState>
|
|||
}
|
||||
|
||||
private onFormChange = (): void => {
|
||||
const files = this.file.current.files;
|
||||
const files = this.file.current?.files;
|
||||
this.setState({
|
||||
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 => {
|
||||
ev.preventDefault();
|
||||
// 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;
|
||||
};
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@ export default class RecoveryMethodRemovedDialog extends React.PureComponent<IPr
|
|||
Modal.createDialogAsync(
|
||||
import("./CreateKeyBackupDialog") as unknown as Promise<ComponentType<{}>>,
|
||||
undefined,
|
||||
null,
|
||||
undefined,
|
||||
/* priority = */ false,
|
||||
/* 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
|
||||
* @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);
|
||||
return document.execCommand("copy");
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue