Merge pull request #2594 from matrix-org/dbkr/dont_verify_restore
Prompt to restore backup rather than verifypull/21833/head
commit
742af81224
|
@ -38,7 +38,6 @@ limitations under the License.
|
||||||
margin: 0 10px;
|
margin: 0 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_RoomRecoveryReminder_button.mx_RoomRecoveryReminder_secondary {
|
.mx_RoomRecoveryReminder_secondary {
|
||||||
@mixin mx_DialogButton_secondary;
|
font-size: 90%;
|
||||||
background-color: transparent;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,7 @@ export default class RoomRecoveryReminder extends React.PureComponent {
|
||||||
this.state = {
|
this.state = {
|
||||||
loading: true,
|
loading: true,
|
||||||
error: null,
|
error: null,
|
||||||
unverifiedDevice: null,
|
backupInfo: null,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,10 +47,12 @@ export default class RoomRecoveryReminder extends React.PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
async _loadBackupStatus() {
|
async _loadBackupStatus() {
|
||||||
let backupSigStatus;
|
|
||||||
try {
|
try {
|
||||||
const backupInfo = await MatrixClientPeg.get().getKeyBackupVersion();
|
const backupInfo = await MatrixClientPeg.get().getKeyBackupVersion();
|
||||||
backupSigStatus = await MatrixClientPeg.get().isKeyBackupTrusted(backupInfo);
|
this.setState({
|
||||||
|
loading: false,
|
||||||
|
backupInfo,
|
||||||
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log("Unable to fetch key backup status", e);
|
console.log("Unable to fetch key backup status", e);
|
||||||
this.setState({
|
this.setState({
|
||||||
|
@ -59,44 +61,20 @@ export default class RoomRecoveryReminder extends React.PureComponent {
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let unverifiedDevice;
|
|
||||||
for (const sig of backupSigStatus.sigs) {
|
|
||||||
if (sig.device && !sig.device.isVerified()) {
|
|
||||||
unverifiedDevice = sig.device;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.setState({
|
|
||||||
loading: false,
|
|
||||||
unverifiedDevice,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
showSetupDialog = () => {
|
showSetupDialog = () => {
|
||||||
if (this.state.unverifiedDevice) {
|
if (this.state.backupInfo) {
|
||||||
// A key backup exists for this account, but the creating device is not
|
// A key backup exists for this account, but the creating device is not
|
||||||
// verified, so we'll show the device verify dialog.
|
// verified, so restore the backup which will give us the keys from it and
|
||||||
// TODO: Should change to a restore key backup flow that checks the recovery
|
// allow us to trust it (ie. upload keys to it)
|
||||||
// passphrase while at the same time also cross-signing the device as well in
|
const RestoreKeyBackupDialog = sdk.getComponent('dialogs.keybackup.RestoreKeyBackupDialog');
|
||||||
// a single flow (for cases where a key backup exists but the backup creating
|
Modal.createTrackedDialog('Restore Backup', '', RestoreKeyBackupDialog, {});
|
||||||
// device is unverified). Since we don't have that yet, we'll look for an
|
} else {
|
||||||
// unverified device and verify it. Note that this means we won't restore
|
Modal.createTrackedDialogAsync("Key Backup", "Key Backup",
|
||||||
// keys yet; instead we'll only trust the backup for sending our own new keys
|
import("../../../async-components/views/dialogs/keybackup/CreateKeyBackupDialog"),
|
||||||
// to it.
|
);
|
||||||
const DeviceVerifyDialog = sdk.getComponent('views.dialogs.DeviceVerifyDialog');
|
|
||||||
Modal.createTrackedDialog('Device Verify Dialog', '', DeviceVerifyDialog, {
|
|
||||||
userId: MatrixClientPeg.get().credentials.userId,
|
|
||||||
device: this.state.unverifiedDevice,
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// The default case assumes that a key backup doesn't exist for this account, so
|
|
||||||
// we'll show the create key backup flow.
|
|
||||||
Modal.createTrackedDialogAsync("Key Backup", "Key Backup",
|
|
||||||
import("../../../async-components/views/dialogs/keybackup/CreateKeyBackupDialog"),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onDontAskAgainClick = () => {
|
onDontAskAgainClick = () => {
|
||||||
|
@ -133,53 +111,40 @@ export default class RoomRecoveryReminder extends React.PureComponent {
|
||||||
const AccessibleButton = sdk.getComponent("views.elements.AccessibleButton");
|
const AccessibleButton = sdk.getComponent("views.elements.AccessibleButton");
|
||||||
|
|
||||||
let body;
|
let body;
|
||||||
let primaryCaption = _t("Set up");
|
|
||||||
if (this.state.error) {
|
if (this.state.error) {
|
||||||
body = <div className="error">
|
body = <div className="error">
|
||||||
{_t("Unable to load key backup status")}
|
{_t("Unable to load key backup status")}
|
||||||
</div>;
|
</div>;
|
||||||
} else if (this.state.unverifiedDevice) {
|
} else if (this.state.backupInfo) {
|
||||||
// A key backup exists for this account, but the creating device is not
|
// A key backup exists for this account, but we're not using it.
|
||||||
// verified.
|
|
||||||
body = <div>
|
body = <div>
|
||||||
<p>{_t(
|
<p>{_t(
|
||||||
"Secure Message Recovery has been set up on another device: <deviceName></deviceName>",
|
"Secure Key Backup should be active on all of your devices to avoid " +
|
||||||
{},
|
"losing access to your encrypted messages.",
|
||||||
{
|
|
||||||
deviceName: () => <i>{this.state.unverifiedDevice.unsigned.device_display_name}</i>,
|
|
||||||
},
|
|
||||||
)}</p>
|
|
||||||
<p>{_t(
|
|
||||||
"To view your secure message history and ensure you can view new " +
|
|
||||||
"messages on future devices, verify that device now.",
|
|
||||||
)}</p>
|
)}</p>
|
||||||
</div>;
|
</div>;
|
||||||
primaryCaption = _t("Verify device");
|
|
||||||
} else {
|
} else {
|
||||||
// The default case assumes that a key backup doesn't exist for this account.
|
|
||||||
// (This component doesn't currently check that itself.)
|
|
||||||
body = _t(
|
body = _t(
|
||||||
"If you log out or use another device, you'll lose your " +
|
"Securely back up your decryption keys to the server to make sure " +
|
||||||
"secure message history. To prevent this, set up Secure " +
|
"you'll always be able to read your encrypted messages.",
|
||||||
"Message Recovery.",
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mx_RoomRecoveryReminder">
|
<div className="mx_RoomRecoveryReminder">
|
||||||
<div className="mx_RoomRecoveryReminder_header">{_t(
|
<div className="mx_RoomRecoveryReminder_header">{_t(
|
||||||
"Secure Message Recovery",
|
"Don't risk losing your encrypted messages!",
|
||||||
)}</div>
|
)}</div>
|
||||||
<div className="mx_RoomRecoveryReminder_body">{body}</div>
|
<div className="mx_RoomRecoveryReminder_body">{body}</div>
|
||||||
<div className="mx_RoomRecoveryReminder_buttons">
|
<div className="mx_RoomRecoveryReminder_buttons">
|
||||||
<AccessibleButton className="mx_RoomRecoveryReminder_button mx_RoomRecoveryReminder_secondary"
|
|
||||||
onClick={this.onDontAskAgainClick}>
|
|
||||||
{ _t("Don't ask again") }
|
|
||||||
</AccessibleButton>
|
|
||||||
<AccessibleButton className="mx_RoomRecoveryReminder_button"
|
<AccessibleButton className="mx_RoomRecoveryReminder_button"
|
||||||
onClick={this.onSetupClick}>
|
onClick={this.onSetupClick}>
|
||||||
{primaryCaption}
|
{_t("Activate Secure Key Backup")}
|
||||||
</AccessibleButton>
|
</AccessibleButton>
|
||||||
|
<p><AccessibleButton className="mx_RoomRecoveryReminder_secondary mx_linkButton"
|
||||||
|
onClick={this.onDontAskAgainClick}>
|
||||||
|
{ _t("No thanks, I'll download a copy of my decryption keys before I log out") }
|
||||||
|
</AccessibleButton></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -27,7 +27,6 @@ export default class KeyBackupPanel extends React.PureComponent {
|
||||||
|
|
||||||
this._startNewBackup = this._startNewBackup.bind(this);
|
this._startNewBackup = this._startNewBackup.bind(this);
|
||||||
this._deleteBackup = this._deleteBackup.bind(this);
|
this._deleteBackup = this._deleteBackup.bind(this);
|
||||||
this._verifyDevice = this._verifyDevice.bind(this);
|
|
||||||
this._onKeyBackupSessionsRemaining =
|
this._onKeyBackupSessionsRemaining =
|
||||||
this._onKeyBackupSessionsRemaining.bind(this);
|
this._onKeyBackupSessionsRemaining.bind(this);
|
||||||
this._onKeyBackupStatus = this._onKeyBackupStatus.bind(this);
|
this._onKeyBackupStatus = this._onKeyBackupStatus.bind(this);
|
||||||
|
@ -133,19 +132,6 @@ export default class KeyBackupPanel extends React.PureComponent {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_verifyDevice(e) {
|
|
||||||
const device = this.state.backupSigStatus.sigs[e.target.getAttribute('data-sigindex')].device;
|
|
||||||
|
|
||||||
const DeviceVerifyDialog = sdk.getComponent('views.dialogs.DeviceVerifyDialog');
|
|
||||||
Modal.createTrackedDialog('Device Verify Dialog', '', DeviceVerifyDialog, {
|
|
||||||
userId: MatrixClientPeg.get().credentials.userId,
|
|
||||||
device: device,
|
|
||||||
onFinished: () => {
|
|
||||||
this._loadBackupStatus();
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const Spinner = sdk.getComponent("elements.Spinner");
|
const Spinner = sdk.getComponent("elements.Spinner");
|
||||||
const AccessibleButton = sdk.getComponent("elements.AccessibleButton");
|
const AccessibleButton = sdk.getComponent("elements.AccessibleButton");
|
||||||
|
@ -163,9 +149,8 @@ export default class KeyBackupPanel extends React.PureComponent {
|
||||||
if (MatrixClientPeg.get().getKeyBackupEnabled()) {
|
if (MatrixClientPeg.get().getKeyBackupEnabled()) {
|
||||||
clientBackupStatus = _t("This device is using key backup");
|
clientBackupStatus = _t("This device is using key backup");
|
||||||
} else {
|
} else {
|
||||||
// XXX: display why and how to fix it
|
|
||||||
clientBackupStatus = _t(
|
clientBackupStatus = _t(
|
||||||
"This device is <b>not</b> using key backup", {},
|
"This device is <b>not</b> using key backup. Restore the backup to start using it.", {},
|
||||||
{b: x => <b>{x}</b>},
|
{b: x => <b>{x}</b>},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -233,17 +218,8 @@ export default class KeyBackupPanel extends React.PureComponent {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let verifyButton;
|
|
||||||
if (sig.device && !sig.device.isVerified()) {
|
|
||||||
verifyButton = <div><br /><AccessibleButton className="mx_GeneralButton"
|
|
||||||
onClick={this._verifyDevice} data-sigindex={i}>
|
|
||||||
{ _t("Verify...") }
|
|
||||||
</AccessibleButton></div>;
|
|
||||||
}
|
|
||||||
|
|
||||||
return <div key={i}>
|
return <div key={i}>
|
||||||
{sigStatus}
|
{sigStatus}
|
||||||
{verifyButton}
|
|
||||||
</div>;
|
</div>;
|
||||||
});
|
});
|
||||||
if (this.state.backupSigStatus.sigs.length === 0) {
|
if (this.state.backupSigStatus.sigs.length === 0) {
|
||||||
|
@ -256,12 +232,15 @@ export default class KeyBackupPanel extends React.PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
return <div>
|
return <div>
|
||||||
<div>{_t("Backup version: ")}{this.state.backupInfo.version}</div>
|
|
||||||
<div>{_t("Algorithm: ")}{this.state.backupInfo.algorithm}</div>
|
|
||||||
<div>{clientBackupStatus}</div>
|
<div>{clientBackupStatus}</div>
|
||||||
{uploadStatus}
|
<details>
|
||||||
<div>{backupSigStatuses}</div>
|
<summary>{_t("Advanced")}</summary>
|
||||||
<div>{trustedLocally}</div>
|
<div>{_t("Backup version: ")}{this.state.backupInfo.version}</div>
|
||||||
|
<div>{_t("Algorithm: ")}{this.state.backupInfo.algorithm}</div>
|
||||||
|
{uploadStatus}
|
||||||
|
<div>{backupSigStatuses}</div>
|
||||||
|
<div>{trustedLocally}</div>
|
||||||
|
</details>
|
||||||
<p>
|
<p>
|
||||||
<AccessibleButton kind="primary" onClick={this._restoreBackup}>
|
<AccessibleButton kind="primary" onClick={this._restoreBackup}>
|
||||||
{ _t("Restore backup") }
|
{ _t("Restore backup") }
|
||||||
|
|
|
@ -443,7 +443,7 @@
|
||||||
"Delete backup": "Delete backup",
|
"Delete backup": "Delete backup",
|
||||||
"Unable to load key backup status": "Unable to load key backup status",
|
"Unable to load key backup status": "Unable to load key backup status",
|
||||||
"This device is using key backup": "This device is using key backup",
|
"This device is using key backup": "This device is using key backup",
|
||||||
"This device is <b>not</b> using key backup": "This device is <b>not</b> using key backup",
|
"This device is <b>not</b> using key backup. Restore the backup to start using it.": "This device is <b>not</b> using key backup. Restore the backup to start using it.",
|
||||||
"Backing up %(sessionsRemaining)s keys...": "Backing up %(sessionsRemaining)s keys...",
|
"Backing up %(sessionsRemaining)s keys...": "Backing up %(sessionsRemaining)s keys...",
|
||||||
"All keys backed up": "All keys backed up",
|
"All keys backed up": "All keys backed up",
|
||||||
"Backup has a signature from <verify>unknown</verify> device with ID %(deviceId)s.": "Backup has a signature from <verify>unknown</verify> device with ID %(deviceId)s.",
|
"Backup has a signature from <verify>unknown</verify> device with ID %(deviceId)s.": "Backup has a signature from <verify>unknown</verify> device with ID %(deviceId)s.",
|
||||||
|
@ -452,9 +452,9 @@
|
||||||
"Backup has a <validity>valid</validity> signature from <verify>unverified</verify> device <device></device>": "Backup has a <validity>valid</validity> signature from <verify>unverified</verify> device <device></device>",
|
"Backup has a <validity>valid</validity> signature from <verify>unverified</verify> device <device></device>": "Backup has a <validity>valid</validity> signature from <verify>unverified</verify> device <device></device>",
|
||||||
"Backup has an <validity>invalid</validity> signature from <verify>verified</verify> device <device></device>": "Backup has an <validity>invalid</validity> signature from <verify>verified</verify> device <device></device>",
|
"Backup has an <validity>invalid</validity> signature from <verify>verified</verify> device <device></device>": "Backup has an <validity>invalid</validity> signature from <verify>verified</verify> device <device></device>",
|
||||||
"Backup has an <validity>invalid</validity> signature from <verify>unverified</verify> device <device></device>": "Backup has an <validity>invalid</validity> signature from <verify>unverified</verify> device <device></device>",
|
"Backup has an <validity>invalid</validity> signature from <verify>unverified</verify> device <device></device>": "Backup has an <validity>invalid</validity> signature from <verify>unverified</verify> device <device></device>",
|
||||||
"Verify...": "Verify...",
|
|
||||||
"Backup is not signed by any of your devices": "Backup is not signed by any of your devices",
|
"Backup is not signed by any of your devices": "Backup is not signed by any of your devices",
|
||||||
"This backup is trusted because it has been restored on this device": "This backup is trusted because it has been restored on this device",
|
"This backup is trusted because it has been restored on this device": "This backup is trusted because it has been restored on this device",
|
||||||
|
"Advanced": "Advanced",
|
||||||
"Backup version: ": "Backup version: ",
|
"Backup version: ": "Backup version: ",
|
||||||
"Algorithm: ": "Algorithm: ",
|
"Algorithm: ": "Algorithm: ",
|
||||||
"Restore backup": "Restore backup",
|
"Restore backup": "Restore backup",
|
||||||
|
@ -498,7 +498,6 @@
|
||||||
"Save": "Save",
|
"Save": "Save",
|
||||||
"This room is not accessible by remote Matrix servers": "This room is not accessible by remote Matrix servers",
|
"This room is not accessible by remote Matrix servers": "This room is not accessible by remote Matrix servers",
|
||||||
"Upgrade room to version %(ver)s": "Upgrade room to version %(ver)s",
|
"Upgrade room to version %(ver)s": "Upgrade room to version %(ver)s",
|
||||||
"Advanced": "Advanced",
|
|
||||||
"Room information": "Room information",
|
"Room information": "Room information",
|
||||||
"Internal room ID:": "Internal room ID:",
|
"Internal room ID:": "Internal room ID:",
|
||||||
"Room version": "Room version",
|
"Room version": "Room version",
|
||||||
|
@ -786,13 +785,11 @@
|
||||||
"You are trying to access a room.": "You are trying to access a room.",
|
"You are trying to access a room.": "You are trying to access a room.",
|
||||||
"<a>Click here</a> to join the discussion!": "<a>Click here</a> to join the discussion!",
|
"<a>Click here</a> to join the discussion!": "<a>Click here</a> to join the discussion!",
|
||||||
"This is a preview of this room. Room interactions have been disabled": "This is a preview of this room. Room interactions have been disabled",
|
"This is a preview of this room. Room interactions have been disabled": "This is a preview of this room. Room interactions have been disabled",
|
||||||
"Set up": "Set up",
|
"Secure Key Backup should be active on all of your devices to avoid losing access to your encrypted messages.": "Secure Key Backup should be active on all of your devices to avoid losing access to your encrypted messages.",
|
||||||
"Secure Message Recovery has been set up on another device: <deviceName></deviceName>": "Secure Message Recovery has been set up on another device: <deviceName></deviceName>",
|
"Securely back up your decryption keys to the server to make sure you'll always be able to read your encrypted messages.": "Securely back up your decryption keys to the server to make sure you'll always be able to read your encrypted messages.",
|
||||||
"To view your secure message history and ensure you can view new messages on future devices, verify that device now.": "To view your secure message history and ensure you can view new messages on future devices, verify that device now.",
|
"Don't risk losing your encrypted messages!": "Don't risk losing your encrypted messages!",
|
||||||
"Verify device": "Verify device",
|
"Activate Secure Key Backup": "Activate Secure Key Backup",
|
||||||
"If you log out or use another device, you'll lose your secure message history. To prevent this, set up Secure Message Recovery.": "If you log out or use another device, you'll lose your secure message history. To prevent this, set up Secure Message Recovery.",
|
"No thanks, I'll download a copy of my decryption keys before I log out": "No thanks, I'll download a copy of my decryption keys before I log out",
|
||||||
"Secure Message Recovery": "Secure Message Recovery",
|
|
||||||
"Don't ask again": "Don't ask again",
|
|
||||||
"Add a topic": "Add a topic",
|
"Add a topic": "Add a topic",
|
||||||
"This room is using an unstable room version. If you aren't expecting this, please upgrade the room.": "This room is using an unstable room version. If you aren't expecting this, please upgrade the room.",
|
"This room is using an unstable room version. If you aren't expecting this, please upgrade the room.": "This room is using an unstable room version. If you aren't expecting this, please upgrade the room.",
|
||||||
"Click here to upgrade to the latest room version.": "Click here to upgrade to the latest room version.",
|
"Click here to upgrade to the latest room version.": "Click here to upgrade to the latest room version.",
|
||||||
|
@ -927,6 +924,7 @@
|
||||||
"Unblacklist": "Unblacklist",
|
"Unblacklist": "Unblacklist",
|
||||||
"Blacklist": "Blacklist",
|
"Blacklist": "Blacklist",
|
||||||
"Unverify": "Unverify",
|
"Unverify": "Unverify",
|
||||||
|
"Verify...": "Verify...",
|
||||||
"Join": "Join",
|
"Join": "Join",
|
||||||
"No results": "No results",
|
"No results": "No results",
|
||||||
"Delete": "Delete",
|
"Delete": "Delete",
|
||||||
|
@ -1058,6 +1056,7 @@
|
||||||
"Please forget all messages I have sent when my account is deactivated (<b>Warning:</b> this will cause future users to see an incomplete view of conversations)": "Please forget all messages I have sent when my account is deactivated (<b>Warning:</b> this will cause future users to see an incomplete view of conversations)",
|
"Please forget all messages I have sent when my account is deactivated (<b>Warning:</b> this will cause future users to see an incomplete view of conversations)": "Please forget all messages I have sent when my account is deactivated (<b>Warning:</b> this will cause future users to see an incomplete view of conversations)",
|
||||||
"To continue, please enter your password:": "To continue, please enter your password:",
|
"To continue, please enter your password:": "To continue, please enter your password:",
|
||||||
"password": "password",
|
"password": "password",
|
||||||
|
"Verify device": "Verify device",
|
||||||
"Use Legacy Verification (for older clients)": "Use Legacy Verification (for older clients)",
|
"Use Legacy Verification (for older clients)": "Use Legacy Verification (for older clients)",
|
||||||
"Verify by comparing a short text string.": "Verify by comparing a short text string.",
|
"Verify by comparing a short text string.": "Verify by comparing a short text string.",
|
||||||
"Begin Verifying": "Begin Verifying",
|
"Begin Verifying": "Begin Verifying",
|
||||||
|
@ -1523,6 +1522,8 @@
|
||||||
"Retry": "Retry",
|
"Retry": "Retry",
|
||||||
"Without setting up Secure Message Recovery, you'll lose your secure message history when you log out.": "Without setting up Secure Message Recovery, you'll lose your secure message history when you log out.",
|
"Without setting up Secure Message Recovery, you'll lose your secure message history when you log out.": "Without setting up Secure Message Recovery, you'll lose your secure message history when you log out.",
|
||||||
"If you don't want to set this up now, you can later in Settings.": "If you don't want to set this up now, you can later in Settings.",
|
"If you don't want to set this up now, you can later in Settings.": "If you don't want to set this up now, you can later in Settings.",
|
||||||
|
"Set up": "Set up",
|
||||||
|
"Don't ask again": "Don't ask again",
|
||||||
"New Recovery Method": "New Recovery Method",
|
"New Recovery Method": "New Recovery Method",
|
||||||
"A new recovery passphrase and key for Secure Messages have been detected.": "A new recovery passphrase and key for Secure Messages have been detected.",
|
"A new recovery passphrase and key for Secure Messages have been detected.": "A new recovery passphrase and key for Secure Messages have been detected.",
|
||||||
"If you didn't set the new recovery method, an attacker may be trying to access your account. Change your account password and set a new recovery method immediately in Settings.": "If you didn't set the new recovery method, an attacker may be trying to access your account. Change your account password and set a new recovery method immediately in Settings.",
|
"If you didn't set the new recovery method, an attacker may be trying to access your account. Change your account password and set a new recovery method immediately in Settings.": "If you didn't set the new recovery method, an attacker may be trying to access your account. Change your account password and set a new recovery method immediately in Settings.",
|
||||||
|
|
Loading…
Reference in New Issue