Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nextcloud/twofactor_u2f.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/AppInfo/Application.php4
-rw-r--r--lib/Controller/SettingsController.php3
-rw-r--r--lib/Provider/U2FLoginProvider.php39
-rw-r--r--lib/Provider/U2FProvider.php23
-rw-r--r--package-lock.json213
-rw-r--r--package.json2
-rw-r--r--src/components/AddDeviceDialog.vue32
-rw-r--r--src/components/LoginSetup.vue69
-rw-r--r--src/logger.js32
-rw-r--r--src/main-login-setup.js37
-rw-r--r--src/tests/setup.js6
-rw-r--r--src/webpack.common.js3
-rw-r--r--templates/loginsetup.php28
-rw-r--r--tests/Unit/Provider/U2FProviderTest.php25
14 files changed, 412 insertions, 104 deletions
diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php
index 5ecb7f8..a552036 100644
--- a/lib/AppInfo/Application.php
+++ b/lib/AppInfo/Application.php
@@ -24,8 +24,10 @@ use Symfony\Component\EventDispatcher\EventDispatcherInterface;
class Application extends App {
+ const APP_ID = 'twofactor_u2f';
+
public function __construct(array $urlParams = []) {
- parent::__construct('twofactor_u2f', $urlParams);
+ parent::__construct(self::APP_ID, $urlParams);
$container = $this->getContainer();
/** @var EventDispatcherInterface $eventDispatcher */
diff --git a/lib/Controller/SettingsController.php b/lib/Controller/SettingsController.php
index e7965dd..3d3e0dc 100644
--- a/lib/Controller/SettingsController.php
+++ b/lib/Controller/SettingsController.php
@@ -19,10 +19,11 @@ require_once(__DIR__ . '/../../vendor/yubico/u2flib-server/src/u2flib_server/U2F
use OCA\TwoFactorU2F\Service\U2FManager;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http\JSONResponse;
+use OCP\Authentication\TwoFactorAuth\ALoginSetupController;
use OCP\IRequest;
use OCP\IUserSession;
-class SettingsController extends Controller {
+class SettingsController extends ALoginSetupController {
/** @var U2FManager */
private $manager;
diff --git a/lib/Provider/U2FLoginProvider.php b/lib/Provider/U2FLoginProvider.php
new file mode 100644
index 0000000..09649f9
--- /dev/null
+++ b/lib/Provider/U2FLoginProvider.php
@@ -0,0 +1,39 @@
+<?php declare(strict_types=1);
+
+/**
+ * @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * 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
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+namespace OCA\TwoFactorU2F\Provider;
+
+use OCA\TwoFactorU2F\AppInfo\Application;
+use OCP\Authentication\TwoFactorAuth\ILoginSetupProvider;
+use OCP\Template;
+
+class U2FLoginProvider implements ILoginSetupProvider {
+
+ /**
+ * @return Template
+ */
+ public function getBody(): Template {
+ return new Template(Application::APP_ID, 'loginsetup');
+ }
+
+}
diff --git a/lib/Provider/U2FProvider.php b/lib/Provider/U2FProvider.php
index ab3f92a..c9e8b9b 100644
--- a/lib/Provider/U2FProvider.php
+++ b/lib/Provider/U2FProvider.php
@@ -16,16 +16,18 @@ namespace OCA\TwoFactorU2F\Provider;
use OCA\TwoFactorU2F\Service\U2FManager;
use OCA\TwoFactorU2F\Settings\Personal;
+use OCP\AppFramework\IAppContainer;
+use OCP\Authentication\TwoFactorAuth\IActivatableAtLogin;
use OCP\Authentication\TwoFactorAuth\IDeactivatableByAdmin;
+use OCP\Authentication\TwoFactorAuth\ILoginSetupProvider;
use OCP\Authentication\TwoFactorAuth\IPersonalProviderSettings;
-use OCP\Authentication\TwoFactorAuth\IProvider;
use OCP\Authentication\TwoFactorAuth\IProvidesIcons;
use OCP\Authentication\TwoFactorAuth\IProvidesPersonalSettings;
use OCP\IL10N;
use OCP\IUser;
use OCP\Template;
-class U2FProvider implements IProvider, IProvidesIcons, IProvidesPersonalSettings, IDeactivatableByAdmin {
+class U2FProvider implements IActivatableAtLogin, IProvidesIcons, IProvidesPersonalSettings, IDeactivatableByAdmin {
/** @var IL10N */
private $l10n;
@@ -33,9 +35,15 @@ class U2FProvider implements IProvider, IProvidesIcons, IProvidesPersonalSetting
/** @var U2FManager */
private $manager;
- public function __construct(IL10N $l10n, U2FManager $manager) {
+ /** @var IAppContainer */
+ private $container;
+
+ public function __construct(IL10N $l10n,
+ U2FManager $manager,
+ IAppContainer $container) {
$this->l10n = $l10n;
$this->manager = $manager;
+ $this->container = $container;
}
/**
@@ -105,4 +113,13 @@ class U2FProvider implements IProvider, IProvidesIcons, IProvidesPersonalSetting
$this->manager->removeAllDevices($user);
}
+ /**
+ * @param IUser $user
+ *
+ * @return ILoginSetupProvider
+ */
+ public function getLoginSetup(IUser $user): ILoginSetupProvider {
+ return $this->container->query(U2FLoginProvider::class);
+ }
+
}
diff --git a/package-lock.json b/package-lock.json
index bd4e717..c571104 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -2813,7 +2813,6 @@
"version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz",
"integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=",
- "dev": true,
"requires": {
"chalk": "^1.1.3",
"esutils": "^2.0.2",
@@ -2823,20 +2822,17 @@
"ansi-regex": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
- "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
- "dev": true
+ "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
},
"ansi-styles": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
- "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
- "dev": true
+ "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4="
},
"chalk": {
"version": "1.1.3",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
- "dev": true,
"requires": {
"ansi-styles": "^2.2.1",
"escape-string-regexp": "^1.0.2",
@@ -2848,14 +2844,12 @@
"js-tokens": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz",
- "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=",
- "dev": true
+ "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls="
},
"strip-ansi": {
"version": "3.0.1",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+ "resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
- "dev": true,
"requires": {
"ansi-regex": "^2.0.0"
}
@@ -2863,8 +2857,7 @@
"supports-color": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
- "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
- "dev": true
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc="
}
}
},
@@ -2898,6 +2891,27 @@
}
}
},
+ "babel-helper-function-name": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz",
+ "integrity": "sha1-00dbjAPtmCQqJbSDUasYOZ01gKk=",
+ "requires": {
+ "babel-helper-get-function-arity": "^6.24.1",
+ "babel-runtime": "^6.22.0",
+ "babel-template": "^6.24.1",
+ "babel-traverse": "^6.24.1",
+ "babel-types": "^6.24.1"
+ }
+ },
+ "babel-helper-get-function-arity": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz",
+ "integrity": "sha1-j3eCqpNAfEHTqlCQj4mwMbG2hT0=",
+ "requires": {
+ "babel-runtime": "^6.22.0",
+ "babel-types": "^6.24.1"
+ }
+ },
"babel-loader": {
"version": "8.0.6",
"resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.0.6.tgz",
@@ -2922,7 +2936,6 @@
"version": "6.23.0",
"resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz",
"integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=",
- "dev": true,
"requires": {
"babel-runtime": "^6.22.0"
}
@@ -3132,11 +3145,26 @@
"resolve": "^1.4.0"
}
},
+ "babel-plugin-syntax-class-properties": {
+ "version": "6.13.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz",
+ "integrity": "sha1-1+sjt5oxf4VDlixQW4J8fWysJ94="
+ },
+ "babel-plugin-transform-class-properties": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.24.1.tgz",
+ "integrity": "sha1-anl2PqYdM9NvN7YRqp3vgagbRqw=",
+ "requires": {
+ "babel-helper-function-name": "^6.24.1",
+ "babel-plugin-syntax-class-properties": "^6.8.0",
+ "babel-runtime": "^6.22.0",
+ "babel-template": "^6.24.1"
+ }
+ },
"babel-runtime": {
"version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
"integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=",
- "dev": true,
"requires": {
"core-js": "^2.4.0",
"regenerator-runtime": "^0.11.0"
@@ -3146,7 +3174,6 @@
"version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz",
"integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=",
- "dev": true,
"requires": {
"babel-runtime": "^6.26.0",
"babel-traverse": "^6.26.0",
@@ -3158,8 +3185,7 @@
"babylon": {
"version": "6.18.0",
"resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz",
- "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==",
- "dev": true
+ "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ=="
}
}
},
@@ -3167,7 +3193,6 @@
"version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz",
"integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=",
- "dev": true,
"requires": {
"babel-code-frame": "^6.26.0",
"babel-messages": "^6.23.0",
@@ -3183,14 +3208,12 @@
"babylon": {
"version": "6.18.0",
"resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz",
- "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==",
- "dev": true
+ "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ=="
},
"globals": {
"version": "9.18.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz",
- "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==",
- "dev": true
+ "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ=="
}
}
},
@@ -3198,7 +3221,6 @@
"version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz",
"integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=",
- "dev": true,
"requires": {
"babel-runtime": "^6.26.0",
"esutils": "^2.0.2",
@@ -3209,8 +3231,7 @@
"to-fast-properties": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz",
- "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=",
- "dev": true
+ "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc="
}
}
},
@@ -3616,9 +3637,9 @@
"dev": true
},
"semver": {
- "version": "5.7.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz",
- "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==",
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+ "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
"dev": true
}
}
@@ -3999,8 +4020,7 @@
"core-js": {
"version": "2.5.7",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz",
- "integrity": "sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw==",
- "dev": true
+ "integrity": "sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw=="
},
"core-js-compat": {
"version": "3.1.4",
@@ -4291,7 +4311,6 @@
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
- "dev": true,
"requires": {
"ms": "2.0.0"
}
@@ -4580,8 +4599,7 @@
"escape-string-regexp": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
- "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
- "dev": true
+ "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
},
"escodegen": {
"version": "1.11.1",
@@ -4630,8 +4648,7 @@
"esutils": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz",
- "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=",
- "dev": true
+ "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs="
},
"events": {
"version": "3.0.0",
@@ -5857,7 +5874,6 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
"integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=",
- "dev": true,
"requires": {
"ansi-regex": "^2.0.0"
},
@@ -5865,8 +5881,7 @@
"ansi-regex": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
- "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
- "dev": true
+ "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
}
}
},
@@ -6157,7 +6172,6 @@
"version": "2.2.4",
"resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
"integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
- "dev": true,
"requires": {
"loose-envify": "^1.0.0"
}
@@ -6477,9 +6491,9 @@
"dev": true
},
"semver": {
- "version": "5.7.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz",
- "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==",
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+ "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
"dev": true
},
"supports-color": {
@@ -6544,9 +6558,9 @@
"dev": true
},
"semver": {
- "version": "5.7.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz",
- "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==",
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+ "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
"dev": true
}
}
@@ -6569,8 +6583,7 @@
"js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
- "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
- "dev": true
+ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
},
"js-yaml": {
"version": "3.13.1",
@@ -6587,6 +6600,24 @@
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
"dev": true
+ },
+ "istanbul-lib-coverage": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz",
+ "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA=="
+ },
+ "make-dir": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz",
+ "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==",
+ "requires": {
+ "pify": "^4.0.1"
+ }
+ },
+ "pify": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
+ "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="
}
}
},
@@ -6835,7 +6866,6 @@
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
- "dev": true,
"requires": {
"js-tokens": "^3.0.0 || ^4.0.0"
}
@@ -7053,7 +7083,7 @@
},
"minimist": {
"version": "1.2.0",
- "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
+ "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
"dev": true
},
@@ -7113,9 +7143,9 @@
}
},
"mixin-deep": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz",
- "integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==",
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz",
+ "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==",
"dev": true,
"requires": {
"for-in": "^1.0.2",
@@ -7171,7 +7201,7 @@
"dependencies": {
"commander": {
"version": "2.15.1",
- "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz",
+ "resolved": "http://registry.npmjs.org/commander/-/commander-2.15.1.tgz",
"integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==",
"dev": true
},
@@ -7289,7 +7319,7 @@
},
"yargs": {
"version": "11.1.0",
- "resolved": "https://registry.npmjs.org/yargs/-/yargs-11.1.0.tgz",
+ "resolved": "http://registry.npmjs.org/yargs/-/yargs-11.1.0.tgz",
"integrity": "sha512-NwW69J42EsCSanF8kyn5upxvjp5ds+t3+udGBeTbFnERA+lF541DDpMawzo4z6W/QrzNM18D+BPMiOBibnFV5A==",
"dev": true,
"requires": {
@@ -7396,6 +7426,21 @@
"integrity": "sha512-AO81vsIO1k1sM4Zrd6Hu7regmJN1NSiAja10gc4bX3F0wd+9rQmcuHQaHVQCYIEC8iFXnE+mavh23GOt7wBgug==",
"dev": true
},
+ "nextcloud-auth": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/nextcloud-auth/-/nextcloud-auth-0.0.3.tgz",
+ "integrity": "sha512-qEAl55QJg2gZZIpfin9NzCPWm/Mfbo+HOdaXpsastPZw8oA7YLFFZon3x6SQ/p/LVIPQzRZmMpjd8R2FAAbjzg==",
+ "requires": {
+ "core-js": "^3.1.4"
+ },
+ "dependencies": {
+ "core-js": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.2.0.tgz",
+ "integrity": "sha512-gybgLzmr7SQRSF6UzGYXducx4eE10ONQlyEnQoqiGPbmbn7zLkb73tPfc4YbZN0lvcTQwoLNPjq4RuCaCumGyQ=="
+ }
+ }
+ },
"nextcloud-axios": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/nextcloud-axios/-/nextcloud-axios-0.2.0.tgz",
@@ -7404,6 +7449,22 @@
"axios": "^0.19.0"
}
},
+ "nextcloud-logger": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/nextcloud-logger/-/nextcloud-logger-0.0.3.tgz",
+ "integrity": "sha512-bTCSzISptSPeZDdM030rc3M2wH2YEysBslSTmDmxwAlKZlBiDaca/swYfUO0y/fnxMfZuLh6Odr1EJXLgFVSrQ==",
+ "requires": {
+ "babel-plugin-transform-class-properties": "^6.24.1",
+ "core-js": "^3.1.4"
+ },
+ "dependencies": {
+ "core-js": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.2.0.tgz",
+ "integrity": "sha512-gybgLzmr7SQRSF6UzGYXducx4eE10ONQlyEnQoqiGPbmbn7zLkb73tPfc4YbZN0lvcTQwoLNPjq4RuCaCumGyQ=="
+ }
+ }
+ },
"nextcloud-password-confirmation": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/nextcloud-password-confirmation/-/nextcloud-password-confirmation-0.4.1.tgz",
@@ -8674,8 +8735,7 @@
"regenerator-runtime": {
"version": "0.11.1",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz",
- "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==",
- "dev": true
+ "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg=="
},
"regenerator-transform": {
"version": "0.14.0",
@@ -9018,9 +9078,9 @@
"dev": true
},
"set-value": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz",
- "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==",
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz",
+ "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==",
"dev": true,
"requires": {
"extend-shallow": "^2.0.1",
@@ -9891,38 +9951,15 @@
"dev": true
},
"union-value": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz",
- "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=",
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz",
+ "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==",
"dev": true,
"requires": {
"arr-union": "^3.1.0",
"get-value": "^2.0.6",
"is-extendable": "^0.1.1",
- "set-value": "^0.4.3"
- },
- "dependencies": {
- "extend-shallow": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
- "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
- "dev": true,
- "requires": {
- "is-extendable": "^0.1.0"
- }
- },
- "set-value": {
- "version": "0.4.3",
- "resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz",
- "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=",
- "dev": true,
- "requires": {
- "extend-shallow": "^2.0.1",
- "is-extendable": "^0.1.1",
- "is-plain-object": "^2.0.1",
- "to-object-path": "^0.3.0"
- }
- }
+ "set-value": "^2.0.1"
}
},
"uniq": {
@@ -10595,7 +10632,7 @@
},
"strip-ansi": {
"version": "3.0.1",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+ "resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
"dev": true,
"requires": {
diff --git a/package.json b/package.json
index 45df398..6a5fa49 100644
--- a/package.json
+++ b/package.json
@@ -4,7 +4,9 @@
"description": "U2F second factor provider for Nextcloud",
"private": true,
"dependencies": {
+ "nextcloud-auth": "0.0.3",
"nextcloud-axios": "^0.2.0",
+ "nextcloud-logger": "0.0.3",
"nextcloud-password-confirmation": "^0.4.1",
"nextcloud-router": "0.0.6",
"nextcloud-vue": "^0.12.1",
diff --git a/src/components/AddDeviceDialog.vue b/src/components/AddDeviceDialog.vue
index 8a72126..78c5e8f 100644
--- a/src/components/AddDeviceDialog.vue
+++ b/src/components/AddDeviceDialog.vue
@@ -56,16 +56,26 @@
import confirmPassword from 'nextcloud-password-confirmation'
import u2f from 'u2f-api'
+ import logger from '../logger'
+
import {
startRegistration,
finishRegistration
} from '../services/RegistrationService'
const logAndPass = (text) => (data) => {
- console.debug(text)
+ logger.debug(text)
return data
}
+ /**
+ * Tap into a promise without losing the value
+ */
+ const tap = cb => val => {
+ cb(val)
+ return val
+ }
+
const RegistrationSteps = Object.freeze({
READY: 1,
U2F_REGISTRATION: 2,
@@ -94,23 +104,23 @@
.then(this.getRegistrationData)
.then(this.register)
.then(() => this.step = RegistrationSteps.NAMING)
- .catch(console.error.bind(this))
+ .catch(logger.error.bind(logger))
},
getRegistrationData () {
return startRegistration()
.catch(err => {
- console.error('Error getting u2f registration data from server', err)
+ logger.error('Error getting u2f registration data from server', err)
throw new Error(t('twofactor_u2f', 'Server error while trying to add U2F device'))
})
},
register ({req, sigs}) {
- console.debug('starting u2f registration')
+ logger.debug('starting registration')
return u2f.register([req], sigs)
.then(data => {
- console.debug('u2f registration was successful', data)
+ logger.debug('registration was successful', data)
if (data.errorCode && data.errorCode !== 0) {
return this.rejectRegistration(data)
@@ -118,6 +128,7 @@
this.registrationData = data
})
+ .catch(e => this.rejectRegistration(e))
},
rejectRegistration (data) {
@@ -148,24 +159,29 @@
submit () {
this.step = RegistrationSteps.PERSIST
+ logger.debug('persisting registration on server')
+
return confirmPassword()
.then(logAndPass('confirmed password'))
.then(this.saveRegistrationData)
.then(logAndPass('registration data saved'))
+ .then(tap(() => this.$emit('add')))
.then(() => this.reset())
.then(logAndPass('app reset'))
- .catch(console.error.bind(this))
+ .catch(logger.error.bind(logger))
},
saveRegistrationData () {
const data = this.registrationData
data.name = this.name
+ logger.debug('saving registration data', {data})
+
return finishRegistration(data)
.then(device => this.$store.commit('addDevice', device))
.then(logAndPass('new device added to store'))
.catch(err => {
- console.error('Error persisting u2f registration', err)
+ logger.error('Error persisting registration', err)
throw new Error(t('twofactor_u2f', 'Server error while trying to complete U2F device registration'))
})
},
@@ -190,4 +206,4 @@
.new-u2f-device {
line-height: 300%;
}
-</style> \ No newline at end of file
+</style>
diff --git a/src/components/LoginSetup.vue b/src/components/LoginSetup.vue
new file mode 100644
index 0000000..537beb5
--- /dev/null
+++ b/src/components/LoginSetup.vue
@@ -0,0 +1,69 @@
+<!--
+ - @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ -
+ - @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ -
+ - @license GNU AGPL version 3 or any later version
+ -
+ - This program is free software: you can redistribute it and/or modify
+ - it under the terms of the GNU Affero General Public License as
+ - published by the Free Software Foundation, either version 3 of the
+ - License, or (at your option) any later version.
+ -
+ - 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
+ - along with this program. If not, see <http://www.gnu.org/licenses/>.
+ -->
+
+<template>
+ <div>
+ <!-- TODO: at some explanatory text about what this page is about -->
+ <AddDeviceDialog v-if="!added"
+ :httpWarning="httpWarning"
+ @add="onAdded" />
+ <p v-if="notSupported">
+ {{ t('twofactor_u2f', 'Your browser does not support U2F.') }}
+ {{ t('twofactor_u2f', 'Chrome is the only browser that supports U2F devices. You need to install the "U2F Support Add-on" on Firefox to use U2F.') }}
+ </p>
+ <p v-if="httpWarning"
+ id="u2f-http-warning">
+ {{ t('twofactor_u2f', 'You are accessing this site via an insecure connection. Browsers might therefore refuse the U2F authentication.') }}
+ </p>
+ <form ref="confirmForm" method="POST"></form>
+ </div>
+</template>
+
+<script>
+ import u2f from 'u2f-api'
+
+ import AddDeviceDialog from './AddDeviceDialog'
+ import Device from './Device'
+
+ export default {
+ name: 'PersonalSettings',
+ props: {
+ httpWarning: Boolean
+ },
+ components: {
+ AddDeviceDialog,
+ Device
+ },
+ data() {
+ return {
+ added: false,
+ notSupported: !u2f.isSupported()
+ }
+ },
+ methods: {
+ onAdded() {
+ this.added = true
+
+ this.$refs.confirmForm.submit()
+ }
+ }
+ }
+</script>
diff --git a/src/logger.js b/src/logger.js
new file mode 100644
index 0000000..5efdf66
--- /dev/null
+++ b/src/logger.js
@@ -0,0 +1,32 @@
+/*
+ * @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * 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
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+import { getCurrentUser } from 'nextcloud-auth'
+import { getLoggerBuilder } from 'nextcloud-logger'
+
+const builder = getLoggerBuilder().setApp('twofactor_u2f')
+
+const user = getCurrentUser()
+if (user !== null) {
+ builder.setUid(user.uid)
+}
+
+export default builder.build()
diff --git a/src/main-login-setup.js b/src/main-login-setup.js
new file mode 100644
index 0000000..2a27a6c
--- /dev/null
+++ b/src/main-login-setup.js
@@ -0,0 +1,37 @@
+/*
+ * @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * 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
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+import Vue from 'vue'
+
+import Nextcloud from './mixins/Nextcloud'
+import store from './store'
+
+Vue.mixin(Nextcloud)
+
+import LoginSetup from './components/LoginSetup'
+
+const View = Vue.extend(LoginSetup)
+new View({
+ propsData: {
+ httpWarning: document.location.protocol !== 'https:',
+ },
+ store,
+}).$mount('#twofactor-u2f-login-setup')
diff --git a/src/tests/setup.js b/src/tests/setup.js
index 59a3c57..451b349 100644
--- a/src/tests/setup.js
+++ b/src/tests/setup.js
@@ -30,7 +30,11 @@ require('vue').mixin({
})
global.expect = require('chai').expect
-global.OC = {}
+global.OC = {
+ getCurrentUser: () => {
+ return { uid: false }
+ },
+}
global.t = t
// https://github.com/vuejs/vue-test-utils/issues/936
diff --git a/src/webpack.common.js b/src/webpack.common.js
index 4940550..8dc3d21 100644
--- a/src/webpack.common.js
+++ b/src/webpack.common.js
@@ -4,7 +4,8 @@ const { VueLoaderPlugin } = require('vue-loader');
module.exports = {
entry: {
challenge: path.join(__dirname, 'main-challenge.js'),
- settings: path.join(__dirname, 'main-settings.js')
+ 'login-setup': path.join(__dirname, 'main-login-setup.js'),
+ settings: path.join(__dirname, 'main-settings.js'),
},
output: {
path: path.resolve(__dirname, '../js'),
diff --git a/templates/loginsetup.php b/templates/loginsetup.php
new file mode 100644
index 0000000..d603f0a
--- /dev/null
+++ b/templates/loginsetup.php
@@ -0,0 +1,28 @@
+<?php declare(strict_types=1);
+
+/**
+ * @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * 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
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+script('twofactor_u2f', 'login-setup');
+
+?>
+
+<div id="twofactor-u2f-login-setup"></div>
diff --git a/tests/Unit/Provider/U2FProviderTest.php b/tests/Unit/Provider/U2FProviderTest.php
index b6f99c6..6f6df28 100644
--- a/tests/Unit/Provider/U2FProviderTest.php
+++ b/tests/Unit/Provider/U2FProviderTest.php
@@ -12,9 +12,11 @@
namespace OCA\TwoFactorU2F\Tests\Unit\Provider;
+use OCA\TwoFactorU2F\Provider\U2FLoginProvider;
use OCA\TwoFactorU2F\Provider\U2FProvider;
use OCA\TwoFactorU2F\Service\U2FManager;
use OCA\TwoFactorU2F\Settings\Personal;
+use OCP\AppFramework\IAppContainer;
use OCP\IL10N;
use OCP\IUser;
use OCP\Template;
@@ -29,6 +31,9 @@ class U2FProviderTest extends TestCase {
/** @var U2FManager|MockObject */
private $manager;
+ /** @var IAppContainer|MockObject */
+ private $container;
+
/** @var U2FProvider */
private $provider;
@@ -37,8 +42,13 @@ class U2FProviderTest extends TestCase {
$this->l10n = $this->createMock(IL10N::class);
$this->manager = $this->createMock(U2FManager::class);
+ $this->container = $this->createMock(IAppContainer::class);
- $this->provider = new U2FProvider($this->l10n, $this->manager);
+ $this->provider = new U2FProvider(
+ $this->l10n,
+ $this->manager,
+ $this->container
+ );
}
public function testGetId() {
@@ -148,4 +158,17 @@ class U2FProviderTest extends TestCase {
$this->provider->disableFor($user);
}
+ public function testGet() {
+ $user = $this->createMock(IUser::class);
+ $loginProvider = $this->createMock(U2FLoginProvider::class);
+ $this->container->expects($this->once())
+ ->method('query')
+ ->with(U2FLoginProvider::class)
+ ->willReturn($loginProvider);
+
+ $result = $this->provider->getLoginSetup($user);
+
+ $this->assertSame($loginProvider, $result);
+ }
+
}