Skip to content

Commit

Permalink
Communicate the reason and recoverability of a lock out.
Browse files Browse the repository at this point in the history
  • Loading branch information
adenexter committed Jan 30, 2017
1 parent 6e02089 commit 2e73451
Show file tree
Hide file tree
Showing 15 changed files with 373 additions and 72 deletions.
4 changes: 4 additions & 0 deletions dbus/org.nemomobile.devicelock.client.AuthenticationInput.xml
Expand Up @@ -16,6 +16,10 @@
<arg name="current" type="u" direction="in"/>
<arg name="maximum" type="u" direction="in"/>
</method>
<method name="AuthenticationResumed">
<arg name="utilized_methods" type="u" direction="in"/>
<arg name="instruction" type="u" direction="in"/>
</method>
<method name="Feedback">
<arg name="feedback" type="u" direction="in"/>
<arg name="attempts_remaining" type="u" direction="in"/>
Expand Down
28 changes: 28 additions & 0 deletions src/nemo-devicelock/authenticationinput.cpp
Expand Up @@ -59,6 +59,13 @@ void AuthenticationInputAdaptor::AuthenticationUnavailable(uint pid, uint error)
AuthenticationInput::Error(error));
}

void AuthenticationInputAdaptor::AuthenticationResumed(uint utilizedMethods, uint instruction)
{
m_authenticationInput->handleAuthenticationResumed(
Authenticator::Methods(utilizedMethods),
AuthenticationInput::Feedback(instruction));
}

void AuthenticationInputAdaptor::AuthenticationEvaluating()
{
m_authenticationInput->handleAuthenticationEvaluating();
Expand Down Expand Up @@ -395,6 +402,27 @@ void AuthenticationInput::handleAuthenticationUnavailable(int pid, Error error)
}
}


void AuthenticationInput::handleAuthenticationResumed(
Authenticator::Methods utilizedMethods, Feedback feedback)
{
const auto previousStatus = m_status;
const auto previousMethods = m_utilizedMethods;

m_status = Authenticating;
m_utilizedMethods = utilizedMethods;

if (m_utilizedMethods != previousMethods) {
emit utilizedMethodsChanged();
}

emit AuthenticationInput::feedback(feedback, -1);

if (m_status != previousStatus) {
emit statusChanged();
}
}

/*!
\signal NemoDeviceLock::AuthenticationInput::authenticationEvaluating()
Expand Down
12 changes: 10 additions & 2 deletions src/nemo-devicelock/authenticationinput.h
Expand Up @@ -48,6 +48,7 @@ class AuthenticationInputAdaptor : public QDBusAbstractAdaptor
public slots:
Q_NOREPLY void AuthenticationStarted(uint pid, uint utilizedMethods, uint instruction);
Q_NOREPLY void AuthenticationUnavailable(uint pid, uint error);
Q_NOREPLY void AuthenticationResumed(uint utilizedMethods, uint instruction);
Q_NOREPLY void AuthenticationEvaluating();
Q_NOREPLY void AuthenticationProgress(int current, int maximum);
Q_NOREPLY void AuthenticationEnded(bool confirmed);
Expand Down Expand Up @@ -88,11 +89,17 @@ class NEMODEVICELOCK_EXPORT AuthenticationInput : public QObject, private Connec
SwipeFaster,
SwipeSlower,
UnrecognizedFinger,
IncorrectSecurityCode
IncorrectSecurityCode,
ContactSupport,
TemporarilyLocked,
PermanentlyLocked,
UnlockToPerformOperation
};

enum Error {
LockedOut,
FunctionUnavailable,
LockedByManager,
MaximumAttemptsExceeded,
Canceled,
SoftwareError
};
Expand Down Expand Up @@ -157,6 +164,7 @@ class NEMODEVICELOCK_EXPORT AuthenticationInput : public QObject, private Connec
inline void handleAuthenticationStarted(
int pid, Authenticator::Methods utilizedMethods, Feedback feedback);
inline void handleAuthenticationUnavailable(int pid, Error error);
inline void handleAuthenticationResumed(Authenticator::Methods utilizedMethods, Feedback feedback);
inline void handleAuthenticationEvaluating();
inline void handleAuthenticationEnded(bool confirmed);
inline void handleFeedback(
Expand Down
23 changes: 20 additions & 3 deletions src/nemo-devicelock/devicelock.cpp
Expand Up @@ -64,6 +64,10 @@ DeviceLock::DeviceLock(QObject *parent)
this, &DeviceLock::automaticLockingChanged);
connect(this, &DeviceLock::enabledChanged,
this, &DeviceLock::automaticLockingChanged);
connect(m_settings.data(), &SettingsWatcher::showNotificationsChanged,
this, &DeviceLock::showNotificationsChanged);
connect(this, &DeviceLock::stateChanged,
this, &DeviceLock::showNotificationsChanged);

m_connection->onConnected(this, [this] {
connected();
Expand Down Expand Up @@ -103,6 +107,17 @@ int DeviceLock::automaticLocking() const
return isEnabled() ? m_settings->automaticLocking : -1;
}

/*!
\property NemoDeviceLock::DeviceLock::showNotifications
This property holds whether the notifications should be shown over the lockscreen.
*/

