Skip to content

Commit

Permalink
Handle the authentication flow in the base library.
Browse files Browse the repository at this point in the history
  • Loading branch information
adenexter committed Nov 11, 2016
1 parent d1855c8 commit a64044d
Show file tree
Hide file tree
Showing 25 changed files with 693 additions and 620 deletions.
4 changes: 2 additions & 2 deletions src/nemo-devicelock/authenticationinput.cpp
Expand Up @@ -200,9 +200,9 @@ void AuthenticationInput::setRegistered(bool registered)
emit registeredChanged();
}
}
void AuthenticationInput::enterLockCode(const QString &code)
void AuthenticationInput::enterSecurityCode(const QString &code)
{
call(QStringLiteral("EnterLockCode"), m_localPath, code);
call(QStringLiteral("EnterSecurityCode"), m_localPath, code);
}

void AuthenticationInput::cancel()
Expand Down
14 changes: 8 additions & 6 deletions src/nemo-devicelock/authenticationinput.h
Expand Up @@ -75,17 +75,19 @@ class NEMODEVICELOCK_EXPORT AuthenticationInput : public QObject, private Connec
Q_ENUMS(Status)
public:
enum Feedback {
EnterLockCode,
EnterNewLockCode,
RepeatNewLockCode,
LockCodesDoNotMatch,
EnterSecurityCode,
EnterNewSecurityCode,
RepeatNewSecurityCode,
SecurityCodesDoNotMatch,
SecurityCodeInHistory,
SecurityCodeExpired,
PartialPrint,
PrintIsUnclear,
SensorIsDirty,
SwipeFaster,
SwipeSlower,
UnrecognizedFinger,
IncorrectLockCode
IncorrectSecurityCode
};

enum Error {
Expand Down Expand Up @@ -125,7 +127,7 @@ class NEMODEVICELOCK_EXPORT AuthenticationInput : public QObject, private Connec
int maximumCodeLength() const;
bool codeInputIsKeyboard() const;

Q_INVOKABLE void enterLockCode(const QString &code);
Q_INVOKABLE void enterSecurityCode(const QString &code);
Q_INVOKABLE void cancel();

signals:
Expand Down
4 changes: 2 additions & 2 deletions src/nemo-devicelock/authenticator.h
Expand Up @@ -68,7 +68,7 @@ class NEMODEVICELOCK_EXPORT Authenticator : public QObject, private ConnectionCl
public:
enum Method {
NoAuthentication = 0x00,
LockCode = 0x01,
SecurityCode = 0x01,
Fingerprint = 0x02
};

Expand All @@ -81,7 +81,7 @@ class NEMODEVICELOCK_EXPORT Authenticator : public QObject, private ConnectionCl
bool isAuthenticating() const;

Q_INVOKABLE void authenticate(
const QVariant &challengeCode, Methods methods = Methods(LockCode | Fingerprint));
const QVariant &challengeCode, Methods methods = Methods(SecurityCode | Fingerprint));
Q_INVOKABLE void cancel();

