Skip to content

Commit

Permalink
Allow unlocking and code changes to be performed asynchronously in th…
Browse files Browse the repository at this point in the history
…e backend.

These can take longer than the standard dbus reply timeout when encryption
is enabled.  Allow the commands to return that they are evaluating
immediately so the call can return, and then notify later when they
are complete.
  • Loading branch information
adenexter committed Dec 21, 2016
1 parent c770f01 commit 698ddd9
Show file tree
Hide file tree
Showing 7 changed files with 142 additions and 60 deletions.
5 changes: 2 additions & 3 deletions src/nemo-devicelock/host/cli/clidevicelock.cpp
Expand Up @@ -80,10 +80,9 @@ int CliDeviceLock::setCode(const QString &oldCode, const QString &newCode)
return m_watcher->runPlugin(QStringList() << QStringLiteral("--set-code") << oldCode << newCode);
}

bool CliDeviceLock::unlockWithCode(const QString &code)
int CliDeviceLock::unlockWithCode(const QString &code)
{
return m_watcher->runPlugin(QStringList()
<< QStringLiteral("--unlock") << code) == HostAuthenticationInput::Success;
return m_watcher->runPlugin(QStringList() << QStringLiteral("--unlock") << code);
}

}
2 changes: 1 addition & 1 deletion src/nemo-devicelock/host/cli/clidevicelock.h
Expand Up @@ -53,7 +53,7 @@ class CliDeviceLock : public MceDeviceLock

int checkCode(const QString &code) override;
int setCode(const QString &oldCode, const QString &newCode) override;
bool unlockWithCode(const QString &code) override;
int unlockWithCode(const QString &code) override;

private:
QExplicitlySharedDataPointer<LockCodeWatcher> m_watcher;
Expand Down
3 changes: 2 additions & 1 deletion src/nemo-devicelock/host/hostauthenticationinput.h
Expand Up @@ -69,7 +69,8 @@ class HostAuthenticationInput : public HostObject
Success = 0,
Failure = -1,
SecurityCodeExpired = -2,
SecurityCodeInHistory = -3
SecurityCodeInHistory = -3,
Evaluating = -4
};

enum Availability {
Expand Down
62 changes: 41 additions & 21 deletions src/nemo-devicelock/host/hostauthenticator.cpp
Expand Up @@ -251,32 +251,13 @@ void HostAuthenticator::enterSecurityCode(const QString &code)
return;
}

// With disk encryption enabled changing the code can take a few seconds, don't leave
// the user hanging.
authenticationEvaluating();

const auto currentCode = m_currentCode;
m_currentCode.clear();
m_newCode.clear();

switch (setCode(currentCode, code)) {
case Success:
qCDebug(daemon, "Lock code changed.");
securityCodeChanged(authenticateChallengeCode(m_challengeCode));
return;
case SecurityCodeInHistory:
qCDebug(daemon, "Security code disallowed.");
m_state = EnteringNewSecurityCode;
feedback(AuthenticationInput::SecurityCodeInHistory, -1);
feedback(AuthenticationInput::EnterNewSecurityCode, -1);
return;
default:
qCDebug(daemon, "Lock code change failed.");
setCodeFinished(setCode(currentCode, code));

m_state = ChangeError;
authenticationUnavailable(AuthenticationInput::SoftwareError);
return;
}
return;
}
case AuthenticatingForClear: {
qCDebug(daemon, "Lock code entered for clear authentication.");
Expand Down Expand Up @@ -308,6 +289,40 @@ void HostAuthenticator::enterSecurityCode(const QString &code)
}
}

void HostAuthenticator::setCodeFinished(int result)
{
switch (result) {
case Success:
qCDebug(daemon, "Lock code changed.");
securityCodeChanged(authenticateChallengeCode(m_challengeCode));
break;
case SecurityCodeInHistory:
if (m_state == ChangeCanceled) {
securityCodeChangeAborted();
} else {
qCDebug(daemon, "Security code disallowed.");
m_state = EnteringNewSecurityCode;
feedback(AuthenticationInput::SecurityCodeInHistory, -1);
feedback(AuthenticationInput::EnterNewSecurityCode, -1);
}
break;
case Evaluating:
if (m_state == RepeatingNewSecurityCode) {
m_state = Changing;
authenticationEvaluating();
} else {
abortAuthentication(AuthenticationInput::SoftwareError);
}
break;
default:
qCDebug(daemon, "Lock code change failed.");

m_state = ChangeError;
authenticationUnavailable(AuthenticationInput::SoftwareError);
break;
}
}

void HostAuthenticator::confirmAuthentication()
{
authenticated(authenticateChallengeCode(m_challengeCode));
Expand Down Expand Up @@ -359,6 +374,11 @@ void HostAuthenticator::cancel()
case ChangeError:
securityCodeChangeAborted();
break;
case Changing:
m_state = ChangeCanceled;
break;
case ChangeCanceled:
break;
case AuthenticatingForClear:
case ClearError:
securityCodeClearAborted();
Expand Down
6 changes: 5 additions & 1 deletion src/nemo-devicelock/host/hostauthenticator.h
Expand Up @@ -121,6 +121,8 @@ class HostAuthenticator : public HostAuthenticationInput
void abortAuthentication(AuthenticationInput::Error error) override;
void authenticationEnded(bool confirmed) override;

void setCodeFinished(int result);

// Signals
void authenticated(const QVariant &authenticationToken);
void aborted();
Expand All @@ -142,9 +144,11 @@ class HostAuthenticator : public HostAuthenticationInput
AuthenticatingForChange,
EnteringNewSecurityCode,
RepeatingNewSecurityCode,
Changing,
ChangeError,
ChangeCanceled,
AuthenticatingForClear,
ClearError
ClearError,
};