bool DeviceLock::showNotifications() const
{
return m_state <= Locked && m_settings->showNotifications;
}

/*!
\property NemoDeviceLock::DeviceLock::enabled
Expand Down Expand Up @@ -143,7 +158,7 @@ DeviceLock::LockState DeviceLock::state() const

void DeviceLock::unlock()
{
if (!m_unlocking && m_state == Locked) {
if (!m_unlocking && m_state >= Locked && m_state < Undefined) {
m_unlocking = true;

const auto response = call(QStringLiteral("Unlock"));
Expand Down Expand Up @@ -207,13 +222,15 @@ void DeviceLock::connected()
});
subscribeToProperty<uint>(QStringLiteral("State"), [this](uint state) {
if (m_state != state) {
bool wasLocked = m_state >= Locked;

m_state = LockState(state);

emit stateChanged();

if (m_state == Locked) {
if (!wasLocked && m_state >= Locked && m_state < Undefined) {
emit locked();
} else if (m_state == Unlocked) {
} else if (wasLocked && m_state == Unlocked) {
emit unlocked();
}
}
Expand Down
6 changes: 6 additions & 0 deletions src/nemo-devicelock/devicelock.h
Expand Up @@ -33,6 +33,7 @@ class NEMODEVICELOCK_EXPORT DeviceLock : public QObject, private ConnectionClien
Q_PROPERTY(bool unlocking READ isUnlocking NOTIFY unlockingChanged)
Q_PROPERTY(LockState state READ state NOTIFY stateChanged)
Q_PROPERTY(int automaticLocking READ automaticLocking NOTIFY automaticLockingChanged)
Q_PROPERTY(bool showNotifications READ showNotifications NOTIFY showNotificationsChanged)
public:
explicit DeviceLock(QObject *parent = nullptr);
~DeviceLock();
Expand All @@ -41,6 +42,9 @@ class NEMODEVICELOCK_EXPORT DeviceLock : public QObject, private ConnectionClien
{
Unlocked = 0, /*!< Unlocked - The lock is unlocked */
Locked, /*!< Locked - The lock is being used */
ManagerLockout, /*!< ManagerLockout - Access has been restricted by a device manager. */
TemporaryLockout, /*!< TemporaryLockout - Access has been temporarily restricted because of excessive incorrect unlock attempts. */
PermanentLockout, /*!< PermanentLockout - Access has been permanently restricted because of excessive incorrect unlock attempts. */
Undefined /*!< Undefined - The state of the lock is unknown */
};

Expand All @@ -49,6 +53,7 @@ class NEMODEVICELOCK_EXPORT DeviceLock : public QObject, private ConnectionClien
LockState state() const;

int automaticLocking() const;
bool showNotifications() const;

Q_INVOKABLE void unlock();
Q_INVOKABLE void cancel();
Expand All @@ -58,6 +63,7 @@ class NEMODEVICELOCK_EXPORT DeviceLock : public QObject, private ConnectionClien
void unlockingChanged();
void stateChanged();
void automaticLockingChanged();
void showNotificationsChanged();

