diff --git a/dbus/org.nemomobile.devicelock.AuthenticationInput.xml b/dbus/org.nemomobile.devicelock.AuthenticationInput.xml index db58394..0f0d227 100644 --- a/dbus/org.nemomobile.devicelock.AuthenticationInput.xml +++ b/dbus/org.nemomobile.devicelock.AuthenticationInput.xml @@ -14,6 +14,9 @@ + + + diff --git a/dbus/org.nemomobile.devicelock.DeviceLock.xml b/dbus/org.nemomobile.devicelock.DeviceLock.xml index 2f449b8..15ba7bf 100644 --- a/dbus/org.nemomobile.devicelock.DeviceLock.xml +++ b/dbus/org.nemomobile.devicelock.DeviceLock.xml @@ -7,5 +7,9 @@ + + + + diff --git a/dbus/org.nemomobile.devicelock.client.AuthenticationInput.xml b/dbus/org.nemomobile.devicelock.client.AuthenticationInput.xml index af159a9..b04788f 100644 --- a/dbus/org.nemomobile.devicelock.client.AuthenticationInput.xml +++ b/dbus/org.nemomobile.devicelock.client.AuthenticationInput.xml @@ -22,7 +22,7 @@ - + diff --git a/src/nemo-devicelock/authenticationinput.cpp b/src/nemo-devicelock/authenticationinput.cpp index a3a2b46..0aa8807 100644 --- a/src/nemo-devicelock/authenticationinput.cpp +++ b/src/nemo-devicelock/authenticationinput.cpp @@ -44,12 +44,14 @@ AuthenticationInputAdaptor::AuthenticationInputAdaptor(AuthenticationInput *auth { } -void AuthenticationInputAdaptor::AuthenticationStarted(uint pid, uint utilizedMethods, uint instruction) +void AuthenticationInputAdaptor::AuthenticationStarted( + uint pid, uint utilizedMethods, uint instruction, const QVariantMap &data) { m_authenticationInput->handleAuthenticationStarted( pid, Authenticator::Methods(utilizedMethods), - AuthenticationInput::Feedback(instruction)); + AuthenticationInput::Feedback(instruction), + data); } void AuthenticationInputAdaptor::AuthenticationUnavailable(uint pid, uint error) @@ -59,11 +61,13 @@ void AuthenticationInputAdaptor::AuthenticationUnavailable(uint pid, uint error) AuthenticationInput::Error(error)); } -void AuthenticationInputAdaptor::AuthenticationResumed(uint utilizedMethods, uint instruction) +void AuthenticationInputAdaptor::AuthenticationResumed( + uint utilizedMethods, uint instruction, const QVariantMap &data) { m_authenticationInput->handleAuthenticationResumed( Authenticator::Methods(utilizedMethods), - AuthenticationInput::Feedback(instruction)); + AuthenticationInput::Feedback(instruction), + data); } void AuthenticationInputAdaptor::AuthenticationEvaluating() @@ -81,11 +85,11 @@ void AuthenticationInputAdaptor::AuthenticationEnded(bool confirmed) m_authenticationInput->handleAuthenticationEnded(confirmed); } -void AuthenticationInputAdaptor::Feedback(uint feedback, uint attemptsRemaining, uint utilizedMethods) +void AuthenticationInputAdaptor::Feedback(uint feedback, const QVariantMap &data, uint utilizedMethods) { m_authenticationInput->handleFeedback( AuthenticationInput::Feedback(feedback), - attemptsRemaining, + data, Authenticator::Methods(utilizedMethods)); } @@ -115,6 +119,92 @@ void AuthenticationInputAdaptor::Error(uint error) as fingerprint scanning should now also accept input. */ +/*! + \enum AuthenticationInput::Feedback + + Message codes for primary feedback during authentication or supplementary feedback following + a primary message or error. + + \value EnterSecurityCode Instruct the user to enter their current security code. + \value EnterNewSecurityCode Instruct the user to enter a new security code. + \value RepeatNewSecurityCode Instruct the user to repeat the new security code. + \value SuggestSecurityCode Suggest a new security code the user should use. The code is + provided as the \c securityCode member of the feedback data. + \value SecurityCodesDoNotMatch Inform the user the user that they entered a different code when + repeating their new security code. + \value SecurityCodeInHistory Inform the user that the code they entered has already been used. + \value SecurityCodeExpired Inform the user that their current code has expired. + \value SecurityCodeDueToExpire Inform the user that their current code is due to expire. The + expiration date is provided as the \c expirationDate member of the feedback data. + \value PartialPrint Inform the user that the fingerprint reader wasn't able to capture a full + print. + \value PrintIsUnclear Inform the user that fingerprint reader wasn't able to capture a clear + print. + \value SensorIsDirty Inform the user that the fingerprint reader sensor is dirty. + \value SwipeFaster Ask the user to user a faster motion when swiping the fingerprint reader. + \value SwipeSlower Ask the user to user a slower motion when swiping the fingerprint reader. + \value UnrecognizedFinger Inform the user that the scanned fingerprint did not match any + authorized print. The number of times the user may attempt another finger is passed as the + \c attemptsRemaining member of the feedback data. + \value IncorrectSecurityCode Inform the user that the entered security code is incorrect. The + number of times the user may attempt to enter another cod is passed as the \c attemptsRemaining + member of the feedback data. + \value ContactSupport Inform the user to contact support for help with the preceding error. + \value TemporarilyLocked Inform the user that the device has been temporarily locked. + \value PermanentlyLocked Inform the user that the device has been permanently locked. + \value UnlockToPerformOperation. Inform the user they must unlock the device before they are + able to continue. +*/ + +/*! + \enum AuthenticationInput::Error + + Message codes for feedback when authentication cannot continue. + + \value FunctionUnavailable Authentication could not be performed at this time. + \value LockedByManager The device manager has locked down the device and it cannot be unlocked + by the user. + \value MaximumAttemptsExceeded Too many incorrect security codes have been tried and no more + will be accepted. + \value Canceled Authentication was canceled. + \value SoftwareError The device lock has entered an unexpected state and cannot provide + authentication. +*/ + +/*! + \enum AuthenticationInput::Type + + The type of input. + + \value Authentication Provides authentication for changing settings. + \value DeviceLock Provides authentication for unlocking the device. +*/ + +/*! + \enum AuthenticationInput::Status + + The status of the authentication input. + + \value Idle Nothing is currently trying to authenticate. + \value Authenticating Authentication input is currently being accepted. + \value Evaluating Authentication is active but not currently accepting input. This may be + because a time consuming action is taking place post confirmation, or a forced delay between + code entry attempts is being enforced. + \value AuthenticationError Authentication is not being accepted following an error. +*/ + +/*! + \enum AuthenticationInput::CodeGeneration + + The level of support for code generation. + + \value NoCodeGeneration Code generation is supported. + \value OptionalCodeGeneration Code generation is available as an alternative to the user + choosing their own security code. + \value MandatoryCodeGeneration The user is required to use a generated code instead of picking + their own. +*/ + /*! Constructs an authentication input which handles requests of a given \a type as a child of \a parent. @@ -139,6 +229,8 @@ AuthenticationInput::AuthenticationInput(Type type, QObject *parent) this, &AuthenticationInput::maximumAttemptsChanged); connect(m_settings.data(), &SettingsWatcher::inputIsKeyboardChanged, this, &AuthenticationInput::codeInputIsKeyboardChanged); + connect(m_settings.data(), &SettingsWatcher::codeGenerationChanged, + this, &AuthenticationInput::codeGenerationChanged); m_connection->onConnected(this, [this] { connected(); @@ -207,6 +299,17 @@ int AuthenticationInput::maximumAttempts() const return m_settings->maximumAttempts; } +/*! + \property NemoDeviceLock::AuthenticationInput::codeGeneration + + This property holds the level of support for generated security codes. +*/ +AuthenticationInput::CodeGeneration AuthenticationInput::codeGeneration() const +{ + return m_settings->codeGeneration; +} + + /*! \property NemoDeviceLock::AuthenticationInput::codeInputIsKeyboard @@ -322,6 +425,15 @@ void AuthenticationInput::enterSecurityCode(const QString &code) call(QStringLiteral("EnterSecurityCode"), m_localPath, code); } +/*! + Sends a request for the security daemon to suggest a new security code. +*/ + +void AuthenticationInput::requestSecurityCode() +{ + call(QStringLiteral("RequestSecurityCode"), m_localPath); +} + /*! Sends a request to cancel authentication to the security daemon. */ @@ -336,14 +448,15 @@ void AuthenticationInput::cancel() } /*! - \signal NemoDeviceLock::AuthenticationInput::authenticationStarted(Feedback feedback) + \signal NemoDeviceLock::AuthenticationInput::authenticationStarted(Feedback feedback, object data) Signals that an application has requested authentication and that the input should be displayed - with the given initial \a feedback message. + with the given initial \a feedback message. Arguments associated with the feedback message + are passed through the \a data object. */ void AuthenticationInput::handleAuthenticationStarted( - int pid, Authenticator::Methods utilizedMethods, Feedback feedback) + int pid, Authenticator::Methods utilizedMethods, Feedback feedback, const QVariantMap &data) { qCDebug(devicelock, "Authentication started. Methods: %i, Feedback: %i.", int(utilizedMethods), int(feedback)); @@ -368,7 +481,7 @@ void AuthenticationInput::handleAuthenticationStarted( emit utilizedMethodsChanged(); } - emit authenticationStarted(feedback); + emit authenticationStarted(feedback, data); if (m_status != previousStatus) { emit statusChanged(); @@ -411,7 +524,7 @@ void AuthenticationInput::handleAuthenticationUnavailable(int pid, Error error) void AuthenticationInput::handleAuthenticationResumed( - Authenticator::Methods utilizedMethods, Feedback feedback) + Authenticator::Methods utilizedMethods, Feedback feedback, const QVariantMap &data) { const auto previousStatus = m_status; const auto previousMethods = m_utilizedMethods; @@ -423,7 +536,7 @@ void AuthenticationInput::handleAuthenticationResumed( emit utilizedMethodsChanged(); } - emit AuthenticationInput::feedback(feedback, -1); + emit AuthenticationInput::feedback(feedback, data); if (m_status != previousStatus) { emit statusChanged(); @@ -469,24 +582,25 @@ void AuthenticationInput::handleAuthenticationEnded(bool confirmed) } /*! - \signal NemoDeviceLock::AuthenticationInput::feedback(Feedback feedback, int attemptsRemaining) + \signal NemoDeviceLock::AuthenticationInput::feedback(Feedback feedback, object data) - Signals that a \a feedback message should be shown to the user incorporating - \a attemptsRemaining if it is not equal to -1. + Signals that a \a feedback message should be shown to the user. Some feedback will also + include \a data that should be incorporated into the message, the members of data + accompanying a feedback message will be described in the documentation for that feedback. */ void AuthenticationInput::handleFeedback( - Feedback feedback, int attemptsRemaining, Authenticator::Methods utilizedMethods) + Feedback feedback, const QVariantMap &data, Authenticator::Methods utilizedMethods) { if (m_status != Idle) { - qCDebug(devicelock, "Authentication feedback %i. Attempts remaining: %i. Methods: %i", - int(feedback), attemptsRemaining, int(utilizedMethods)); + qCDebug(devicelock, "Authentication feedback %i. Methods: %i", + int(feedback), int(utilizedMethods)); const bool methodsChanged = m_utilizedMethods != utilizedMethods; m_utilizedMethods = utilizedMethods; - emit AuthenticationInput::feedback(feedback, attemptsRemaining); + emit AuthenticationInput::feedback(feedback, data); if (methodsChanged) { emit utilizedMethodsChanged(); diff --git a/src/nemo-devicelock/authenticationinput.h b/src/nemo-devicelock/authenticationinput.h index 476d4d4..43461e6 100644 --- a/src/nemo-devicelock/authenticationinput.h +++ b/src/nemo-devicelock/authenticationinput.h @@ -34,6 +34,7 @@ #define NEMODEVICELOCK_AUTHENTICATIONINPUT_H #include +#include namespace NemoDeviceLock { @@ -46,13 +47,13 @@ class AuthenticationInputAdaptor : public QDBusAbstractAdaptor explicit AuthenticationInputAdaptor(AuthenticationInput *authenticationInput); public slots: - Q_NOREPLY void AuthenticationStarted(uint pid, uint utilizedMethods, uint instruction); + Q_NOREPLY void AuthenticationStarted(uint pid, uint utilizedMethods, uint instruction, const QVariantMap &data); Q_NOREPLY void AuthenticationUnavailable(uint pid, uint error); - Q_NOREPLY void AuthenticationResumed(uint utilizedMethods, uint instruction); + Q_NOREPLY void AuthenticationResumed(uint utilizedMethods, uint instruction, const QVariantMap &data); Q_NOREPLY void AuthenticationEvaluating(); Q_NOREPLY void AuthenticationProgress(int current, int maximum); Q_NOREPLY void AuthenticationEnded(bool confirmed); - Q_NOREPLY void Feedback(uint feedback, uint attemptsRemaining, uint utilizedMethods); + Q_NOREPLY void Feedback(uint feedback, const QVariantMap &data, uint utilizedMethods); Q_NOREPLY void Error(uint error); private: @@ -72,17 +73,17 @@ class NEMODEVICELOCK_EXPORT AuthenticationInput : public QObject, private Connec Q_PROPERTY(int maximumCodeLength READ maximumCodeLength CONSTANT) Q_PROPERTY(int maximumAttempts READ maximumAttempts NOTIFY maximumAttemptsChanged) Q_PROPERTY(bool codeInputIsKeyboard READ codeInputIsKeyboard NOTIFY codeInputIsKeyboardChanged) - Q_ENUMS(Feedback) - Q_ENUMS(Error) - Q_ENUMS(Status) + Q_PROPERTY(CodeGeneration codeGeneration READ codeGeneration NOTIFY codeGenerationChanged) public: enum Feedback { EnterSecurityCode, EnterNewSecurityCode, RepeatNewSecurityCode, + SuggestSecurityCode, SecurityCodesDoNotMatch, SecurityCodeInHistory, SecurityCodeExpired, + SecurityCodeDueToExpire, PartialPrint, PrintIsUnclear, SensorIsDirty, @@ -95,6 +96,7 @@ class NEMODEVICELOCK_EXPORT AuthenticationInput : public QObject, private Connec PermanentlyLocked, UnlockToPerformOperation }; + Q_ENUM(Feedback) enum Error { FunctionUnavailable, @@ -103,6 +105,7 @@ class NEMODEVICELOCK_EXPORT AuthenticationInput : public QObject, private Connec Canceled, SoftwareError }; + Q_ENUM(Error) enum Type { Authentication, @@ -115,6 +118,14 @@ class NEMODEVICELOCK_EXPORT AuthenticationInput : public QObject, private Connec Evaluating, AuthenticationError }; + Q_ENUM(Status) + + enum CodeGeneration { + NoCodeGeneration, + OptionalCodeGeneration, + MandatoryCodeGeneration + }; + Q_ENUM(CodeGeneration) explicit AuthenticationInput(Type type = Authentication, QObject *parent = nullptr); ~AuthenticationInput(); @@ -131,11 +142,14 @@ class NEMODEVICELOCK_EXPORT AuthenticationInput : public QObject, private Connec int maximumAttempts() const; + CodeGeneration codeGeneration() const; + int minimumCodeLength() const; int maximumCodeLength() const; bool codeInputIsKeyboard() const; Q_INVOKABLE void enterSecurityCode(const QString &code); + Q_INVOKABLE void requestSecurityCode(); Q_INVOKABLE void cancel(); signals: @@ -145,15 +159,18 @@ class NEMODEVICELOCK_EXPORT AuthenticationInput : public QObject, private Connec void authenticatingPidChanged(); void utilizedMethodsChanged(); void maximumAttemptsChanged(); + void temporaryLockoutDurationChanged(); + void temporaryLockoutExpirationChanged(); + void codeGenerationChanged(); void codeInputIsKeyboardChanged(); - void authenticationStarted(Feedback feedback); + void authenticationStarted(Feedback feedback, const QVariant &data); void authenticationUnavailable(Error error); void authenticationEvaluating(); void authenticationProgress(int current, int maximum); void authenticationEnded(bool confirmed); - void feedback(Feedback feedback, int attemptsRemaining); + void feedback(Feedback feedback, const QVariantMap &data); void error(Error error); private: @@ -162,13 +179,17 @@ class NEMODEVICELOCK_EXPORT AuthenticationInput : public QObject, private Connec inline void connected(); inline void handleAuthenticationStarted( - int pid, Authenticator::Methods utilizedMethods, Feedback feedback); + int pid, + Authenticator::Methods utilizedMethods, + Feedback feedback, + const QVariantMap &data); inline void handleAuthenticationUnavailable(int pid, Error error); - inline void handleAuthenticationResumed(Authenticator::Methods utilizedMethods, Feedback feedback); + inline void handleAuthenticationResumed( + Authenticator::Methods utilizedMethods, Feedback feedback, const QVariantMap &data); inline void handleAuthenticationEvaluating(); inline void handleAuthenticationEnded(bool confirmed); inline void handleFeedback( - Feedback feedback, int attemptsRemaining, Authenticator::Methods utilizedMethods); + Feedback feedback, const QVariantMap &data, Authenticator::Methods utilizedMethods); inline void handleError(Error error); AuthenticationInputAdaptor m_adaptor; diff --git a/src/nemo-devicelock/devicelock.cpp b/src/nemo-devicelock/devicelock.cpp index b721257..d63fc60 100644 --- a/src/nemo-devicelock/devicelock.cpp +++ b/src/nemo-devicelock/devicelock.cpp @@ -47,6 +47,17 @@ namespace NemoDeviceLock AuthenticationInput provider. */ +/*! + \enum NemoDeviceLock::DeviceLock::Notice + + Broadcast notifications decribing events of importance. + + \value SecurityCodeDueToExpire The user's security code is due to due to expire in the near + future. The expiration date is provided as an ISO 8601 formatted string in the + \c expirationDate member of the notice data. + \value SecurityCodeChanged The user's security code has been changed. +*/ + /*! Constructs a device lock interface instance which is a child of \a parent. */ @@ -217,10 +228,25 @@ void DeviceLock::cancel() Signals that there was an error requesting authentication to unlock the device. */ + +/*! + \signal NemoDeviceLock::DeviceLock::notice(Notice notice, const QVariantMap &map) + + Emits a broadcast \a notice from the device lock. Some noteices will also + include \a data that should be incorporated into the message, the members of data + accompanying a notice will be described in the documentation for that notice. +*/ +void DeviceLock::handleNotice(uint notice, const QVariantMap &data) +{ + emit DeviceLock::notice(DeviceLock::Notice(notice), data); +} + void DeviceLock::connected() { registerObject(); + connectToSignal(QStringLiteral("Notice"), SLOT(handleNotice(uint,QVariantMap))); + subscribeToProperty(QStringLiteral("Enabled"), [this](bool enabled) { if (m_enabled != enabled) { m_enabled = enabled; diff --git a/src/nemo-devicelock/devicelock.h b/src/nemo-devicelock/devicelock.h index a891eff..e73b12b 100644 --- a/src/nemo-devicelock/devicelock.h +++ b/src/nemo-devicelock/devicelock.h @@ -28,7 +28,6 @@ class SettingsWatcher; class NEMODEVICELOCK_EXPORT DeviceLock : public QObject, private ConnectionClient { Q_OBJECT - Q_ENUMS(LockState) Q_PROPERTY(bool enabled READ isEnabled NOTIFY enabledChanged) Q_PROPERTY(bool unlocking READ isUnlocking NOTIFY unlockingChanged) Q_PROPERTY(LockState state READ state NOTIFY stateChanged) @@ -43,10 +42,17 @@ 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. */ + CodeEntryLockout, /*!< CodeEntryLockout - Access has been restricted because of excessive incorrect unlock attempts. */ Undefined /*!< Undefined - The state of the lock is unknown */ }; + Q_ENUM(LockState) + + enum Notice + { + SecurityCodeDueToExpire, + SecurityCodeChanged + }; + Q_ENUM(Notice) bool isEnabled() const; bool isUnlocking() const; @@ -69,6 +75,11 @@ class NEMODEVICELOCK_EXPORT DeviceLock : public QObject, private ConnectionClien void unlocked(); void unlockError(); + void notice(Notice notice, const QVariantMap &data); + +private slots: + void handleNotice(uint notice, const QVariantMap &data); + private: inline void connected(); diff --git a/src/nemo-devicelock/host/cli/cliauthenticator.cpp b/src/nemo-devicelock/host/cli/cliauthenticator.cpp index b2094ad..b81449b 100644 --- a/src/nemo-devicelock/host/cli/cliauthenticator.cpp +++ b/src/nemo-devicelock/host/cli/cliauthenticator.cpp @@ -72,7 +72,7 @@ HostAuthenticationInput::Availability CliAuthenticator::availability() const const int attempts = currentAttempts(); if (maximum > 0 && attempts >= maximum) { - return PermanentlyLocked; + return CodeEntryLockedPermanent; } else { return CanAuthenticate; } diff --git a/src/nemo-devicelock/host/cli/clidevicelock.cpp b/src/nemo-devicelock/host/cli/clidevicelock.cpp index d1a3b89..85d5f3e 100644 --- a/src/nemo-devicelock/host/cli/clidevicelock.cpp +++ b/src/nemo-devicelock/host/cli/clidevicelock.cpp @@ -61,7 +61,7 @@ HostAuthenticationInput::Availability CliDeviceLock::availability() const const int attempts = currentAttempts(); if (maximum > 0 && attempts >= maximum) { - return PermanentlyLocked; + return CodeEntryLockedPermanent; } else { return CanAuthenticate; } diff --git a/src/nemo-devicelock/host/hostauthenticationinput.cpp b/src/nemo-devicelock/host/hostauthenticationinput.cpp index 66fc79d..9c00b39 100644 --- a/src/nemo-devicelock/host/hostauthenticationinput.cpp +++ b/src/nemo-devicelock/host/hostauthenticationinput.cpp @@ -34,6 +34,8 @@ #include "settingswatcher.h" +#include + namespace NemoDeviceLock { @@ -61,6 +63,11 @@ void HostAuthenticationInputAdaptor::EnterSecurityCode(const QDBusObjectPath &pa m_authenticationInput->handleEnterSecurityCode(path.path(), code); } +void HostAuthenticationInputAdaptor::RequestSecurityCode(const QDBusObjectPath &path) +{ + m_authenticationInput->handleRequestSecurityCode(path.path()); +} + void HostAuthenticationInputAdaptor::Cancel(const QDBusObjectPath &path) { m_authenticationInput->handleCancel(path.path()); @@ -83,15 +90,27 @@ HostAuthenticationInput::~HostAuthenticationInput() void HostAuthenticationInput::authenticationStarted( Authenticator::Methods methods, - AuthenticationInput::Feedback feedback) + AuthenticationInput::Feedback) +{ + qCDebug(daemon, "Authentication started"); + + m_authenticating = true; + m_activeMethods = methods & m_supportedMethods; +} + + +void HostAuthenticationInput::startAuthentication( + AuthenticationInput::Feedback feedback, + const QVariantMap &data, + Authenticator::Methods methods) { qCDebug(daemon, "Authentication started"); const uint pid = connectionPid(QDBusContext::connection()); if (pid != 0 && !m_inputStack.isEmpty()) { - m_authenticating = true; - m_activeMethods = methods & m_supportedMethods; + authenticationStarted(methods, feedback); + NemoDBus::send( m_inputStack.last().connection, m_inputStack.last().path, @@ -99,10 +118,12 @@ void HostAuthenticationInput::authenticationStarted( QStringLiteral("AuthenticationStarted"), pid, uint(m_activeMethods), - uint(feedback)); + uint(feedback), + data); } } + void HostAuthenticationInput::authenticationUnavailable(AuthenticationInput::Error error) { qCDebug(daemon, "Authentication unavailable"); @@ -122,7 +143,9 @@ void HostAuthenticationInput::authenticationUnavailable(AuthenticationInput::Err void HostAuthenticationInput::authenticationResumed( - AuthenticationInput::Feedback feedback, Authenticator::Methods utilizedMethods) + AuthenticationInput::Feedback feedback, + const QVariantMap &data, + Authenticator::Methods utilizedMethods) { qCDebug(daemon, "Authentication resumed"); @@ -139,7 +162,8 @@ void HostAuthenticationInput::authenticationResumed( clientInterface, QStringLiteral("AuthenticationResumed"), uint(m_activeMethods), - uint(feedback)); + uint(feedback), + data); } } @@ -270,9 +294,25 @@ int HostAuthenticationInput::currentAttempts() const return m_settings->currentAttempts; } +AuthenticationInput::CodeGeneration HostAuthenticationInput::codeGeneration() const +{ + return m_settings->codeGeneration; +} + +QString HostAuthenticationInput::generateCode() const +{ + quint64 number = 0; + QFile file(QStringLiteral("/dev/random")); + if (file.open(QIODevice::ReadOnly)) { + file.read(reinterpret_cast(&number), sizeof(number)); + file.close(); + } + return QString::number(number).right(m_settings->minimumLength).rightJustified(m_settings->minimumLength, QLatin1Char('0')); +} + void HostAuthenticationInput::feedback( AuthenticationInput::Feedback feedback, - int attemptsRemaining, + const QVariantMap &data, Authenticator::Methods utilizedMethods) { if (!m_inputStack.isEmpty()) { @@ -287,30 +327,51 @@ void HostAuthenticationInput::feedback( clientInterface, QStringLiteral("Feedback"), uint(feedback), - uint(attemptsRemaining), + data, uint(m_activeMethods)); } } +void HostAuthenticationInput::feedback( + AuthenticationInput::Feedback feedback, + int attemptsRemaining, + Authenticator::Methods utilizedMethods) +{ + QVariantMap data; + data.insert(QStringLiteral("attemptsRemaining"), attemptsRemaining); + HostAuthenticationInput::feedback(feedback, data, utilizedMethods); +} + void HostAuthenticationInput::lockedOut() { - switch (availability()) { - case ManagerLocked: - abortAuthentication(AuthenticationInput::LockedByManager); - feedback(AuthenticationInput::ContactSupport, -1); - break; - case TemporarilyLocked: - abortAuthentication(AuthenticationInput::MaximumAttemptsExceeded); + lockedOut(availability(), &HostAuthenticationInput::abortAuthentication); +} + +void HostAuthenticationInput::lockedOut( + Availability availability, + void (HostAuthenticationInput::*errorFunction)(AuthenticationInput::Error error)) +{ + switch (availability) { + case CodeEntryLockedRecoverable: + (this->*errorFunction)(AuthenticationInput::MaximumAttemptsExceeded); feedback(AuthenticationInput::TemporarilyLocked, -1); break; - case PermanentlyLocked: - abortAuthentication(AuthenticationInput::MaximumAttemptsExceeded); + case CodeEntryLockedPermanent: + (this->*errorFunction)(AuthenticationInput::MaximumAttemptsExceeded); + feedback(AuthenticationInput::PermanentlyLocked, -1); + break; + case ManagerLockedRecoverable: + (this->*errorFunction)(AuthenticationInput::LockedByManager); + feedback(AuthenticationInput::ContactSupport, -1); + break; + case ManagerLockedPermanent: + (this->*errorFunction)(AuthenticationInput::LockedByManager); 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); + (this->*errorFunction)(AuthenticationInput::SoftwareError); } } @@ -359,6 +420,16 @@ void HostAuthenticationInput::handleEnterSecurityCode(const QString &path, const } } +void HostAuthenticationInput::handleRequestSecurityCode(const QString &path) +{ + const auto connection = QDBusContext::connection().name(); + if (!m_inputStack.isEmpty() + && m_inputStack.last().connection == connection + && m_inputStack.last().path == path) { + requestSecurityCode(); + } +} + void HostAuthenticationInput::handleCancel(const QString &path) { const auto connection = QDBusContext::connection().name(); diff --git a/src/nemo-devicelock/host/hostauthenticationinput.h b/src/nemo-devicelock/host/hostauthenticationinput.h index e1ec8fc..04d9dc4 100644 --- a/src/nemo-devicelock/host/hostauthenticationinput.h +++ b/src/nemo-devicelock/host/hostauthenticationinput.h @@ -55,6 +55,7 @@ public slots: void SetRegistered(const QDBusObjectPath &path, bool registered); void SetActive(const QDBusObjectPath &path, bool active); void EnterSecurityCode(const QDBusObjectPath &path, const QString &code); + void RequestSecurityCode(const QDBusObjectPath &path); void Cancel(const QDBusObjectPath &path); private: @@ -79,11 +80,15 @@ class HostAuthenticationInput : public HostObject CanAuthenticate, CanAuthenticateSecurityCode, SecurityCodeRequired, - ManagerLocked, - TemporarilyLocked, - PermanentlyLocked + CodeEntryLockedRecoverable, + CodeEntryLockedPermanent, + ManagerLockedRecoverable, + ManagerLockedPermanent }; + typedef void (HostAuthenticationInput::*FeedbackFunction)( + AuthenticationInput::Feedback, const QVariantMap &, Authenticator::Methods); + explicit HostAuthenticationInput( const QString &path, Authenticator::Methods supportedMethods = Authenticator::SecurityCode, @@ -100,16 +105,25 @@ class HostAuthenticationInput : public HostObject virtual int maximumAttempts() const; virtual int currentAttempts() const; + virtual AuthenticationInput::CodeGeneration codeGeneration() const; + virtual QString generateCode() const; + virtual void enterSecurityCode(const QString &code) = 0; + virtual void requestSecurityCode() = 0; void cancel() override = 0; // Client + void startAuthentication( + AuthenticationInput::Feedback feedback, + const QVariantMap &data, + Authenticator::Methods methods); virtual void authenticationStarted( Authenticator::Methods methods, AuthenticationInput::Feedback feedback = AuthenticationInput::EnterSecurityCode); void authenticationUnavailable(AuthenticationInput::Error error); void authenticationResumed( AuthenticationInput::Feedback feedback, + const QVariantMap &data = QVariantMap(), Authenticator::Methods utilizedMethods = Authenticator::Methods()); void authenticationEvaluating(); void authenticationProgress(int current, int maximum); @@ -122,6 +136,10 @@ class HostAuthenticationInput : public HostObject virtual void abortAuthentication(AuthenticationInput::Error error); // Signals + void feedback( + AuthenticationInput::Feedback feedback, + const QVariantMap &data, + Authenticator::Methods utilizedMethods = Authenticator::Methods()); void feedback( AuthenticationInput::Feedback feedback, int attemptsRemaining, @@ -132,6 +150,9 @@ class HostAuthenticationInput : public HostObject protected: void lockedOut(); + void lockedOut( + Availability availability, + void (HostAuthenticationInput::*errorFunction)(AuthenticationInput::Error error)); private: friend class HostAuthenticationInputAdaptor; @@ -146,6 +167,7 @@ class HostAuthenticationInput : public HostObject }; inline void handleEnterSecurityCode(const QString &client, const QString &code); + inline void handleRequestSecurityCode(const QString &path); inline void handleCancel(const QString &client); inline void setRegistered(const QString &path, bool registered); diff --git a/src/nemo-devicelock/host/hostauthenticator.cpp b/src/nemo-devicelock/host/hostauthenticator.cpp index 21ddc77..4b5b894 100644 --- a/src/nemo-devicelock/host/hostauthenticator.cpp +++ b/src/nemo-devicelock/host/hostauthenticator.cpp @@ -130,7 +130,8 @@ void HostAuthenticator::authenticate( m_state = Authenticating; m_challengeCode = challengeCode; - switch (availability()) { + const auto availability = this->availability(); + switch (availability) { case AuthenticationNotRequired: qCDebug(daemon, "Authentication requested. Unsecured, authenticating immediately."); confirmAuthentication(); @@ -140,26 +141,18 @@ void HostAuthenticator::authenticate( // Fall through. case CanAuthenticate: qCDebug(daemon, "Authentication requested using methods %i.", int(methods)); - authenticationStarted(methods, AuthenticationInput::EnterSecurityCode); + startAuthentication(AuthenticationInput::EnterSecurityCode, QVariantMap(), methods); break; case SecurityCodeRequired: m_challengeCode.clear(); authenticationUnavailable(AuthenticationInput::FunctionUnavailable); break; - case ManagerLocked: - m_challengeCode.clear(); - authenticationUnavailable(AuthenticationInput::LockedByManager); - feedback(AuthenticationInput::ContactSupport, -1); - break; - case TemporarilyLocked: + case CodeEntryLockedRecoverable: + case CodeEntryLockedPermanent: + case ManagerLockedRecoverable: + case ManagerLockedPermanent: m_challengeCode.clear(); - authenticationUnavailable(AuthenticationInput::MaximumAttemptsExceeded); - feedback(AuthenticationInput::TemporarilyLocked, -1); - break; - case PermanentlyLocked: - m_challengeCode.clear(); - authenticationUnavailable(AuthenticationInput::MaximumAttemptsExceeded); - feedback(AuthenticationInput::PermanentlyLocked, -1); + lockedOut(availability, &HostAuthenticationInput::authenticationUnavailable); break; } } @@ -181,16 +174,16 @@ void HostAuthenticator::handleChangeSecurityCode(const QString &client, const QV switch (availability()) { case AuthenticationNotRequired: case SecurityCodeRequired: - m_state = EnteringNewSecurityCode; - authenticationStarted(Authenticator::SecurityCode, AuthenticationInput::EnterNewSecurityCode); + enterCodeChangeState(&HostAuthenticationInput::startAuthentication, Authenticator::SecurityCode); break; case CanAuthenticateSecurityCode: case CanAuthenticate: - authenticationStarted(Authenticator::SecurityCode, AuthenticationInput::EnterSecurityCode); + startAuthentication(AuthenticationInput::EnterSecurityCode, QVariantMap(), Authenticator::SecurityCode); break; - case ManagerLocked: - case TemporarilyLocked: - case PermanentlyLocked: + case CodeEntryLockedRecoverable: + case CodeEntryLockedPermanent: + case ManagerLockedRecoverable: + case ManagerLockedPermanent: m_challengeCode.clear(); authenticationUnavailable(AuthenticationInput::FunctionUnavailable); break; @@ -217,12 +210,14 @@ void HostAuthenticator::handleClearSecurityCode(const QString &client) break; case CanAuthenticateSecurityCode: case CanAuthenticate: - authenticationStarted(Authenticator::SecurityCode, AuthenticationInput::EnterSecurityCode); + startAuthentication( + AuthenticationInput::EnterSecurityCode, QVariantMap(), Authenticator::SecurityCode); break; case SecurityCodeRequired: - case ManagerLocked: - case TemporarilyLocked: - case PermanentlyLocked: + case CodeEntryLockedRecoverable: + case CodeEntryLockedPermanent: + case ManagerLockedRecoverable: + case ManagerLockedPermanent: authenticationUnavailable(AuthenticationInput::FunctionUnavailable); break; } @@ -252,9 +247,9 @@ void HostAuthenticator::enterSecurityCode(const QString &code) switch ((attempts = checkCode(code))) { case Success: case SecurityCodeExpired: - m_state = EnteringNewSecurityCode; m_currentCode = code; - feedback(AuthenticationInput::EnterNewSecurityCode, -1); + enterCodeChangeState(&HostAuthenticationInput::feedback, Authenticator::SecurityCode); + return; case LockedOut: lockedOut(); @@ -267,6 +262,16 @@ void HostAuthenticator::enterSecurityCode(const QString &code) m_state = RepeatingNewSecurityCode; feedback(AuthenticationInput::RepeatNewSecurityCode, -1); return; + case ExpectingGeneratedSecurityCode: + if (m_generatedCode == code) { + m_newCode = code; + m_state = RepeatingNewSecurityCode; + feedback(AuthenticationInput::RepeatNewSecurityCode, -1); + } else { + feedback(AuthenticationInput::SecurityCodesDoNotMatch, QVariantMap()); + feedback(AuthenticationInput::SuggestSecurityCode, generatedCodeData()); + } + return; case RepeatingNewSecurityCode: { qCDebug(daemon, "New lock code confirmation entered."); if (m_newCode != code) { @@ -278,8 +283,7 @@ void HostAuthenticator::enterSecurityCode(const QString &code) switch (availability()) { case AuthenticationNotRequired: case SecurityCodeRequired: - m_state = EnteringNewSecurityCode; - feedback(AuthenticationInput::EnterNewSecurityCode, -1); + enterCodeChangeState(&HostAuthenticationInput::feedback, Authenticator::SecurityCode); break; default: m_state = AuthenticatingForChange; @@ -325,6 +329,16 @@ void HostAuthenticator::enterSecurityCode(const QString &code) } } +void HostAuthenticator::requestSecurityCode() +{ + if (m_state == EnteringNewSecurityCode + && codeGeneration() != AuthenticationInput::NoCodeGeneration) { + feedback(AuthenticationInput::EnterNewSecurityCode, generatedCodeData()); + } else if (m_state == ExpectingGeneratedSecurityCode) { + feedback(AuthenticationInput::SuggestSecurityCode, generatedCodeData()); + } +} + void HostAuthenticator::setCodeFinished(int result) { switch (result) { @@ -339,9 +353,8 @@ void HostAuthenticator::setCodeFinished(int result) securityCodeChangeAborted(); } else { qCDebug(daemon, "Security code disallowed."); - m_state = EnteringNewSecurityCode; feedback(AuthenticationInput::SecurityCodeInHistory, -1); - feedback(AuthenticationInput::EnterNewSecurityCode, -1); + enterCodeChangeState(&HostAuthenticationInput::feedback, Authenticator::SecurityCode); } break; case Evaluating: @@ -375,6 +388,7 @@ void HostAuthenticator::abortAuthentication(AuthenticationInput::Error error) case AuthenticatingForChange: case EnteringNewSecurityCode: case RepeatingNewSecurityCode: + case ExpectingGeneratedSecurityCode: m_state = ChangeError; break; case AuthenticatingForClear: @@ -409,6 +423,7 @@ void HostAuthenticator::cancel() case AuthenticatingForChange: case EnteringNewSecurityCode: case RepeatingNewSecurityCode: + case ExpectingGeneratedSecurityCode: case ChangeError: securityCodeChangeAborted(); break; @@ -485,4 +500,24 @@ void HostAuthenticator::handleCancel(const QString &client) } } +QVariantMap HostAuthenticator::generatedCodeData() +{ + m_generatedCode = generateCode(); + + QVariantMap data; + data.insert(QStringLiteral("securityCode"), m_generatedCode); + return data; +} + +void HostAuthenticator::enterCodeChangeState(FeedbackFunction feedback, Authenticator::Methods methods) +{ + if (codeGeneration() == AuthenticationInput::MandatoryCodeGeneration) { + m_state = ExpectingGeneratedSecurityCode; + (this->*feedback)(AuthenticationInput::SuggestSecurityCode, generatedCodeData(), methods); + } else { + m_state = EnteringNewSecurityCode; + (this->*feedback)(AuthenticationInput::EnterNewSecurityCode, QVariantMap(), methods); + } +} + } diff --git a/src/nemo-devicelock/host/hostauthenticator.h b/src/nemo-devicelock/host/hostauthenticator.h index 17fa81c..f1d59b0 100644 --- a/src/nemo-devicelock/host/hostauthenticator.h +++ b/src/nemo-devicelock/host/hostauthenticator.h @@ -115,6 +115,7 @@ class HostAuthenticator : public HostAuthenticationInput int setCode(const QString &oldCode, const QString &newCode) override = 0; void enterSecurityCode(const QString &code) override; + void requestSecurityCode() override; void cancel() override; void confirmAuthentication() override; @@ -144,6 +145,7 @@ class HostAuthenticator : public HostAuthenticationInput AuthenticatingForChange, EnteringNewSecurityCode, RepeatingNewSecurityCode, + ExpectingGeneratedSecurityCode, Changing, ChangeError, ChangeCanceled, @@ -157,6 +159,9 @@ class HostAuthenticator : public HostAuthenticationInput inline void handleChangeSecurityCode(const QString &client, const QVariant &challengeCode); inline void handleClearSecurityCode(const QString &client); inline void handleCancel(const QString &client); + inline QVariantMap generatedCodeData(); + inline void enterCodeChangeState( + FeedbackFunction feedback, Authenticator::Methods methods = Authenticator::Methods()); friend class HostAuthenticatorAdaptor; friend class HostSecurityCodeSettingsAdaptor; @@ -166,6 +171,7 @@ class HostAuthenticator : public HostAuthenticationInput QVariant m_challengeCode; QString m_currentCode; QString m_newCode; + QString m_generatedCode; State m_state; }; diff --git a/src/nemo-devicelock/host/hostdevicelock.cpp b/src/nemo-devicelock/host/hostdevicelock.cpp index 6a91b0a..73c9660 100644 --- a/src/nemo-devicelock/host/hostdevicelock.cpp +++ b/src/nemo-devicelock/host/hostdevicelock.cpp @@ -111,37 +111,29 @@ void HostDeviceLock::unlock() m_state = Authenticating; - switch (availability()) { + switch (const auto availability = this->availability()) { case AuthenticationNotRequired: m_state = Idle; setLocked(false); return; case CanAuthenticate: - authenticationStarted( - Authenticator::SecurityCode | Authenticator::Fingerprint, - AuthenticationInput::EnterSecurityCode); + startAuthentication( + AuthenticationInput::EnterSecurityCode, + QVariantMap(), + Authenticator::SecurityCode | Authenticator::Fingerprint); break; case CanAuthenticateSecurityCode: - authenticationStarted(Authenticator::SecurityCode, AuthenticationInput::EnterSecurityCode); + startAuthentication(AuthenticationInput::EnterSecurityCode, QVariantMap(), Authenticator::SecurityCode); break; case SecurityCodeRequired: - m_state = EnteringNewSecurityCode; - authenticationStarted(Authenticator::SecurityCode, AuthenticationInput::EnterNewSecurityCode); - break; - case ManagerLocked: - m_state = AuthenticationError; - authenticationUnavailable(AuthenticationInput::LockedByManager); - feedback(AuthenticationInput::ContactSupport, -1); + enterCodeChangeState(&HostAuthenticationInput::startAuthentication); break; - case TemporarilyLocked: + case CodeEntryLockedRecoverable: + case CodeEntryLockedPermanent: + case ManagerLockedRecoverable: + case ManagerLockedPermanent: m_state = AuthenticationError; - authenticationUnavailable(AuthenticationInput::MaximumAttemptsExceeded); - feedback(AuthenticationInput::TemporarilyLocked, -1); - break; - case PermanentlyLocked: - m_state = AuthenticationError; - authenticationUnavailable(AuthenticationInput::MaximumAttemptsExceeded); - feedback(AuthenticationInput::PermanentlyLocked, -1); + lockedOut(availability, &HostAuthenticationInput::authenticationUnavailable); break; } @@ -162,7 +154,7 @@ void HostDeviceLock::enterSecurityCode(const QString &code) m_state = EnteringNewSecurityCode; m_currentCode = code; feedback(AuthenticationInput::SecurityCodeExpired, -1); - feedback(AuthenticationInput::EnterNewSecurityCode, -1); + enterCodeChangeState(&HostAuthenticationInput::feedback); break; case SecurityCodeInHistory: break; @@ -191,6 +183,16 @@ void HostDeviceLock::enterSecurityCode(const QString &code) m_state = RepeatingNewSecurityCode; feedback(AuthenticationInput::RepeatNewSecurityCode, -1); break; + case ExpectingGeneratedSecurityCode: + if (m_generatedCode == code) { + m_newCode = code; + m_state = RepeatingNewSecurityCode; + feedback(AuthenticationInput::RepeatNewSecurityCode, -1); + } else { + feedback(AuthenticationInput::SecurityCodesDoNotMatch, QVariantMap()); + feedback(AuthenticationInput::SuggestSecurityCode, generatedCodeData()); + } + break; case RepeatingNewSecurityCode: if (m_newCode != code) { m_newCode.clear(); @@ -200,8 +202,7 @@ void HostDeviceLock::enterSecurityCode(const QString &code) switch (availability()) { case AuthenticationNotRequired: case SecurityCodeRequired: - m_state = EnteringNewSecurityCode; - feedback(AuthenticationInput::EnterNewSecurityCode, -1); + enterCodeChangeState(&HostAuthenticationInput::feedback); break; default: m_state = Authenticating; @@ -221,6 +222,16 @@ void HostDeviceLock::enterSecurityCode(const QString &code) } } +void HostDeviceLock::requestSecurityCode() +{ + if (m_state == EnteringNewSecurityCode + && codeGeneration() != AuthenticationInput::NoCodeGeneration) { + feedback(AuthenticationInput::EnterNewSecurityCode, generatedCodeData()); + } else if (m_state == ExpectingGeneratedSecurityCode) { + feedback(AuthenticationInput::SuggestSecurityCode, generatedCodeData()); + } +} + void HostDeviceLock::unlockFinished(int result) { switch (result) { @@ -271,9 +282,8 @@ void HostDeviceLock::setCodeFinished(int result) break; case SecurityCodeInHistory: qCDebug(daemon, "Security code disallowed."); - m_state = EnteringNewSecurityCode; feedback(AuthenticationInput::SecurityCodeInHistory, -1); - feedback(AuthenticationInput::EnterNewSecurityCode, -1); + enterCodeChangeState(&HostAuthenticationInput::feedback); break; case Evaluating: if (m_state == RepeatingNewSecurityCode) { @@ -327,9 +337,10 @@ void HostDeviceLock::confirmAuthentication() authenticationEnded(true); break; - case ManagerLocked: - case TemporarilyLocked: - case PermanentlyLocked: + case CodeEntryLockedRecoverable: + case CodeEntryLockedPermanent: + case ManagerLockedRecoverable: + case ManagerLockedPermanent: authenticationEnded(false); break; } @@ -347,6 +358,7 @@ void HostDeviceLock::abortAuthentication(AuthenticationInput::Error error) case Unlocking: case EnteringNewSecurityCode: case RepeatingNewSecurityCode: + case ExpectingGeneratedSecurityCode: case ChangingSecurityCode: m_state = AuthenticationError; break; @@ -357,19 +369,26 @@ void HostDeviceLock::abortAuthentication(AuthenticationInput::Error error) HostAuthenticationInput::abortAuthentication(error); } +void HostDeviceLock::notice(DeviceLock::Notice notice, const QVariantMap &data) +{ + broadcastSignal( + QStringLiteral("org.nemomobile.devicelock.DeviceLock"), + QStringLiteral("Notice"), + NemoDBus::marshallArguments(uint(notice), data)); +} + void HostDeviceLock::stateChanged() { const auto previousState = m_lockState; switch (availability()) { - case ManagerLocked: - m_lockState = DeviceLock::ManagerLockout; - break; - case TemporarilyLocked: - m_lockState = DeviceLock::TemporaryLockout; + case CodeEntryLockedRecoverable: + case CodeEntryLockedPermanent: + m_lockState = DeviceLock::CodeEntryLockout; break; - case PermanentlyLocked: - m_lockState = DeviceLock::PermanentLockout; + case ManagerLockedRecoverable: + case ManagerLockedPermanent: + m_lockState = DeviceLock::ManagerLockout; break; case SecurityCodeRequired: m_lockState = DeviceLock::Locked; @@ -395,14 +414,14 @@ void HostDeviceLock::lockedChanged() void HostDeviceLock::availabilityChanged() { - const auto available = availability(); + const auto availability = this->availability(); propertyChanged( QStringLiteral("org.nemomobile.devicelock.DeviceLock"), QStringLiteral("Enabled"), - available != AuthenticationNotRequired); + availability != AuthenticationNotRequired); - switch (available) { + switch (availability) { case AuthenticationNotRequired: switch (m_state) { case Authenticating: @@ -431,7 +450,7 @@ void HostDeviceLock::availabilityChanged() break; case AuthenticationError: m_state = Authenticating; - authenticationResumed(AuthenticationInput::EnterSecurityCode, Authenticator::SecurityCode); + authenticationResumed(AuthenticationInput::EnterSecurityCode, QVariantMap(), Authenticator::SecurityCode); break; default: break; @@ -440,48 +459,19 @@ void HostDeviceLock::availabilityChanged() case SecurityCodeRequired: switch (m_state) { case Authenticating: - m_state = EnteringNewSecurityCode; - feedback(AuthenticationInput::EnterNewSecurityCode, -1, Authenticator::SecurityCode); - break; - case AuthenticationError: - m_state = EnteringNewSecurityCode; - authenticationResumed(AuthenticationInput::EnterNewSecurityCode, Authenticator::SecurityCode); - break; - default: - break; - } - break; - case ManagerLocked: - setLocked(true); - - switch (m_state) { - case Authenticating: - case EnteringNewSecurityCode: - case RepeatingNewSecurityCode: - case AuthenticationError: - abortAuthentication(AuthenticationInput::LockedByManager); - feedback(AuthenticationInput::ContactSupport, -1); - break; - default: + enterCodeChangeState(&HostAuthenticationInput::feedback, Authenticator::SecurityCode); break; - } - break; - case TemporarilyLocked: - setLocked(true); - - switch (m_state) { - case Authenticating: - case EnteringNewSecurityCode: - case RepeatingNewSecurityCode: case AuthenticationError: - abortAuthentication(AuthenticationInput::MaximumAttemptsExceeded); - feedback(AuthenticationInput::TemporarilyLocked, -1); + enterCodeChangeState(&HostAuthenticationInput::authenticationResumed, Authenticator::SecurityCode); break; default: break; } break; - case PermanentlyLocked: + case CodeEntryLockedRecoverable: + case CodeEntryLockedPermanent: + case ManagerLockedRecoverable: + case ManagerLockedPermanent: setLocked(true); switch (m_state) { @@ -489,8 +479,7 @@ void HostDeviceLock::availabilityChanged() case EnteringNewSecurityCode: case RepeatingNewSecurityCode: case AuthenticationError: - abortAuthentication(AuthenticationInput::MaximumAttemptsExceeded); - feedback(AuthenticationInput::PermanentlyLocked, -1); + lockedOut(availability, &HostAuthenticationInput::abortAuthentication); break; default: break; @@ -513,4 +502,24 @@ void HostDeviceLock::automaticLockingChanged() { } +QVariantMap HostDeviceLock::generatedCodeData() +{ + m_generatedCode = generateCode(); + + QVariantMap data; + data.insert(QStringLiteral("securityCode"), m_generatedCode); + return data; +} + +void HostDeviceLock::enterCodeChangeState(FeedbackFunction feedback, Authenticator::Methods methods) +{ + if (codeGeneration() == AuthenticationInput::MandatoryCodeGeneration) { + m_state = ExpectingGeneratedSecurityCode; + (this->*feedback)(AuthenticationInput::SuggestSecurityCode, generatedCodeData(), methods); + } else { + m_state = EnteringNewSecurityCode; + (this->*feedback)(AuthenticationInput::EnterNewSecurityCode, QVariantMap(), methods); + } +} + } diff --git a/src/nemo-devicelock/host/hostdevicelock.h b/src/nemo-devicelock/host/hostdevicelock.h index 8025def..63625fb 100644 --- a/src/nemo-devicelock/host/hostdevicelock.h +++ b/src/nemo-devicelock/host/hostdevicelock.h @@ -82,6 +82,7 @@ class HostDeviceLock : public HostAuthenticationInput void unlock(); void enterSecurityCode(const QString &code) override; + void requestSecurityCode() override; void cancel() override; Availability availability() const override = 0; @@ -104,6 +105,9 @@ class HostDeviceLock : public HostAuthenticationInput void unlockFinished(int result); void setCodeFinished(int result); + // Signals + void notice(DeviceLock::Notice notice, const QVariantMap &data); + protected: virtual void stateChanged(); @@ -115,6 +119,7 @@ class HostDeviceLock : public HostAuthenticationInput Authenticating, Unlocking, EnteringNewSecurityCode, + ExpectingGeneratedSecurityCode, RepeatingNewSecurityCode, ChangingSecurityCode, Canceled, @@ -123,11 +128,15 @@ class HostDeviceLock : public HostAuthenticationInput inline bool isEnabled() const; inline void unlockingChanged(); + inline QVariantMap generatedCodeData(); + inline void enterCodeChangeState( + FeedbackFunction feedback, Authenticator::Methods methods = Authenticator::Methods()); HostDeviceLockAdaptor m_adaptor; QExplicitlySharedDataPointer m_settings; QString m_currentCode; QString m_newCode; + QString m_generatedCode; State m_state; DeviceLock::LockState m_lockState; }; diff --git a/src/nemo-devicelock/host/hostobject.cpp b/src/nemo-devicelock/host/hostobject.cpp index 2ecf2bb..94b9e48 100644 --- a/src/nemo-devicelock/host/hostobject.cpp +++ b/src/nemo-devicelock/host/hostobject.cpp @@ -100,12 +100,17 @@ void HostObject::propertyChanged(const QString &interface, const QString &proper const QVariantMap properties = { { property, value } }; - QDBusMessage message = QDBusMessage::createSignal( - m_path, + broadcastSignal( QStringLiteral("org.freedesktop.DBus.Properties"), - QStringLiteral("PropertiesChanged")); + QStringLiteral("PropertiesChanged"), + NemoDBus::marshallArguments(interface, properties, QStringList())); +} + +void HostObject::broadcastSignal(const QString &interface, const QString &name, const QVariantList &arguments) +{ + QDBusMessage message = QDBusMessage::createSignal(m_path, interface, name); - message.setArguments(NemoDBus::marshallArguments(interface, properties, QStringList())); + message.setArguments(arguments); for (const auto connectionName : m_connections) { QDBusConnection(connectionName).send(message); diff --git a/src/nemo-devicelock/host/hostobject.h b/src/nemo-devicelock/host/hostobject.h index 6bc1b0d..97171c7 100644 --- a/src/nemo-devicelock/host/hostobject.h +++ b/src/nemo-devicelock/host/hostobject.h @@ -70,6 +70,7 @@ class HostObject : public QObject, protected QDBusContext protected: void propertyChanged(const QString &interface, const QString &property, const QVariant &value); + void broadcastSignal(const QString &interface, const QString &name, const QVariantList &arguments); template inline bool sendToActiveClient( const QString &interface, diff --git a/src/nemo-devicelock/private/settingswatcher.cpp b/src/nemo-devicelock/private/settingswatcher.cpp index c1d653c..447b8ef 100644 --- a/src/nemo-devicelock/private/settingswatcher.cpp +++ b/src/nemo-devicelock/private/settingswatcher.cpp @@ -92,6 +92,7 @@ SettingsWatcher::SettingsWatcher(QObject *parent) , maximumAutomaticLocking(-1) , absoluteMaximumAttempts(-1) , supportedDeviceResetOptions(DeviceReset::Reboot) + , codeGeneration(AuthenticationInput::NoCodeGeneration) , inputIsKeyboard(false) , currentCodeIsDigitOnly(true) , isHomeEncrypted(false) @@ -268,6 +269,7 @@ void SettingsWatcher::reloadSettings() read(settings, this, "absolute_maximum_attempts", -1, &absoluteMaximumAttempts, &SettingsWatcher::absoluteMaximumAttemptsChanged); read(settings, this, "supported_device_reset_options", DeviceReset::Options(DeviceReset::Reboot), &supportedDeviceResetOptions, &SettingsWatcher::supportedDeviceResetOptionsChanged); read(settings, this, "code_is_mandatory", false, &codeIsMandatory, &SettingsWatcher::codeIsMandatoryChanged); + read(settings, this, "code_generation", AuthenticationInput::NoCodeGeneration, &codeGeneration, &SettingsWatcher::codeGenerationChanged); g_key_file_free(settings); } diff --git a/src/nemo-devicelock/private/settingswatcher.h b/src/nemo-devicelock/private/settingswatcher.h index 7bc1142..b262a77 100644 --- a/src/nemo-devicelock/private/settingswatcher.h +++ b/src/nemo-devicelock/private/settingswatcher.h @@ -33,7 +33,7 @@ #ifndef NEMODEVICELOCK_SETTINGSWATCHER_H #define NEMODEVICELOCK_SETTINGSWATCHER_H -#include +#include #include #include @@ -57,6 +57,11 @@ template <> inline QMetaEnum resolveMetaEnum() { template <> inline DeviceReset::Options settingsValueFromString(const char *string) { return flagsFromString(string); } +template <> inline QMetaEnum resolveMetaEnum() { + return resolveMetaEnum(&AuthenticationInput::staticMetaObject, "CodeGeneration"); } +template <> inline AuthenticationInput::CodeGeneration settingsValueFromString(const char *string) { + return AuthenticationInput::CodeGeneration(flagsFromString(resolveMetaEnum(), string)); } + class NEMODEVICELOCK_EXPORT SettingsWatcher : public QSocketNotifier, public QSharedData { Q_OBJECT @@ -65,7 +70,6 @@ class NEMODEVICELOCK_EXPORT SettingsWatcher : public QSocketNotifier, public QSh static SettingsWatcher *instance(); - int automaticLocking; int minimumLength; int maximumLength; @@ -77,6 +81,7 @@ class NEMODEVICELOCK_EXPORT SettingsWatcher : public QSocketNotifier, public QSh int maximumAutomaticLocking; int absoluteMaximumAttempts; DeviceReset::Options supportedDeviceResetOptions; + AuthenticationInput::CodeGeneration codeGeneration; bool inputIsKeyboard; bool currentCodeIsDigitOnly; bool isHomeEncrypted; @@ -111,6 +116,7 @@ class NEMODEVICELOCK_EXPORT SettingsWatcher : public QSocketNotifier, public QSh void inputIsKeyboardChanged(); void currentCodeIsDigitOnlyChanged(); void codeIsMandatoryChanged(); + void codeGenerationChanged(); private: explicit SettingsWatcher(QObject *parent = nullptr);