Skip to content

Commit

Permalink
Allow creating/verifying/using one-time use backup keys (type: plain,…
Browse files Browse the repository at this point in the history
… onetime: true). #35
  • Loading branch information
ShaneMcC committed Nov 11, 2018
1 parent bad6c98 commit 6cf1a8f
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 5 deletions.
9 changes: 6 additions & 3 deletions web/1.0/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -220,22 +220,25 @@ function getKnownDevice($user, &$context) {
$user = User::loadFromEmail($context['db'], $_SERVER['PHP_AUTH_USER']);

if ($user !== FALSE && $user->checkPassword($_SERVER['PHP_AUTH_PW'])) {
$keys = TwoFactorKey::getSearch($context['db'])->where('user_id', $user->getID())->where('active', 'true')->find('key');
$possibleKeys = TwoFactorKey::getSearch($context['db'])->where('user_id', $user->getID())->where('active', 'true')->find('key');

// Don't check 2FA keys if we have a valid saved device.
getKnownDevice($user, $context);
if (isset($context['device'])) {
$keys = [];
$possibleKeys = [];
}

$keys = [];
foreach ($possibleKeys as $key) { if ($key->isUsableKey()) { $keys[] = $key; } }

$valid = true;
if (count($keys) > 0) {
$valid = false;
$testCode = isset($_SERVER['HTTP_X_2FA_KEY']) ? $_SERVER['HTTP_X_2FA_KEY'] : NULL;

if ($testCode !== NULL) {
foreach ($keys as $key) {
if ($key->isUsableKey() && $key->verify($testCode, 1)) {
if ($key->verify($testCode, 1)) {
$valid = true;
$key->setLastUsed(time())->save();

Expand Down
27 changes: 25 additions & 2 deletions web/1.0/methods/useradmin.php
Original file line number Diff line number Diff line change
Expand Up @@ -441,6 +441,7 @@ protected function get2FAKeys($user) {
if ($v->isActive()) {
unset($result[$k]['key']);
}
$result[$k]['usable'] = $v->isUsableKey();
}

$this->getContextKey('response')->data($result);
Expand Down Expand Up @@ -482,7 +483,26 @@ protected function get2FAKey($user, $key) {
}

protected function create2FAKey($user) {
$key = (new TwoFactorKey($this->getContextKey('db')))->setKey(TRUE)->setUserID($user->getID())->setCreated(time());
$key = (new TwoFactorKey($this->getContextKey('db')))->setUserID($user->getID())->setCreated(time());

$data = $this->getContextKey('data');
if (isset($data['data']['type'])) {
$key->setType($data['data']['type']);
}

if (isset($data['data']['onetime'])) {
$key->setOneTime($data['data']['onetime']);
}

// Some keys in future may allow this, for now do not.
$canSetSecret = false;

if ($canSetSecret && isset($data['data']['secret'])) {
$key->setKey($data['data']['secret']);
} else {
$key->setKey(TRUE);
}

return $this->update2FAKey($user, $key, true);
}

Expand Down Expand Up @@ -564,7 +584,10 @@ protected function verify2FAKey($user, $key) {
}

// Activate the key once verified.
$key->setActive(true)->setLastUsed(time())->save();
$key->setActive(true);
if (!$key->isOneTime()) { $key->setLastUsed(time()); }
$key->save();

$this->getContextKey('response')->data(['success' => 'Valid code provided.']);

return TRUE;
Expand Down

0 comments on commit 6cf1a8f

Please sign in to comment.