void locked();
void unlocked();
Expand Down
2 changes: 1 addition & 1 deletion src/nemo-devicelock/devicelocksettings.h
Expand Up @@ -51,7 +51,7 @@ class NEMODEVICELOCK_EXPORT DeviceLockSettings : public QObject, private Connec
Q_PROPERTY(int showNotifications READ showNotifications NOTIFY showNotificationsChanged)
Q_PROPERTY(bool inputIsKeyboard READ inputIsKeyboard NOTIFY inputIsKeyboardChanged)
Q_PROPERTY(bool currentCodeIsDigitOnly READ currentCodeIsDigitOnly NOTIFY currentCodeIsDigitOnlyChanged)
Q_PROPERTY(bool isHomeEncrypted READ isHomeEncrypted CONSTANT)
Q_PROPERTY(bool homeEncrypted READ isHomeEncrypted CONSTANT)
public:
explicit DeviceLockSettings(QObject *parent = nullptr);
~DeviceLockSettings();
Expand Down
2 changes: 1 addition & 1 deletion src/nemo-devicelock/host/cli/cliauthenticator.cpp
Expand Up @@ -72,7 +72,7 @@ HostAuthenticationInput::Availability CliAuthenticator::availability() const
const int attempts = currentAttempts();

if (maximum > 0 && attempts >= maximum) {
return AuthenticationLocked;
return PermanentlyLocked;
} else {
return CanAuthenticate;
}
Expand Down
2 changes: 1 addition & 1 deletion src/nemo-devicelock/host/cli/clidevicelock.cpp
Expand Up @@ -61,7 +61,7 @@ HostAuthenticationInput::Availability CliDeviceLock::availability() const
const int attempts = currentAttempts();

if (maximum > 0 && attempts >= maximum) {
return AuthenticationLocked;
return PermanentlyLocked;
} else {
return CanAuthenticate;
}
Expand Down
48 changes: 47 additions & 1 deletion src/nemo-devicelock/host/hostauthenticationinput.cpp
Expand Up @@ -98,7 +98,7 @@ void HostAuthenticationInput::authenticationStarted(
clientInterface,
QStringLiteral("AuthenticationStarted"),
pid,
uint(methods),
uint(m_activeMethods),
uint(feedback));
}
}
Expand All @@ -120,6 +120,29 @@ void HostAuthenticationInput::authenticationUnavailable(AuthenticationInput::Err
}
}


void HostAuthenticationInput::authenticationResumed(
AuthenticationInput::Feedback feedback, Authenticator::Methods utilizedMethods)
{
qCDebug(daemon, "Authentication resumed");

if (!m_inputStack.isEmpty()) {
if (utilizedMethods != 0) { // Utilized methods can be empty if there is no change.
utilizedMethods = m_activeMethods;
}
m_activeMethods = utilizedMethods & m_supportedMethods;

m_authenticating = true;
NemoDBus::send(
m_inputStack.last().connection,
m_inputStack.last().path,
clientInterface,
QStringLiteral("AuthenticationResumed"),
uint(m_activeMethods),
uint(feedback));
}
}

