diff --git a/appinfo/routes.php b/appinfo/routes.php
index 58bbfe3..cced935 100644
--- a/appinfo/routes.php
+++ b/appinfo/routes.php
@@ -36,5 +36,16 @@
'url' => '/settings/verifyNewSecret',
'verb' => 'POST'
],
+ ],
+ 'ocs' => [
+ [
+ 'name' => 'totp_api#validateKey',
+ 'url' => '/api/v1/validate/{uid}/{key}',
+ 'verb' => 'GET',
+ 'requirements' => [
+ 'uid' => '.+',
+ 'key' => '.+'
+ ]
+ ]
]
];
diff --git a/lib/Controller/TotpApiController.php b/lib/Controller/TotpApiController.php
new file mode 100644
index 0000000..7e32f26
--- /dev/null
+++ b/lib/Controller/TotpApiController.php
@@ -0,0 +1,82 @@
+
+ *
+ * Two-factor TOTP
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see
+ *
+ */
+
+namespace OCA\TwoFactor_Totp\Controller;
+
+use OCA\TwoFactor_Totp\Exception\NoTotpSecretFoundException;
+use OCP\AppFramework\Http;
+use OCP\AppFramework\Http\DataResponse;
+use OCP\AppFramework\OCSController;
+use OCP\ILogger;
+use \OCP\IRequest;
+use \OCP\IUserManager;
+use OCA\TwoFactor_Totp\Service\ITotp;
+
+class TotpApiController extends OCSController {
+
+ /** @var ITotp */
+ private $totp;
+
+ /** @var IUserManager */
+ private $userManager;
+
+ /** @var ILogger */
+ private $logger;
+
+ public function __construct(
+ $appName,
+ IRequest $request,
+ ITotp $totp,
+ IUserManager $userManager,
+ ILogger $logger
+ ) {
+ parent::__construct($appName, $request);
+ $this->totp = $totp;
+ $this->userManager = $userManager;
+ $this->logger = $logger;
+ }
+
+ /**
+ * @CORS
+ * @NoCSRFRequired
+ *
+ * @param string $uid
+ * @param string $key 6 digits numeric time-based one time password.
+ * @return DataResponse
+ */
+ public function validateKey($uid, $key) {
+ $user = $this->userManager->get($uid);
+ if ($user !== null) {
+ try {
+ return new DataResponse(['data' => ['result' => $this->totp->validateKey($user, $key)]]);
+ } catch (NoTotpSecretFoundException $e) {
+ $this->logger->logException($e);
+ }
+ }
+ return new DataResponse(
+ [
+ 'statuscode' => 404,
+ 'data' => ['result' => false]
+ ],
+ Http::STATUS_NOT_FOUND
+ );
+ }
+}
diff --git a/lib/Provider/TotpProvider.php b/lib/Provider/TotpProvider.php
index 42a8e7c..47d45f9 100644
--- a/lib/Provider/TotpProvider.php
+++ b/lib/Provider/TotpProvider.php
@@ -90,7 +90,7 @@ public function getTemplate(IUser $user) {
* @param string $challenge
*/
public function verifyChallenge(IUser $user, $challenge) {
- return $this->totp->validateSecret($user, $challenge);
+ return $this->totp->validateKey($user, $challenge);
}
/**
diff --git a/lib/Service/ITotp.php b/lib/Service/ITotp.php
index e714a4d..582d0c5 100644
--- a/lib/Service/ITotp.php
+++ b/lib/Service/ITotp.php
@@ -22,6 +22,7 @@
namespace OCA\TwoFactor_Totp\Service;
+use OCA\TwoFactor_Totp\Exception\NoTotpSecretFoundException;
use OCA\TwoFactor_Totp\Exception\TotpSecretAlreadySet;
use OCP\IUser;
@@ -46,9 +47,11 @@ public function deleteSecret(IUser $user);
/**
* @param IUser $user
- * @param string $key
+ * @param string $key 6 digits numeric time-based one time password.
+ * @return boolean If key is correct
+ * @throws NoTotpSecretFoundException
*/
- public function validateSecret(IUser $user, $key);
+ public function validateKey(IUser $user, $key);
/**
* @param IUser $user
diff --git a/lib/Service/Totp.php b/lib/Service/Totp.php
index 7b97678..e9f97bd 100644
--- a/lib/Service/Totp.php
+++ b/lib/Service/Totp.php
@@ -92,7 +92,7 @@ public function deleteSecret(IUser $user) {
* @param string $key
*/
public function verifySecret(IUser $user, $key) {
- if ($this->validateSecret($user, $key) === true) {
+ if ($this->validateKey($user, $key) === true) {
$dbSecret = $this->secretMapper->getSecret($user);
$dbSecret->setVerified(true);
$this->secretMapper->update($dbSecret);
@@ -104,8 +104,10 @@ public function verifySecret(IUser $user, $key) {
/**
* @param IUser $user
* @param string $key
+ * @return boolean
+ * @throws NoTotpSecretFoundException
*/
- public function validateSecret(IUser $user, $key) {
+ public function validateKey(IUser $user, $key) {
try {
$dbSecret = $this->secretMapper->getSecret($user);
} catch (DoesNotExistException $ex) {
diff --git a/tests/unit/Controller/TotpApiControllerTest.php b/tests/unit/Controller/TotpApiControllerTest.php
new file mode 100644
index 0000000..386d49c
--- /dev/null
+++ b/tests/unit/Controller/TotpApiControllerTest.php
@@ -0,0 +1,138 @@
+
+ *
+ * Two-factor TOTP
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see
+ *
+ */
+
+namespace OCA\TwoFactor_Totp\Unit\Controller;
+
+use OC\OCS\Result;
+use OCA\TwoFactor_Totp\Controller\TotpApiController;
+use OCA\TwoFactor_Totp\Exception\NoTotpSecretFoundException;
+use OCA\TwoFactor_Totp\Service\ITotp;
+use OCP\AppFramework\Http;
+use OCP\AppFramework\Http\DataResponse;
+use OCP\ILogger;
+use OCP\IRequest;
+use OCP\IUser;
+use OCP\IUserManager;
+use Test\TestCase;
+use PHPUnit_Framework_MockObject_MockObject;
+
+class TotpApiControllerTest extends TestCase {
+
+ /** @var IRequest | PHPUnit_Framework_MockObject_MockObject */
+ private $request;
+
+ /** @var IUserManager | PHPUnit_Framework_MockObject_MockObject */
+ private $userManager;
+
+ /** @var IUser | PHPUnit_Framework_MockObject_MockObject */
+ private $user;
+
+ /** @var ITotp | PHPUnit_Framework_MockObject_MockObject */
+ private $totp;
+
+ /** @var ILogger | PHPUnit_Framework_MockObject_MockObject */
+ private $logger;
+
+ /** @var TotpApiController */
+ private $controller;
+
+ protected function setUp() {
+ parent::setUp();
+ $this->user = $this->createMock(IUser::class);
+ $this->request = $this->createMock(IRequest::class);
+ $this->userManager = $this->createMock(IUserManager::class);
+ $this->totp = $this->createMock(ITotp::class);
+ $this->logger = $this->createMock(ILogger::class);
+
+ $this->controller = new TotpApiController(
+ 'twofactor_totp',
+ $this->request, $this->totp,
+ $this->userManager,
+ $this->logger
+ );
+ }
+
+ /**
+ * @dataProvider dataTestValidateKey
+ *
+ * @param string $uid
+ * @param boolean $result
+ */
+ public function testValidateKey($uid, $result) {
+ $this->userManager->expects($this->once())
+ ->method('get')
+ ->with($uid)
+ ->will($this->returnValue($this->user));
+ $this->totp->expects($this->once())
+ ->method('validateKey')
+ ->with($this->user, '111111')
+ ->will($this->returnValue($result));
+
+ $expected = new DataResponse(['data' => ['result' => $result]]);
+ $this->assertEquals($expected, $this->controller->validateKey($uid, '111111'));
+ }
+
+ public function dataTestValidateKey() {
+ return [
+ ['testuser', false],
+ ['testuser', true],
+ ];
+ }
+
+ public function testValidateKeyUserNotExist() {
+ $this->userManager->expects($this->once())
+ ->method('get')
+ ->with('notexist')
+ ->will($this->returnValue(null));
+ $expected = new DataResponse(
+ [
+ 'statuscode' => 404,
+ 'data' => ['result' => false]
+ ],
+ Http::STATUS_NOT_FOUND
+ );
+ $this->assertEquals($expected, $this->controller->validateKey('notexist', '111111'));
+ }
+
+ public function testValidateKeySecretNotExist() {
+ $exception = new NoTotpSecretFoundException();
+ $this->user = $this->createMock(IUser::class);
+ $this->userManager->expects($this->once())
+ ->method('get')
+ ->with('testuser')
+ ->will($this->returnValue($this->user));
+ $this->totp->expects($this->once())
+ ->method('validateKey')
+ ->with($this->user, '111111')
+ ->will($this->throwException($exception));
+ $this->logger->expects($this->once())
+ ->method('logException')
+ ->with($exception);
+ $expected = new DataResponse(
+ [
+ 'statuscode' => 404,
+ 'data' => ['result' => false]
+ ],
+ Http::STATUS_NOT_FOUND
+ );
+ $this->assertEquals($expected, $this->controller->validateKey('testuser', '111111'));
+ }
+}
diff --git a/tests/unit/Provider/TotpProviderTest.php b/tests/unit/Provider/TotpProviderTest.php
new file mode 100644
index 0000000..7d3a115
--- /dev/null
+++ b/tests/unit/Provider/TotpProviderTest.php
@@ -0,0 +1,62 @@
+
+ *
+ * Two-factor TOTP
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see
+ *
+ */
+
+namespace OCA\TwoFactor_Totp\Tests\Provider;
+
+use OCA\TwoFactor_Totp\Provider\TotpProvider;
+use OCA\TwoFactor_Totp\Service\ITotp;
+use OCP\IL10N;
+use OCP\IUser;
+use Test\TestCase;
+
+/**
+ * Class TotpTest
+ */
+class TotpProviderTest extends TestCase {
+
+ /** @var ITotp | \PHPUnit_Framework_MockObject_MockObject $totp */
+ private $totp;
+
+ /** @var IL10N | \PHPUnit_Framework_MockObject_MockObject */
+ private $l;
+
+ /** @var IUser | \PHPUnit_Framework_MockObject_MockObject */
+ private $user;
+
+ /** @var TotpProvider $totpProvider */
+ private $totpProvider;
+
+ protected function setUp() {
+ parent::setUp();
+
+ $this->totp = $this->createMock(ITotp::class);
+ $this->l = $this->createMock(IL10N::class);
+ $this->user = $this->createMock(IUser::class);
+
+ $this->totpProvider = new TotpProvider($this->totp, $this->l);
+ }
+
+ public function testVerifyChallange() {
+ $this->totp->expects($this->once())
+ ->method('validateKey')
+ ->with($this->user, '111111');
+ $this->totpProvider->verifyChallenge($this->user, '111111');
+ }
+}
diff --git a/tests/unit/Service/TotpTest.php b/tests/unit/Service/TotpTest.php
index 381ecca..3b1b2c7 100644
--- a/tests/unit/Service/TotpTest.php
+++ b/tests/unit/Service/TotpTest.php
@@ -64,7 +64,7 @@ protected function setUp() {
* @param boolean $validationResult
* @param boolean $expectedResult
*/
- public function testValidateSecret($lastKey, $key, $validationResult, $expectedResult) {
+ public function testValidateKey($lastKey, $key, $validationResult, $expectedResult) {
/** @var IUser | \PHPUnit_Framework_MockObject_MockObject $user */
$user = $this->createMock(IUser::class);
$dbSecret = $this
@@ -96,7 +96,7 @@ public function testValidateSecret($lastKey, $key, $validationResult, $expectedR
->method('update')
->with($dbSecret);
}
- $this->assertEquals($this->totp->validateSecret($user, $key), $expectedResult);
+ $this->assertEquals($this->totp->validateKey($user, $key), $expectedResult);
}
public function validationProvider() {
@@ -117,6 +117,6 @@ public function testValidateSecretNoSecret() {
->with($user)
->will($this->throwException(new DoesNotExistException('')));
$this->expectException(NoTotpSecretFoundException::class);
- $this->totp->validateSecret($user, 'testkey');
+ $this->totp->validateKey($user, 'testkey');
}
}