fix: make sure to display password setup page again when appropriate

The feature to accept accounts from the command line via otpauth:// URI inadvertently broke the initial password setup flow.
With this change password setup and unlocking should now work correctly again in all cases/flows.

Issues: #14
master
Johan Ouwerkerk 2020-11-09 19:20:08 +01:00
parent 5c6c9020d8
commit 8d1a88b8df
3 changed files with 61 additions and 13 deletions

View File

@ -23,8 +23,6 @@ Kirigami.ApplicationWindow {
property Models.ValidatedAccountInput validatedInput: Models.ValidatedAccountInput {}
property Models.PasswordRequestModel passwordRequest: Keysmith.passwordRequest()
property Component passwordRequestPage: passwordRequest.previouslyDefined ? unlockAccountsPage : setupPasswordPage
Component {
id: setupPasswordPage
SetupPassword {
@ -63,11 +61,13 @@ Kirigami.ApplicationWindow {
}
onCancelled: {
root.addAccountConfirmed = false;
popAddAccountPage(passwordRequestPage);
popAddAccountPage();
pushPasswordPage();
}
onNewAccount: {
root.addAccountConfirmed = true;
popAddAccountPage(passwordRequestPage);
popAddAccountPage();
pushPasswordPage();
}
}
}
@ -95,7 +95,8 @@ Kirigami.ApplicationWindow {
title: i18nc("@title:window", "Invalid account")
error: i18nc("@info:label", "The account you are trying to add is invalid. You can either quit the app, or continue without adding the account.")
onDismissed: {
popAddAccountPage(passwordRequestPage);
popAddAccountPage();
pushPasswordPage();
}
onQuit: {
pageStack.pop();
@ -152,6 +153,17 @@ Kirigami.ApplicationWindow {
}
}
function pushPasswordPage() {
/*
* Sanity check that the password request has been resolved already.
* If it is not yet clear which type of password request is needed, then signals should still
* fire once this becomes clear and the request is fully resolved.
*/
if (passwordRequest.previouslyDefined || passwordRequest.firstRun) {
pageStack.push(passwordRequest.previouslyDefined ? unlockAccountsPage : setupPasswordPage);
}
}
/*
* TODO maybe have a onPasswordProvided handler to push a "progress" page to provide visual feedback for devices
* where key derivation is slow?
@ -171,17 +183,22 @@ Kirigami.ApplicationWindow {
pageStack.push(accountsOverviewPage);
}
}
onPreviouslyDefinedChanged: {
onPasswordExists: {
/*
* Ignore if there is an account from the commandline to process: in that case password unlocking/setup is
* Ignore if there is an account from the commandline to process: in that case password unlocking is
* deferred until after account confirmation/rejection by the user
*/
if (!addAccountRequested) {
/*
* Cannot rely on passwordRequestPage property binding having been updated already here, work around
* by repeating the passwordRequestPage property binding expression instead.
*/
pageStack.push(passwordRequest.previouslyDefined ? unlockAccountsPage : setupPasswordPage);
pushPasswordPage();
}
}
onNewPasswordNeeded: {
/*
* Ignore if there is an account from the commandline to process: in that case password setup is deferred
* until after account confirmation/rejection by the user
*/
if (!addAccountRequested) {
pushPasswordPage();
}
}
}
@ -220,6 +237,12 @@ Kirigami.ApplicationWindow {
if (addAccountRequested) {
root.validatedInput.reset();
CommandLine.handleNewAccount(root.validatedInput);
} else {
/*
* In case password request resolves more quickly than the UI, make sure to check if it has been resolved
* yet and prompt for passwords.
*/
pushPasswordPage();
}
}
}

View File

@ -15,13 +15,20 @@ namespace model
QObject(parent), m_secret(secret), m_previous(false), m_haveKey(false), m_havePassword(false)
{
QObject::connect(m_secret, &accounts::AccountSecret::existingPasswordNeeded, this, &PasswordRequest::setPreviouslyDefined);
QObject::connect(m_secret, &accounts::AccountSecret::newPasswordNeeded, this, &PasswordRequest::setNewPasswordNeeded);
QObject::connect(m_secret, &accounts::AccountSecret::passwordAvailable, this, &PasswordRequest::setPasswordAvailable);
QObject::connect(m_secret, &accounts::AccountSecret::keyAvailable, this, &PasswordRequest::setKeyAvailable);
m_previous = secret->isExistingPasswordRequested();
m_firstRun = secret->isNewPasswordRequested();
m_haveKey = secret->isKeyAvailable();
m_havePassword = secret->isPasswordAvailable();
}
bool PasswordRequest::firstRun(void) const
{
return m_firstRun;
}
bool PasswordRequest::previouslyDefined(void) const
{
return m_previous;
@ -109,9 +116,21 @@ namespace model
{
if (!m_previous) {
m_previous = true;
Q_EMIT passwordRequestChanged();
Q_EMIT passwordExists();
} else {
qCDebug(logger) << "Ignored signal: already marked password for existing secrets";
}
}
void PasswordRequest::setNewPasswordNeeded(void)
{
if (!m_firstRun) {
m_firstRun = true;
Q_EMIT passwordRequestChanged();
Q_EMIT newPasswordNeeded();
} else {
qCDebug(logger) << "Ignored signal: already marked password for first run/setup of secrets";
}
}
}

View File

@ -12,11 +12,13 @@ namespace model
class PasswordRequest: public QObject
{
Q_OBJECT
Q_PROPERTY(bool previouslyDefined READ previouslyDefined NOTIFY passwordExists)
Q_PROPERTY(bool firstRun READ firstRun NOTIFY passwordRequestChanged)
Q_PROPERTY(bool previouslyDefined READ previouslyDefined NOTIFY passwordRequestChanged)
Q_PROPERTY(bool keyAvailable READ keyAvailable NOTIFY derivedKey)
Q_PROPERTY(bool passwordProvided READ passwordProvided NOTIFY passwordAccepted)
public:
explicit PasswordRequest(accounts::AccountSecret *secret, QObject *parent = nullptr);
bool firstRun(void) const;
bool previouslyDefined(void) const;
bool keyAvailable(void) const;
bool passwordProvided(void) const;
@ -24,16 +26,20 @@ namespace model
Q_INVOKABLE bool providePassword(QString password);
Q_INVOKABLE bool provideBothPasswords(QString password, QString other);
Q_SIGNALS:
void passwordRequestChanged(void);
void passwordExists(void);
void newPasswordNeeded(void);
void passwordAccepted(void);
void derivedKey(void);
private Q_SLOTS:
void setKeyAvailable(void);
void setPasswordAvailable(void);
void setPreviouslyDefined(void);
void setNewPasswordNeeded(void);
private:
accounts::AccountSecret * m_secret;
private:
bool m_firstRun;
bool m_previous;
bool m_haveKey;
bool m_havePassword;