void HostAuthenticationInput::authenticationEvaluating()
{
if (m_authenticating && !m_inputStack.isEmpty()) {
Expand Down Expand Up @@ -269,6 +292,29 @@ void HostAuthenticationInput::feedback(
}
}

void HostAuthenticationInput::lockedOut()
{
switch (availability()) {
case ManagerLocked:
abortAuthentication(AuthenticationInput::LockedByManager);
feedback(AuthenticationInput::ContactSupport, -1);
break;
case TemporarilyLocked:
abortAuthentication(AuthenticationInput::MaximumAttemptsExceeded);
feedback(AuthenticationInput::TemporarilyLocked, -1);
break;
case PermanentlyLocked:
abortAuthentication(AuthenticationInput::MaximumAttemptsExceeded);
feedback(AuthenticationInput::PermanentlyLocked, -1);
break;
default:
// Locked out but availability doesn't reflect this. This shouldn't be reachable
// under normal circumstances.
abortAuthentication(AuthenticationInput::SoftwareError);
}
}


void HostAuthenticationInput::abortAuthentication(AuthenticationInput::Error error)
{
if (m_authenticating) {
Expand Down
11 changes: 10 additions & 1 deletion src/nemo-devicelock/host/hostauthenticationinput.h
Expand Up @@ -78,7 +78,10 @@ class HostAuthenticationInput : public HostObject
AuthenticationNotRequired,
CanAuthenticate,
CanAuthenticateSecurityCode,
AuthenticationLocked
SecurityCodeRequired,
ManagerLocked,
TemporarilyLocked,
PermanentlyLocked
};

explicit HostAuthenticationInput(
Expand All @@ -105,6 +108,9 @@ class HostAuthenticationInput : public HostObject
Authenticator::Methods methods,
AuthenticationInput::Feedback feedback = AuthenticationInput::EnterSecurityCode);
void authenticationUnavailable(AuthenticationInput::Error error);
void authenticationResumed(
AuthenticationInput::Feedback feedback,
Authenticator::Methods utilizedMethods = Authenticator::Methods());
void authenticationEvaluating();
void authenticationProgress(int current, int maximum);
virtual void authenticationEnded(bool confirmed);
Expand All @@ -124,6 +130,9 @@ class HostAuthenticationInput : public HostObject
// Housekeeping
void clientDisconnected(const QString &connectionName) override;

protected:
void lockedOut();

private:
friend class HostAuthenticationInputAdaptor;

Expand Down
40 changes: 30 additions & 10 deletions src/nemo-devicelock/host/hostauthenticator.cpp
Expand Up @@ -136,9 +136,24 @@ void HostAuthenticator::authenticate(
qCDebug(daemon, "Authentication requested using methods %i.", int(methods));
authenticationStarted(methods, AuthenticationInput::EnterSecurityCode);
break;
case AuthenticationLocked:
case SecurityCodeRequired:
m_challengeCode.clear();
authenticationUnavailable(AuthenticationInput::LockedOut);
authenticationUnavailable(AuthenticationInput::FunctionUnavailable);
break;
case ManagerLocked:
m_challengeCode.clear();
authenticationUnavailable(AuthenticationInput::LockedByManager);
feedback(AuthenticationInput::ContactSupport, -1);
break;
case TemporarilyLocked:
m_challengeCode.clear();
authenticationUnavailable(AuthenticationInput::MaximumAttemptsExceeded);
feedback(AuthenticationInput::TemporarilyLocked, -1);
break;
case PermanentlyLocked:
m_challengeCode.clear();
authenticationUnavailable(AuthenticationInput::MaximumAttemptsExceeded);
feedback(AuthenticationInput::PermanentlyLocked, -1);
break;
}
}
Expand Down Expand Up @@ -166,12 +181,14 @@ void HostAuthenticator::handleChangeSecurityCode(const QString &client, const QV
case CanAuthenticate:
authenticationStarted(Authenticator::SecurityCode, AuthenticationInput::EnterSecurityCode);
break;
case AuthenticationLocked:
case SecurityCodeRequired:
case ManagerLocked:
case TemporarilyLocked:
case PermanentlyLocked:
m_challengeCode.clear();
authenticationUnavailable(AuthenticationInput::LockedOut);
authenticationUnavailable(AuthenticationInput::FunctionUnavailable);
break;
}

}

void HostAuthenticator::handleClearSecurityCode(const QString &client)
Expand All @@ -196,8 +213,11 @@ void HostAuthenticator::handleClearSecurityCode(const QString &client)
case CanAuthenticate:
authenticationStarted(Authenticator::SecurityCode, AuthenticationInput::EnterSecurityCode);
break;
case AuthenticationLocked:
authenticationUnavailable(AuthenticationInput::LockedOut);
case SecurityCodeRequired:
case ManagerLocked:
case TemporarilyLocked:
case PermanentlyLocked:
authenticationUnavailable(AuthenticationInput::FunctionUnavailable);
break;
}
}
Expand All @@ -217,7 +237,7 @@ void HostAuthenticator::enterSecurityCode(const QString &code)
confirmAuthentication();
return;
case LockedOut:
abortAuthentication(AuthenticationInput::LockedOut);
lockedOut();
return;
}
break;
Expand All @@ -231,7 +251,7 @@ void HostAuthenticator::enterSecurityCode(const QString &code)
feedback(AuthenticationInput::EnterNewSecurityCode, -1);
return;
case LockedOut:
abortAuthentication(AuthenticationInput::LockedOut);
lockedOut();
return;
}
break;
Expand Down Expand Up @@ -288,7 +308,7 @@ void HostAuthenticator::enterSecurityCode(const QString &code)
feedback(AuthenticationInput::IncorrectSecurityCode, qMax(0, maximum - attempts));

if (attempts >= maximum) {
abortAuthentication(AuthenticationInput::LockedOut);
lockedOut();
return;
}
} else {
Expand Down

0 comments on commit 2e73451

Please sign in to comment.