inline bool isSecurityCodeSet() const;
Expand Down
115 changes: 84 additions & 31 deletions src/nemo-devicelock/host/hostdevicelock.cpp
Expand Up @@ -134,13 +134,7 @@ void HostDeviceLock::enterSecurityCode(const QString &code)
case Authenticating: {
switch (const int result = checkCode(code)) {
case Success:
authenticationEvaluating();

if (unlockWithCode(code)) {
confirmAuthentication();
} else {
abortAuthentication(AuthenticationInput::SoftwareError);
}
unlockFinished(unlockWithCode(code));
break;
case SecurityCodeExpired:
m_state = EnteringNewSecurityCode;
Expand Down Expand Up @@ -174,51 +168,110 @@ void HostDeviceLock::enterSecurityCode(const QString &code)
case RepeatingNewSecurityCode:
if (m_newCode != code) {
m_currentCode.clear();
m_newCode.clear();

m_state = Authenticating;
feedback(AuthenticationInput::SecurityCodesDoNotMatch, -1);
feedback(AuthenticationInput::EnterNewSecurityCode, -1);
} else {
// With disk encryption enabled changing the code can take a few seconds, don't leave
// the user hanging.
authenticationEvaluating();

const auto currentCode = m_currentCode;
m_currentCode.clear();
m_newCode.clear();

switch (setCode(currentCode, code)) {
case Success:
qCDebug(daemon, "Lock code changed.");
if (unlockWithCode(code)) {
confirmAuthentication();
} else {
abortAuthentication(AuthenticationInput::SoftwareError);
}
break;
case SecurityCodeInHistory:
qCDebug(daemon, "Security code disallowed.");
m_state = EnteringNewSecurityCode;
feedback(AuthenticationInput::SecurityCodeInHistory, -1);
feedback(AuthenticationInput::EnterNewSecurityCode, -1);
break;
default:
qCDebug(daemon, "Lock code change failed.");
m_state = AuthenticationError;
authenticationUnavailable(AuthenticationInput::SoftwareError);
break;
}
setCodeFinished(setCode(currentCode, code));
}
break;
case Unlocking:
case ChangingSecurityCode:
case Canceled:
case AuthenticationError:
break;
}
}

void HostDeviceLock::unlockFinished(int result)
{
switch (result) {
case Success:
confirmAuthentication();
break;
case Evaluating:
if (m_state == Authenticating) {
m_state = Unlocking;
authenticationEvaluating();
} else if (m_state == ChangingSecurityCode) {
m_state = Unlocking;
} else {
abortAuthentication(AuthenticationInput::SoftwareError);
}
break;
default:
if (m_state == Canceled) {
m_state = Idle;

authenticationEnded(false);

unlockingChanged();
} else {
abortAuthentication(AuthenticationInput::SoftwareError);
}
break;
}
}

void HostDeviceLock::setCodeFinished(int result)
{
switch (result) {
case Success:
qCDebug(daemon, "Lock code changed.");
if (m_state == ChangingSecurityCode) {
unlockFinished(unlockWithCode(m_newCode));
} else if (m_state == Canceled) {
m_state = Idle;

authenticationEnded(false);

unlockingChanged();
}
break;
case SecurityCodeInHistory:
qCDebug(daemon, "Security code disallowed.");
m_state = EnteringNewSecurityCode;
feedback(AuthenticationInput::SecurityCodeInHistory, -1);
feedback(AuthenticationInput::EnterNewSecurityCode, -1);
break;
case Evaluating:
if (m_state == RepeatingNewSecurityCode) {
m_state = ChangingSecurityCode;
authenticationEvaluating();
} else {
abortAuthentication(AuthenticationInput::SoftwareError);
}
return;
default:
qCDebug(daemon, "Lock code change failed.");
if (m_state == Canceled) {
m_state = Idle;

authenticationEnded(false);

unlockingChanged();
} else {
m_state = AuthenticationError;
authenticationUnavailable(AuthenticationInput::SoftwareError);
}
break;
}
m_newCode.clear();
}

void HostDeviceLock::cancel()
{
if (m_state != Idle) {
if (m_state == Unlocking || m_state == ChangingSecurityCode) {
m_state = Canceled;
} else if (m_state != Idle && m_state != Canceled) {
m_state = Idle;

authenticationEnded(false);
Expand Down
9 changes: 7 additions & 2 deletions src/nemo-devicelock/host/hostdevicelock.h
Expand Up @@ -74,7 +74,6 @@ class HostDeviceLock : public HostAuthenticationInput
explicit HostDeviceLock(Authenticator::Methods supportedMethods, QObject *parent = nullptr);
~HostDeviceLock();

protected:
virtual DeviceLock::LockState state() const = 0;

bool isUnlocking() const;
Expand All @@ -89,7 +88,7 @@ class HostDeviceLock : public HostAuthenticationInput
int checkCode(const QString &code) override = 0;
int setCode(const QString &oldCode, const QString &newCode) override = 0;

virtual bool unlockWithCode(const QString &code) = 0;
virtual int unlockWithCode(const QString &code) = 0;

virtual void setState(DeviceLock::LockState state) = 0;

Expand All @@ -100,14 +99,20 @@ class HostDeviceLock : public HostAuthenticationInput

virtual void automaticLockingChanged();

void unlockFinished(int result);
void setCodeFinished(int result);

private:
friend class HostDeviceLockAdaptor;

enum State {
Idle,
Authenticating,
Unlocking,
EnteringNewSecurityCode,
RepeatingNewSecurityCode,
ChangingSecurityCode,
Canceled,
AuthenticationError
};

Expand Down

0 comments on commit 698ddd9

Please sign in to comment.