signals:
Expand Down
240 changes: 23 additions & 217 deletions src/nemo-devicelock/host/cli/cliauthenticator.cpp
Expand Up @@ -40,14 +40,13 @@ namespace NemoDeviceLock
{

CliAuthenticator::CliAuthenticator(QObject *parent)
: HostAuthenticator(Authenticator::LockCode, parent)
: HostAuthenticator(Authenticator::SecurityCode, parent)
, m_watcher(LockCodeWatcher::instance())
, m_state(Idle)
{
connect(m_watcher.data(), &LockCodeWatcher::lockCodeSetChanged,
connect(m_watcher.data(), &LockCodeWatcher::securityCodeSetChanged,
this, &CliAuthenticator::availableMethodsChanged);
connect(m_watcher.data(), &LockCodeWatcher::lockCodeSetChanged,
this, &CliAuthenticator::lockCodeSetChanged);
connect(m_watcher.data(), &LockCodeWatcher::securityCodeSetChanged,
this, &CliAuthenticator::availabilityChanged);
}

CliAuthenticator::~CliAuthenticator()
Expand All @@ -58,248 +57,55 @@ Authenticator::Methods CliAuthenticator::availableMethods() const
{
Authenticator::Methods methods;

if (m_watcher->lockCodeSet()) {
methods |= Authenticator::LockCode;
if (m_watcher->securityCodeSet()) {
methods |= Authenticator::SecurityCode;
}

return methods;
}

bool CliAuthenticator::isLockCodeSet() const
{
return m_watcher->lockCodeSet();
}

void CliAuthenticator::authenticate(
const QString &client, const QVariant &, Authenticator::Methods methods)
HostAuthenticationInput::Availability CliAuthenticator::availability() const
{
cancel();

setActiveClient(client);
if (m_watcher->lockCodeSet()) {
if (m_watcher->securityCodeSet()) {
const int maximum = maximumAttempts();
const int attempts = currentAttempts();

m_state = AuthenticationInput;

if (maximum > 0 && attempts >= maximum) {
authenticationUnavailable(AuthenticationInput::LockedOut);
return AuthenticationLocked;
} else {
authenticationStarted(methods, AuthenticationInput::EnterLockCode);
return CanAuthenticate;
}
} else {
// No code is set. Authenticate immediately with a dummy lock code.
authenticated(QStringLiteral("12345"));
clearActiveClient();
return AuthenticationNotRequired;
}
}

void CliAuthenticator::changeLockCode(const QString &client, const QVariant &)
int CliAuthenticator::checkCode(const QString &code)
{
cancel();

setActiveClient(client);

if (m_watcher->lockCodeSet()) {
const int maximum = maximumAttempts();
const int attempts = currentAttempts();

m_state = ChangeCurrentInput;

if (maximum > 0 && attempts >= maximum) {
authenticationUnavailable(AuthenticationInput::LockedOut);
} else {
authenticationStarted(Authenticator::LockCode, AuthenticationInput::EnterLockCode);
}
} else {
m_state = ChangeNewInput;

authenticationStarted(Authenticator::LockCode, AuthenticationInput::EnterNewLockCode);
}
return m_watcher->runPlugin(QStringList() << QStringLiteral("--check-code") << code);
}

void CliAuthenticator::clearLockCode(const QString &client)
{
cancel();

if (m_watcher->lockCodeSet()) {
const int maximum = maximumAttempts();
const int attempts = currentAttempts();

setActiveClient(client);

m_state = AuthenticationInput;

if (maximum > 0 && attempts >= maximum) {
authenticationUnavailable(AuthenticationInput::LockedOut);
} else {
authenticationStarted(Authenticator::LockCode, AuthenticationInput::EnterLockCode);
}
} else {
QDBusContext::sendErrorReply(QDBusError::InvalidArgs);
}
}


void CliAuthenticator::enterLockCode(const QString &code)
int CliAuthenticator::setCode(const QString &oldCode, const QString &newCode)
{
PluginCommand *command = nullptr;

switch (m_state) {
case Idle:
return;
case AuthenticationInput:
if ((command = m_watcher->checkCode(this, code))) {
command->onSuccess([this, code]() {
authenticated(code);
});
} else {
abortAuthentication(AuthenticationInput::SoftwareError);
return;
}
break;
case ChangeCurrentInput:
if ((command = m_watcher->checkCode(this, code))) {
command->onSuccess([this, code]() {
m_state = ChangeNewInput;
feedback(AuthenticationInput::EnterNewLockCode, -1);
});
} else {
abortAuthentication(AuthenticationInput::SoftwareError);
return;
}
break;
case ChangeNewInput:
m_newCode = code;
m_state = ChangeRepeatInput;
feedback(AuthenticationInput::RepeatNewLockCode, -1);
return;
case ChangeRepeatInput: {
if (m_newCode != code) {
m_currentCode.clear();
m_newCode.clear();

feedback(AuthenticationInput::LockCodesDoNotMatch, -1);

if (m_watcher->lockCodeSet()) {
m_state = ChangeCurrentInput;
feedback(AuthenticationInput::EnterLockCode, -1);
} else {
m_state = ChangeNewInput;
feedback(AuthenticationInput::EnterNewLockCode, -1);
}

return;
}

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

if (const auto command = m_watcher->runPlugin(
this, QStringList() << QStringLiteral("--set-code") << currentCode << code)) {
command->onSuccess([this, code]() {
lockCodeChanged(code);
});
command->onFailure([this](int) {
abortAuthentication(AuthenticationInput::SoftwareError);
});
command->waitForFinished();
} else {
abortAuthentication(AuthenticationInput::SoftwareError);
}
return;
}
case ClearInput: {
if ((command = m_watcher->runPlugin(
this, QStringList() << QStringLiteral("--clear-code") << code))) {
command->onSuccess([this, code]() {
lockCodeCleared();
});
} else {
abortAuthentication(AuthenticationInput::SoftwareError);
return;
}
break;
}
default:
return;
}

Q_ASSERT(command);

command->onFailure([this](int exitCode) {
const int maximum = maximumAttempts();

if (maximum > 0 && exitCode < 0) {
const int attempts = -exitCode;
feedback(AuthenticationInput::IncorrectLockCode, qMax(0, maximum - attempts));

if (attempts >= maximum) {
abortAuthentication(AuthenticationInput::LockedOut);
return;
}
} else {
feedback(AuthenticationInput::IncorrectLockCode, -1);
}
});
command->waitForFinished();
return m_watcher->runPlugin(QStringList() << QStringLiteral("--set-code") << oldCode << newCode);
}

void CliAuthenticator::cancel()
bool CliAuthenticator::clearCode(const QString &code)
{
if (m_state != Idle) {
switch (m_state) {
case AuthenticationInput:
case AuthenticationError:
aborted();
break;
case ChangeCurrentInput:
case ChangeNewInput:
case ChangeRepeatInput:
case ChangeError:
lockCodeChangeAborted();
break;
case ClearInput:
case ClearError:
lockCodeClearAborted();
break;
default:
break;
}
}
return m_watcher->runPlugin(QStringList() << QStringLiteral("--clear-code") << code) == Success;
}

void CliAuthenticator::authenticationEnded(bool confirmed)
void CliAuthenticator::enterSecurityCode(const QString &code)
{
clearActiveClient();

m_state = Idle;
m_currentCode.clear();
m_newCode.clear();

HostAuthenticator::authenticationEnded(confirmed);
m_securityCode = code;
HostAuthenticator::enterSecurityCode(code);
m_securityCode.clear();
}

void CliAuthenticator::abortAuthentication(AuthenticationInput::Error error)
QVariant CliAuthenticator::authenticateChallengeCode(const QVariant &)
{
switch (m_state) {
case AuthenticationInput:
m_state = AuthenticationError;
break;
case ChangeCurrentInput:
case ChangeNewInput:
case ChangeRepeatInput:
m_state = ChangeError;
break;
case ClearInput:
m_state = ClearError;
break;
default:
break;
}

HostAuthenticator::abortAuthentication(error);
return m_securityCode;
}

}
35 changes: 7 additions & 28 deletions src/nemo-devicelock/host/cli/cliauthenticator.h
Expand Up @@ -51,39 +51,18 @@ class CliAuthenticator : public HostAuthenticator
~CliAuthenticator();

Authenticator::Methods availableMethods() const override;
bool isLockCodeSet() const override;
Availability availability() const override;

void authenticate(
const QString &authenticator,
const QVariant &challengeCode,
Authenticator::Methods methods) override;
void changeLockCode(const QString &path, const QVariant &challengeCode) override;
void clearLockCode(const QString &path) override;
int checkCode(const QString &code) override;
int setCode(const QString &oldCode, const QString &newCode) override;
bool clearCode(const QString &code) override;

void enterLockCode(const QString &code) override;

void cancel() override;

void authenticationEnded(bool confirmed) override;
void abortAuthentication(AuthenticationInput::Error error) override;
void enterSecurityCode(const QString &code);
QVariant authenticateChallengeCode(const QVariant &challengeCode);

private:
enum State {
Idle,
AuthenticationInput,
AuthenticationError,
ChangeCurrentInput,
ChangeNewInput,
ChangeRepeatInput,
ChangeError,
ClearInput,
ClearError
};

QExplicitlySharedDataPointer<LockCodeWatcher> m_watcher;
QString m_currentCode;
QString m_newCode;
State m_state;
QString m_securityCode;
};

}
Expand Down

0 comments on commit a64044d

Please sign in to comment.