Apply strictNullChecks to src/async-components/* (#10251

* Apply strictNullChecks to src/async-components/*

* Iterate
This commit is contained in:
Michael Telatyński 2023-02-28 10:51:27 +00:00 committed by GitHub
parent 629e5cb01f
commit 8ad21e6492
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 57 additions and 43 deletions

View file

@ -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 => {

View file

@ -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">

View file

@ -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:

View file

@ -38,7 +38,7 @@ interface IProps {
interface IState {
phase: Phase;
errStr: string;
errStr: string | null;
passphrase1: string;
passphrase2: string;
}

View file

@ -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;
};

View file

@ -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,
);

View file

@ -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");
}