15 |
--------------------------------------------------------------------------------
/l10n/es_AR.json:
--------------------------------------------------------------------------------
1 | { "translations": {
2 | "Add" : "Añadir",
3 | "Retry" : "Reintentar",
4 | "An error occurred. Please try again." : "Se presentó un erorr. Favor de volver a intentar. ",
5 | "Your browser does not support WebAuthn." : "Tu navegador no admite WebAuthn.",
6 | "Remove" : "Borrar"
7 | },"pluralForm" :"nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;"
8 | }
--------------------------------------------------------------------------------
/.tx/config:
--------------------------------------------------------------------------------
1 | [main]
2 | host = https://www.transifex.com
3 | lang_map = nb_NO: nb, sk_SK: sk, th_TH: th, ja_JP: ja, bg_BG: bg, cs_CZ: cs, fi_FI: fi, hu_HU: hu
4 |
5 | [o:nextcloud:p:nextcloud:r:twofactor_webauthn]
6 | file_filter = translationfiles//twofactor_webauthn.po
7 | source_file = translationfiles/templates/twofactor_webauthn.pot
8 | source_lang = en
9 | type = PO
10 |
11 |
--------------------------------------------------------------------------------
/l10n/oc.json:
--------------------------------------------------------------------------------
1 | { "translations": {
2 | "Add" : "Apondre",
3 | "Retry" : "Tornar ensajar",
4 | "An error occurred. Please try again." : "Una error s'es producha. Mercé d'ensajar tornamai.",
5 | "Your browser does not support WebAuthn." : "Vòstre navigador es pas compatible amb WebAuthn.",
6 | "Active" : "Activa",
7 | "Remove" : "Suprimir"
8 | },"pluralForm" :"nplurals=2; plural=(n > 1);"
9 | }
--------------------------------------------------------------------------------
/l10n/da.json:
--------------------------------------------------------------------------------
1 | { "translations": {
2 | "Add" : "Tilføj",
3 | "An error occurred: {msg}" : "Der skete en fejl: {msg}",
4 | "Retry" : "Prøv igen",
5 | "An error occurred. Please try again." : "En fejl opstod. Prøv venligst igen.",
6 | "Your browser does not support WebAuthn." : "Din browser understøtter ikke WebAuthn.",
7 | "Remove" : "Fjern"
8 | },"pluralForm" :"nplurals=2; plural=(n != 1);"
9 | }
--------------------------------------------------------------------------------
/l10n/es_MX.json:
--------------------------------------------------------------------------------
1 | { "translations": {
2 | "Add" : "Agregar",
3 | "Retry" : "Reintentar",
4 | "An error occurred. Please try again." : "Se presentó un error. Por favor vuelve a intentarlo.",
5 | "Your browser does not support WebAuthn." : "Su navegador no soporta WebAuthn.",
6 | "Active" : "Activo",
7 | "Remove" : "Eliminar"
8 | },"pluralForm" :"nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;"
9 | }
--------------------------------------------------------------------------------
/l10n/es_AR.js:
--------------------------------------------------------------------------------
1 | OC.L10N.register(
2 | "twofactor_webauthn",
3 | {
4 | "Add" : "Añadir",
5 | "Retry" : "Reintentar",
6 | "An error occurred. Please try again." : "Se presentó un erorr. Favor de volver a intentar. ",
7 | "Your browser does not support WebAuthn." : "Tu navegador no admite WebAuthn.",
8 | "Remove" : "Borrar"
9 | },
10 | "nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;");
11 |
--------------------------------------------------------------------------------
/l10n/ko.json:
--------------------------------------------------------------------------------
1 | { "translations": {
2 | "Add" : "추가",
3 | "Authentication cancelled" : "인증이 취소됨",
4 | "An error occurred: {msg}" : "오류 발생: {msg}",
5 | "Retry" : "다시 시도",
6 | "An error occurred. Please try again." : "오류가 발생했습니다. 다시 시도하십시오.",
7 | "Your browser does not support WebAuthn." : "WebAuthn이 현재 브라우저를 지원하지 않습니다.",
8 | "Active" : "활성화",
9 | "Remove" : "삭제"
10 | },"pluralForm" :"nplurals=1; plural=0;"
11 | }
--------------------------------------------------------------------------------
/l10n/oc.js:
--------------------------------------------------------------------------------
1 | OC.L10N.register(
2 | "twofactor_webauthn",
3 | {
4 | "Add" : "Apondre",
5 | "Retry" : "Tornar ensajar",
6 | "An error occurred. Please try again." : "Una error s'es producha. Mercé d'ensajar tornamai.",
7 | "Your browser does not support WebAuthn." : "Vòstre navigador es pas compatible amb WebAuthn.",
8 | "Active" : "Activa",
9 | "Remove" : "Suprimir"
10 | },
11 | "nplurals=2; plural=(n > 1);");
12 |
--------------------------------------------------------------------------------
/.git-blame-ignore-revs:
--------------------------------------------------------------------------------
1 | # .git-blame-ignore-revs
2 |
3 | # SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
4 | # SPDX-License-Identifier: AGPL-3.0-or-later
5 |
6 | # Update to coding-standard 1.2.3
7 | 58601e8ebae5dd35ba2f97c343e8b4b03a810a57
8 |
9 | # Update to coding-standard 1.3.1
10 | 0a21189522498b47aa657834e259d2a6fbccb0a5
11 |
12 | # Update to coding-standard 1.3.2
13 | 5b2440c618b9a90cd6ee89f2c1d97776fea38235
14 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors
2 | # SPDX-License-Identifier: AGPL-3.0-or-later
3 | /build
4 | /js
5 |
6 | /coverage
7 | /.nyc_output
8 | /node_modules
9 |
10 | /nbproject/private/
11 | /vendor
12 | /vendor-bin/*/vendor
13 | composer.phar
14 | /.php-cs-fixer.cache
15 |
16 | /tests/clover*.xml
17 | /tests/.phpunit.result.cache
18 |
19 | /playwright
20 | /playwright-report
21 | /test-results
22 |
--------------------------------------------------------------------------------
/l10n/da.js:
--------------------------------------------------------------------------------
1 | OC.L10N.register(
2 | "twofactor_webauthn",
3 | {
4 | "Add" : "Tilføj",
5 | "An error occurred: {msg}" : "Der skete en fejl: {msg}",
6 | "Retry" : "Prøv igen",
7 | "An error occurred. Please try again." : "En fejl opstod. Prøv venligst igen.",
8 | "Your browser does not support WebAuthn." : "Din browser understøtter ikke WebAuthn.",
9 | "Remove" : "Fjern"
10 | },
11 | "nplurals=2; plural=(n != 1);");
12 |
--------------------------------------------------------------------------------
/l10n/sc.json:
--------------------------------------------------------------------------------
1 | { "translations": {
2 | "Add" : "Agiunghe",
3 | "An error occurred: {msg}" : "B'at àpidu un'errore: {msg}",
4 | "Retry" : "Torra a proare",
5 | "An error occurred. Please try again." : "B'at àpidu un'errore. Torra a proare.",
6 | "Your browser does not support WebAuthn." : "Su serbidore tuo non suportat WebAuthn.",
7 | "Active" : "Ativu",
8 | "Remove" : "Boga"
9 | },"pluralForm" :"nplurals=2; plural=(n != 1);"
10 | }
--------------------------------------------------------------------------------
/l10n/es_MX.js:
--------------------------------------------------------------------------------
1 | OC.L10N.register(
2 | "twofactor_webauthn",
3 | {
4 | "Add" : "Agregar",
5 | "Retry" : "Reintentar",
6 | "An error occurred. Please try again." : "Se presentó un error. Por favor vuelve a intentarlo.",
7 | "Your browser does not support WebAuthn." : "Su navegador no soporta WebAuthn.",
8 | "Active" : "Activo",
9 | "Remove" : "Eliminar"
10 | },
11 | "nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;");
12 |
--------------------------------------------------------------------------------
/l10n/ko.js:
--------------------------------------------------------------------------------
1 | OC.L10N.register(
2 | "twofactor_webauthn",
3 | {
4 | "Add" : "추가",
5 | "Authentication cancelled" : "인증이 취소됨",
6 | "An error occurred: {msg}" : "오류 발생: {msg}",
7 | "Retry" : "다시 시도",
8 | "An error occurred. Please try again." : "오류가 발생했습니다. 다시 시도하십시오.",
9 | "Your browser does not support WebAuthn." : "WebAuthn이 현재 브라우저를 지원하지 않습니다.",
10 | "Active" : "활성화",
11 | "Remove" : "삭제"
12 | },
13 | "nplurals=1; plural=0;");
14 |
--------------------------------------------------------------------------------
/l10n/he.json:
--------------------------------------------------------------------------------
1 | { "translations": {
2 | "Add" : "הוספה",
3 | "An error occurred: {msg}" : "אירעה שגיאה: {msg}",
4 | "Retry" : "ניסיון חוזר",
5 | "An error occurred. Please try again." : "אירעה שגיאה. נא לנסות שוב.",
6 | "Your browser does not support WebAuthn." : "הדפדפן שלך אינו תומך ב־WebAuthn.",
7 | "Active" : "פעיל",
8 | "Remove" : "הסרה"
9 | },"pluralForm" :"nplurals=3; plural=(n == 1 && n % 1 == 0) ? 0 : (n == 2 && n % 1 == 0) ? 1: 2;"
10 | }
--------------------------------------------------------------------------------
/l10n/sc.js:
--------------------------------------------------------------------------------
1 | OC.L10N.register(
2 | "twofactor_webauthn",
3 | {
4 | "Add" : "Agiunghe",
5 | "An error occurred: {msg}" : "B'at àpidu un'errore: {msg}",
6 | "Retry" : "Torra a proare",
7 | "An error occurred. Please try again." : "B'at àpidu un'errore. Torra a proare.",
8 | "Your browser does not support WebAuthn." : "Su serbidore tuo non suportat WebAuthn.",
9 | "Active" : "Ativu",
10 | "Remove" : "Boga"
11 | },
12 | "nplurals=2; plural=(n != 1);");
13 |
--------------------------------------------------------------------------------
/src/logger.js:
--------------------------------------------------------------------------------
1 | /**
2 | * SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors
3 | * SPDX-License-Identifier: AGPL-3.0-or-later
4 | */
5 |
6 | import { getCurrentUser } from '@nextcloud/auth'
7 | import { getLoggerBuilder } from '@nextcloud/logger'
8 |
9 | const builder = getLoggerBuilder().setApp('twofactor_webauthn')
10 |
11 | const user = getCurrentUser()
12 | if (user !== null) {
13 | builder.setUid(user.uid)
14 | }
15 |
16 | export default builder.build()
17 |
--------------------------------------------------------------------------------
/l10n/es_419.json:
--------------------------------------------------------------------------------
1 | { "translations": {
2 | "You added an WebAuthn hardware token" : "Agregaste un token de hardware WebAuthn ",
3 | "You removed an WebAuthn hardware token" : "Removiste un token de hardware WebAuthn ",
4 | "Add" : "Agregar",
5 | "Retry" : "Reintentar",
6 | "An error occurred. Please try again." : "Se presentó un erorr. Por favor vuelve a intentarlo.",
7 | "Remove" : "Eliminar"
8 | },"pluralForm" :"nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;"
9 | }
--------------------------------------------------------------------------------
/l10n/he.js:
--------------------------------------------------------------------------------
1 | OC.L10N.register(
2 | "twofactor_webauthn",
3 | {
4 | "Add" : "הוספה",
5 | "An error occurred: {msg}" : "אירעה שגיאה: {msg}",
6 | "Retry" : "ניסיון חוזר",
7 | "An error occurred. Please try again." : "אירעה שגיאה. נא לנסות שוב.",
8 | "Your browser does not support WebAuthn." : "הדפדפן שלך אינו תומך ב־WebAuthn.",
9 | "Active" : "פעיל",
10 | "Remove" : "הסרה"
11 | },
12 | "nplurals=3; plural=(n == 1 && n % 1 == 0) ? 0 : (n == 2 && n % 1 == 0) ? 1: 2;");
13 |
--------------------------------------------------------------------------------
/l10n/sl.json:
--------------------------------------------------------------------------------
1 | { "translations": {
2 | "Add" : "Dodaj",
3 | "An error occurred: {msg}" : "Prišlo je do napake: {msg}",
4 | "Retry" : "Poskusi znova",
5 | "An error occurred. Please try again." : "Prišlo je do napake. Poskusite znova.",
6 | "Your browser does not support WebAuthn." : "Brskalnik ne podpira overitve WebAuthn.",
7 | "Active" : "Dejavno",
8 | "Remove" : "Odstrani"
9 | },"pluralForm" :"nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3);"
10 | }
--------------------------------------------------------------------------------
/tests/bootstrap.php:
--------------------------------------------------------------------------------
1 | loadApp('twofactor_webauthn');
18 |
--------------------------------------------------------------------------------
/l10n/hr.json:
--------------------------------------------------------------------------------
1 | { "translations": {
2 | "Add" : "Dodaj",
3 | "An error occurred: {msg}" : "Došlo je do pogreške: {msg}",
4 | "Retry" : "Pokušaj ponovno",
5 | "An error occurred. Please try again." : "Došlo je do pogreške. Pokušajte ponovo.",
6 | "Your browser does not support WebAuthn." : "Vaš preglednik ne podržava WebAuthn.",
7 | "Active" : "Aktivan",
8 | "Remove" : "Ukloni"
9 | },"pluralForm" :"nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;"
10 | }
--------------------------------------------------------------------------------
/l10n/es_419.js:
--------------------------------------------------------------------------------
1 | OC.L10N.register(
2 | "twofactor_webauthn",
3 | {
4 | "You added an WebAuthn hardware token" : "Agregaste un token de hardware WebAuthn ",
5 | "You removed an WebAuthn hardware token" : "Removiste un token de hardware WebAuthn ",
6 | "Add" : "Agregar",
7 | "Retry" : "Reintentar",
8 | "An error occurred. Please try again." : "Se presentó un erorr. Por favor vuelve a intentarlo.",
9 | "Remove" : "Eliminar"
10 | },
11 | "nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;");
12 |
--------------------------------------------------------------------------------
/l10n/sl.js:
--------------------------------------------------------------------------------
1 | OC.L10N.register(
2 | "twofactor_webauthn",
3 | {
4 | "Add" : "Dodaj",
5 | "An error occurred: {msg}" : "Prišlo je do napake: {msg}",
6 | "Retry" : "Poskusi znova",
7 | "An error occurred. Please try again." : "Prišlo je do napake. Poskusite znova.",
8 | "Your browser does not support WebAuthn." : "Brskalnik ne podpira overitve WebAuthn.",
9 | "Active" : "Dejavno",
10 | "Remove" : "Odstrani"
11 | },
12 | "nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3);");
13 |
--------------------------------------------------------------------------------
/src/main-login-setup.js:
--------------------------------------------------------------------------------
1 | /**
2 | * SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors
3 | * SPDX-License-Identifier: AGPL-3.0-or-later
4 | */
5 |
6 | import { createApp } from 'vue'
7 | import { createPinia } from 'pinia'
8 |
9 | import Nextcloud from './mixins/Nextcloud.js'
10 |
11 | import LoginSetup from './components/LoginSetup.vue'
12 |
13 | const pinia = createPinia()
14 |
15 | const app = createApp(LoginSetup)
16 | app.mixin(Nextcloud)
17 | app.use(pinia)
18 | app.mount('#twofactor-webauthn-login-setup')
19 |
--------------------------------------------------------------------------------
/webpack.test.config.js:
--------------------------------------------------------------------------------
1 | /**
2 | * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
3 | * SPDX-License-Identifier: AGPL-3.0-or-later
4 | */
5 |
6 | const webpackConfig = require('./webpack.config.js')
7 |
8 | // For some reason mocha(pack) fails to import webpack chunks because they have a ?v=[contenthash]
9 | // suffix that is not actually present in names of written entrypoints.
10 | webpackConfig.output.filename = webpackConfig.output.filename.replace('?v=[contenthash]', '')
11 |
12 | module.exports = webpackConfig
13 |
--------------------------------------------------------------------------------
/lib/Settings/Personal.php:
--------------------------------------------------------------------------------
1 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/l10n/hr.js:
--------------------------------------------------------------------------------
1 | OC.L10N.register(
2 | "twofactor_webauthn",
3 | {
4 | "Add" : "Dodaj",
5 | "An error occurred: {msg}" : "Došlo je do pogreške: {msg}",
6 | "Retry" : "Pokušaj ponovno",
7 | "An error occurred. Please try again." : "Došlo je do pogreške. Pokušajte ponovo.",
8 | "Your browser does not support WebAuthn." : "Vaš preglednik ne podržava WebAuthn.",
9 | "Active" : "Aktivan",
10 | "Remove" : "Ukloni"
11 | },
12 | "nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;");
13 |
--------------------------------------------------------------------------------
/templates/login-setup.php:
--------------------------------------------------------------------------------
1 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/css/style.css:
--------------------------------------------------------------------------------
1 | /**
2 | * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors
3 | * SPDX-License-Identifier: AGPL-3.0-or-later
4 | */
5 |
6 | /** icons for personal page settings **/
7 | .nav-icon-webauthn-second-factor-auth, .icon-webauthn-device {
8 | background-image: url('../img/app-dark.svg?v=1');
9 | }
10 |
11 | body.theme--dark .nav-icon-webauthn-second-factor-auth,
12 | body.theme--dark .icon-webauthn-device {
13 | background-image: url('../img/app.svg?v=1');
14 | }
15 |
16 | #webauthn-http-warning {
17 | color: var(--color-warning);
18 | }
19 |
--------------------------------------------------------------------------------
/l10n/br.json:
--------------------------------------------------------------------------------
1 | { "translations": {
2 | "Add" : "Ouzhpennañ",
3 | "Retry" : "Klaskit en dro",
4 | "Your browser does not support WebAuthn." : "Ne vez ket douget WebAuthn gant o furcher.",
5 | "Active" : "O labourat",
6 | "Remove" : "Lemel"
7 | },"pluralForm" :"nplurals=5; plural=((n%10 == 1) && (n%100 != 11) && (n%100 !=71) && (n%100 !=91) ? 0 :(n%10 == 2) && (n%100 != 12) && (n%100 !=72) && (n%100 !=92) ? 1 :(n%10 ==3 || n%10==4 || n%10==9) && (n%100 < 10 || n% 100 > 19) && (n%100 < 70 || n%100 > 79) && (n%100 < 90 || n%100 > 99) ? 2 :(n != 0 && n % 1000000 == 0) ? 3 : 4);"
8 | }
--------------------------------------------------------------------------------
/.php-cs-fixer.dist.php:
--------------------------------------------------------------------------------
1 | getFinder()
17 | ->ignoreVCSIgnored(true)
18 | ->notPath('build')
19 | ->notPath('l10n')
20 | ->notPath('lib/Vendor')
21 | ->notPath('src')
22 | ->notPath('vendor')
23 | ->in(__DIR__);
24 | return $config;
25 |
--------------------------------------------------------------------------------
/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "camelcase": false,
3 | "eqeqeq": true,
4 | "immed": true,
5 | "latedef": false,
6 | "noarg": true,
7 | "nonbsp": true,
8 | "undef": true,
9 | "unused": true,
10 | "trailing": true,
11 | "maxparams": 5,
12 | "curly": true,
13 | "maxlen": 120,
14 | "indent": 4,
15 | "browser": true,
16 | "globals": {
17 | "t": true,
18 | "console": true,
19 | "it": true,
20 | "xit": true,
21 | "expect": true,
22 | "describe": true,
23 | "define": true,
24 | "beforeEach": true,
25 | "afterEach": true,
26 | "require": true
27 | },
28 | "esversion": 6,
29 | "asi": true
30 | }
31 |
--------------------------------------------------------------------------------
/l10n/be.json:
--------------------------------------------------------------------------------
1 | { "translations": {
2 | "You added an WebAuthn hardware token" : "Вы дадалі апаратны токен WebAuthn",
3 | "You removed an WebAuthn hardware token" : "Вы выдалілі апаратны токен WebAuthn",
4 | "Add" : "Дадаць",
5 | "Retry" : "Паўтарыць спробу",
6 | "Your browser does not support WebAuthn." : "Ваш браўзер не падтрымлівае WebAuthn.",
7 | "Active" : "Актыўны",
8 | "Remove" : "Выдаліць"
9 | },"pluralForm" :"nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);"
10 | }
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | /**
2 | * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
3 | * SPDX-License-Identifier: AGPL-3.0-or-later
4 | */
5 |
6 | const path = require('path')
7 | const webpackConfig = require('@nextcloud/webpack-vue-config')
8 |
9 | delete webpackConfig.entry['main']
10 | webpackConfig.entry['challenge'] = path.join(__dirname, 'src', 'main-challenge.js')
11 | webpackConfig.entry['settings'] = path.join(__dirname, 'src', 'main-settings.js')
12 | webpackConfig.entry['login-setup'] = path.join(__dirname, 'src', 'main-login-setup.js')
13 |
14 | module.exports = webpackConfig
15 |
--------------------------------------------------------------------------------
/l10n/br.js:
--------------------------------------------------------------------------------
1 | OC.L10N.register(
2 | "twofactor_webauthn",
3 | {
4 | "Add" : "Ouzhpennañ",
5 | "Retry" : "Klaskit en dro",
6 | "Your browser does not support WebAuthn." : "Ne vez ket douget WebAuthn gant o furcher.",
7 | "Active" : "O labourat",
8 | "Remove" : "Lemel"
9 | },
10 | "nplurals=5; plural=((n%10 == 1) && (n%100 != 11) && (n%100 !=71) && (n%100 !=91) ? 0 :(n%10 == 2) && (n%100 != 12) && (n%100 !=72) && (n%100 !=92) ? 1 :(n%10 ==3 || n%10==4 || n%10==9) && (n%100 < 10 || n% 100 > 19) && (n%100 < 70 || n%100 > 79) && (n%100 < 90 || n%100 > 99) ? 2 :(n != 0 && n % 1000000 == 0) ? 3 : 4);");
11 |
--------------------------------------------------------------------------------
/.scrutinizer.yml:
--------------------------------------------------------------------------------
1 | # SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors
2 | # SPDX-License-Identifier: AGPL-3.0-or-later
3 | build:
4 | nodes:
5 | analysis:
6 | tests:
7 | override:
8 | - php-scrutinizer-run --enable-security-analysis
9 |
10 | filter:
11 | excluded_paths:
12 | - 'js/tests/*'
13 | - 'vendor/*'
14 | - 'l10n/*'
15 | - 'tests/*'
16 |
17 | imports:
18 | - javascript
19 | - php
20 |
21 | tools:
22 | external_code_coverage:
23 | timeout: 600 # Timeout in seconds. 10 minutes
24 | runs: 1
25 |
--------------------------------------------------------------------------------
/l10n/be.js:
--------------------------------------------------------------------------------
1 | OC.L10N.register(
2 | "twofactor_webauthn",
3 | {
4 | "You added an WebAuthn hardware token" : "Вы дадалі апаратны токен WebAuthn",
5 | "You removed an WebAuthn hardware token" : "Вы выдалілі апаратны токен WebAuthn",
6 | "Add" : "Дадаць",
7 | "Retry" : "Паўтарыць спробу",
8 | "Your browser does not support WebAuthn." : "Ваш браўзер не падтрымлівае WebAuthn.",
9 | "Active" : "Актыўны",
10 | "Remove" : "Выдаліць"
11 | },
12 | "nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);");
13 |
--------------------------------------------------------------------------------
/lib/Provider/WebAuthnLoginProvider.php:
--------------------------------------------------------------------------------
1 | }
12 | */
13 | export async function login(page) {
14 | await page.goto('./index.php/login')
15 | await page.locator('#user').fill('admin')
16 | await page.locator('#password').fill('admin')
17 | await page.locator('#password').press('Enter')
18 |
19 | // Wait for login to finish
20 | await page.waitForURL('**/apps/**')
21 | }
22 |
--------------------------------------------------------------------------------
/l10n/lv.json:
--------------------------------------------------------------------------------
1 | { "translations": {
2 | "Security key" : "Drošības atslēga",
3 | "Add security key" : "Pievienot drošības atslēgu",
4 | "Please use your security key to authorize." : "Lūgums izmantot savu drošības atslēgu, lai autorizētu.",
5 | "Name your security key" : "Nodēvē savu drošības atslēgu",
6 | "Add" : "Pievienot",
7 | "Adding your security key …" : "Pievieno Tavu drošības atslēgu...",
8 | "Retry" : "Mēģināt vēlreiz",
9 | "Use security key" : "Izmantot drošības atslēgu",
10 | "An error occurred. Please try again." : "Notika kļūda. Mēģini vēlreiz.",
11 | "Remove" : "Noņemt"
12 | },"pluralForm" :"nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2);"
13 | }
--------------------------------------------------------------------------------
/.nextcloudignore:
--------------------------------------------------------------------------------
1 | # SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors
2 | # SPDX-License-Identifier: AGPL-3.0-or-later
3 | /AUTHORS.md
4 | /build
5 | /.babelrc
6 | /.eslintrc.js
7 | /.jshintrc
8 | /.git
9 | /.github
10 | /.gitignore
11 | /.nextcloudignore
12 | /.php-cs-fixer.dist.php
13 | /.travis.yml
14 | /.tx
15 | /.scrutinizer.yml
16 | /.git-blame-ignore-revs
17 | /babel.config.js
18 | /CONTRIBUTING.md
19 | /composer.*
20 | /karma.conf.js
21 | /krankerl.toml
22 | /l10n/no-php
23 | /Makefile
24 | /nbproject
25 | /node_modules
26 | /package*
27 | /playwright*
28 | /psalm.xml
29 | /screenshots
30 | /src
31 | /tests
32 | /test-results
33 | /vendor/bin
34 | /renovate.json
35 | /webpack*.config.*
36 | /vendor-bin
37 |
--------------------------------------------------------------------------------
/l10n/lv.js:
--------------------------------------------------------------------------------
1 | OC.L10N.register(
2 | "twofactor_webauthn",
3 | {
4 | "Security key" : "Drošības atslēga",
5 | "Add security key" : "Pievienot drošības atslēgu",
6 | "Please use your security key to authorize." : "Lūgums izmantot savu drošības atslēgu, lai autorizētu.",
7 | "Name your security key" : "Nodēvē savu drošības atslēgu",
8 | "Add" : "Pievienot",
9 | "Adding your security key …" : "Pievieno Tavu drošības atslēgu...",
10 | "Retry" : "Mēģināt vēlreiz",
11 | "Use security key" : "Izmantot drošības atslēgu",
12 | "An error occurred. Please try again." : "Notika kļūda. Mēģini vēlreiz.",
13 | "Remove" : "Noņemt"
14 | },
15 | "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2);");
16 |
--------------------------------------------------------------------------------
/tests/phpunit.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 | ../lib
10 |
11 |
12 |
13 |
14 |
15 |
16 | .
17 |
18 |
19 |
--------------------------------------------------------------------------------
/appinfo/routes.php:
--------------------------------------------------------------------------------
1 | [
12 | [
13 | 'name' => 'settings#startRegister',
14 | 'url' => '/settings/startregister',
15 | 'verb' => 'POST'
16 | ],
17 | [
18 | 'name' => 'settings#finishRegister',
19 | 'url' => '/settings/finishregister',
20 | 'verb' => 'POST'
21 | ],
22 | [
23 | 'name' => 'settings#remove',
24 | 'url' => '/settings/remove',
25 | 'verb' => 'POST'
26 | ],
27 | [
28 | 'name' => 'settings#changeActivationState',
29 | 'url' => '/settings/active',
30 | 'verb' => 'POST'
31 | ],
32 | ]
33 | ];
34 |
--------------------------------------------------------------------------------
/l10n/lt_LT.json:
--------------------------------------------------------------------------------
1 | { "translations": {
2 | "Security key" : "Saugumo raktas",
3 | "Add security key" : "Pridėti saugumo raktą",
4 | "Add" : "Pridėti",
5 | "Adding your security key …" : "Pridedamas jūsų saugumo raktas…",
6 | "An error occurred: {msg}" : "Įvyko klaida: {msg}",
7 | "Retry" : "Bandyti dar kartą",
8 | "Use security key" : "Naudoti saugumo raktą",
9 | "An error occurred. Please try again." : "Įvyko klaida. Prašome bandyti dar kartą.",
10 | "Your browser does not support WebAuthn." : "Jūsų naršyklė nepalaiko WebAuthn.",
11 | "Active" : "Aktyvi",
12 | "Remove" : "Šalinti"
13 | },"pluralForm" :"nplurals=4; plural=(n % 10 == 1 && (n % 100 > 19 || n % 100 < 11) ? 0 : (n % 10 >= 2 && n % 10 <=9) && (n % 100 > 19 || n % 100 < 11) ? 1 : n % 1 != 0 ? 2: 3);"
14 | }
--------------------------------------------------------------------------------
/l10n/lt_LT.js:
--------------------------------------------------------------------------------
1 | OC.L10N.register(
2 | "twofactor_webauthn",
3 | {
4 | "Security key" : "Saugumo raktas",
5 | "Add security key" : "Pridėti saugumo raktą",
6 | "Add" : "Pridėti",
7 | "Adding your security key …" : "Pridedamas jūsų saugumo raktas…",
8 | "An error occurred: {msg}" : "Įvyko klaida: {msg}",
9 | "Retry" : "Bandyti dar kartą",
10 | "Use security key" : "Naudoti saugumo raktą",
11 | "An error occurred. Please try again." : "Įvyko klaida. Prašome bandyti dar kartą.",
12 | "Your browser does not support WebAuthn." : "Jūsų naršyklė nepalaiko WebAuthn.",
13 | "Active" : "Aktyvi",
14 | "Remove" : "Šalinti"
15 | },
16 | "nplurals=4; plural=(n % 10 == 1 && (n % 100 > 19 || n % 100 < 11) ? 0 : (n % 10 >= 2 && n % 10 <=9) && (n % 100 > 19 || n % 100 < 11) ? 1 : n % 1 != 0 ? 2: 3);");
17 |
--------------------------------------------------------------------------------
/src/main-challenge.js:
--------------------------------------------------------------------------------
1 | /**
2 | * SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors
3 | * SPDX-License-Identifier: AGPL-3.0-or-later
4 | */
5 |
6 | import { createApp } from 'vue'
7 | import { createPinia } from 'pinia'
8 | import Nextcloud from './mixins/Nextcloud.js'
9 | import Challenge from './components/Challenge.vue'
10 | import { loadState } from '@nextcloud/initial-state'
11 | import { useMainStore } from './store.js'
12 |
13 | const pinia = createPinia()
14 |
15 | const credentialRequestOptions = loadState('twofactor_webauthn', 'credential-request-options')
16 | const mainStore = useMainStore(pinia)
17 | mainStore.$patch({
18 | credentialRequestOptions,
19 | })
20 |
21 | const app = createApp(Challenge)
22 | app.mixin(Nextcloud)
23 | app.use(pinia)
24 | app.mount('#twofactor-webauthn-challenge')
25 |
--------------------------------------------------------------------------------
/lib/Event/StateChanged.php:
--------------------------------------------------------------------------------
1 | user;
27 | }
28 |
29 | public function isEnabled(): bool {
30 | return $this->enabled;
31 | }
32 |
33 | public function isByAdmin(): bool {
34 | return $this->byAdmin;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/l10n/ja.json:
--------------------------------------------------------------------------------
1 | { "translations": {
2 | "You added an WebAuthn hardware token" : "WebAuthnハードウェアトークンを追加しました。",
3 | "You removed an WebAuthn hardware token" : "WebAuthnハードウェアトークンを削除しました。",
4 | "WebAuthn disabled by the administration" : "WebAuthnは管理者により無効にされています。",
5 | "Use WebAuthn for second factor authentication" : "WebAuthnを二要素目の認証に利用する",
6 | "Add" : "追加",
7 | "An error occurred: {msg}" : "エラーが発生しました: {msg}",
8 | "Retry" : "リトライ",
9 | "An error occurred. Please try again." : "エラーが発生しました。もう一度試してください。",
10 | "Your browser does not support WebAuthn." : "WebAuthnをサポートしていないブラウザです。",
11 | "You are accessing this site via an insecure connection. Browsers might therefore refuse the WebAuthn authentication." : "安全でない接続を利用してサイトにアクセスしているため、ブラウザがWebAuthnでの認証を拒否する可能性があります。",
12 | "Active" : "有効",
13 | "Remove" : "削除"
14 | },"pluralForm" :"nplurals=1; plural=0;"
15 | }
--------------------------------------------------------------------------------
/.github/workflows/reuse.yml:
--------------------------------------------------------------------------------
1 | # This workflow is provided via the organization template repository
2 | #
3 | # https://github.com/nextcloud/.github
4 | # https://docs.github.com/en/actions/learn-github-actions/sharing-workflows-with-your-organization
5 |
6 | # SPDX-FileCopyrightText: 2022 Free Software Foundation Europe e.V.
7 | #
8 | # SPDX-License-Identifier: CC0-1.0
9 |
10 | name: REUSE Compliance Check
11 |
12 | on: [pull_request]
13 |
14 | permissions:
15 | contents: read
16 |
17 | jobs:
18 | reuse-compliance-check:
19 | runs-on: ubuntu-latest-low
20 | steps:
21 | - name: Checkout
22 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
23 | with:
24 | persist-credentials: false
25 |
26 | - name: REUSE Compliance Check
27 | uses: fsfe/reuse-action@bb774aa972c2a89ff34781233d275075cbddf542 # v5.0.0
28 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
1 | # SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors
2 | # SPDX-License-Identifier: AGPL-3.0-or-later
3 | contact_links:
4 | - name: 🚨 Report a security or privacy issue
5 | url: https://hackerone.com/nextcloud
6 | about: Report security and privacy related issues privately to the Nextcloud team, so we can coordinate the fix and release without potentially exposing all Nextcloud servers and users in the meantime.
7 | - name: ❓ Community Support and Help
8 | url: https://help.nextcloud.com/
9 | about: Configuration, webserver/proxy or performance issues and other questions
10 | - name: 💼 Nextcloud Enterprise
11 | url: https://portal.nextcloud.com/
12 | about: If you are a Nextcloud Enterprise customer, or need Professional support, so it can be resolved directly by our dedicated engineers more quickly
13 |
--------------------------------------------------------------------------------
/src/tests/e2e/virtualAuthenticator.js:
--------------------------------------------------------------------------------
1 | /**
2 | * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
3 | * SPDX-License-Identifier: AGPL-3.0-or-later
4 | */
5 |
6 | /**
7 | * Create a new virtual authenticator for a single test.
8 | * This method is best used in a beforeEach hook.
9 | *
10 | * @param {import("@playwright/test").Page} page The page object to create the authenticator for
11 | * @return {Promise}
12 | */
13 | export async function createVirtualAuthenticator(page) {
14 | const cdpSession = await page.context().newCDPSession(page)
15 | await cdpSession.send('WebAuthn.enable')
16 | await cdpSession.send('WebAuthn.addVirtualAuthenticator', {
17 | options: {
18 | protocol: 'ctap2',
19 | ctap2Version: 'ctap2_1',
20 | hasUserVerification: true,
21 | transport: 'usb',
22 | automaticPresenceSimulation: true,
23 | isUserVerified: true,
24 | },
25 | })
26 | }
27 |
--------------------------------------------------------------------------------
/playwright.config.js:
--------------------------------------------------------------------------------
1 | /**
2 | * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
3 | * SPDX-License-Identifier: AGPL-3.0-or-later
4 | */
5 |
6 | const { defineConfig, devices } = require('@playwright/test')
7 | const path = require('path')
8 |
9 | /**
10 | * @see https://playwright.dev/docs/test-configuration
11 | */
12 | export default defineConfig({
13 | testDir: './src/tests/e2e',
14 | fullyParallel: false,
15 | forbidOnly: !!process.env.CI,
16 | retries: process.env.CI ? 2 : 0,
17 | workers: 1,
18 | reporter: [
19 | ['list'],
20 | ['html'],
21 | ],
22 | use: {
23 | baseURL: process.env.PLAYWRIGHT_BASE_URL ?? 'https://localhost',
24 | trace: 'on-first-retry',
25 | },
26 | projects: [
27 | {
28 | name: 'chromium',
29 | testMatch: '**/*.spec.js',
30 | use: {
31 | ...devices['Desktop Chrome'],
32 | ignoreHTTPSErrors: true,
33 | },
34 | },
35 | ],
36 | })
37 |
--------------------------------------------------------------------------------
/l10n/ja.js:
--------------------------------------------------------------------------------
1 | OC.L10N.register(
2 | "twofactor_webauthn",
3 | {
4 | "You added an WebAuthn hardware token" : "WebAuthnハードウェアトークンを追加しました。",
5 | "You removed an WebAuthn hardware token" : "WebAuthnハードウェアトークンを削除しました。",
6 | "WebAuthn disabled by the administration" : "WebAuthnは管理者により無効にされています。",
7 | "Use WebAuthn for second factor authentication" : "WebAuthnを二要素目の認証に利用する",
8 | "Add" : "追加",
9 | "An error occurred: {msg}" : "エラーが発生しました: {msg}",
10 | "Retry" : "リトライ",
11 | "An error occurred. Please try again." : "エラーが発生しました。もう一度試してください。",
12 | "Your browser does not support WebAuthn." : "WebAuthnをサポートしていないブラウザです。",
13 | "You are accessing this site via an insecure connection. Browsers might therefore refuse the WebAuthn authentication." : "安全でない接続を利用してサイトにアクセスしているため、ブラウザがWebAuthnでの認証を拒否する可能性があります。",
14 | "Active" : "有効",
15 | "Remove" : "削除"
16 | },
17 | "nplurals=1; plural=0;");
18 |
--------------------------------------------------------------------------------
/tests/Unit/Event/StateChangedTest.php:
--------------------------------------------------------------------------------
1 | createMock(IUser::class);
19 |
20 | $event = new StateChanged($user, true);
21 |
22 | self::assertTrue($event->isEnabled());
23 | self::assertSame($user, $event->getUser());
24 | }
25 |
26 | public function testDisabledState(): void {
27 | $user = $this->createMock(IUser::class);
28 |
29 | $event = new StateChanged($user, false);
30 |
31 | self::assertFalse($event->isEnabled());
32 | self::assertSame($user, $event->getUser());
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/img/app-dark.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/img/app.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/tests/unit/setup.js:
--------------------------------------------------------------------------------
1 | /**
2 | * SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors
3 | * SPDX-License-Identifier: AGPL-3.0-or-later
4 | */
5 |
6 | // Emulate browser environment for tests (inside node)
7 | // Ref (url): https://github.com/jsdom/jsdom/issues/2383#issuecomment-442199291
8 | // Ref (SVGElement): https://github.com/vuejs/core/issues/3590
9 | require('jsdom-global')('', {
10 | url: 'http://localhost',
11 | })
12 | global.SVGElement = window.SVGElement
13 |
14 | global.expect = require('chai').expect
15 | global.OC = {
16 | getCurrentUser: () => {
17 | return { uid: false }
18 | },
19 | isUserAdmin() {
20 | return false
21 | },
22 | getLanguage() {
23 | return 'en'
24 | },
25 | getLocale() {
26 | return 'en'
27 | },
28 | }
29 | global.t = (app, str) => str
30 |
31 | // https://github.com/vuejs/vue-test-utils/issues/936
32 | // better fix for "TypeError: Super expression must either be null or
33 | // a function" than pinning an old version of prettier.
34 | window.Date = Date
35 |
--------------------------------------------------------------------------------
/src/tests/unit/components/Device.spec.js:
--------------------------------------------------------------------------------
1 | /**
2 | * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors
3 | * SPDX-License-Identifier: AGPL-3.0-or-later
4 | */
5 |
6 | import { shallowMount } from '@vue/test-utils'
7 | import Nextcloud from '../../../mixins/Nextcloud.js'
8 | import Device from '../../../components/Device.vue'
9 | import { createPinia, setActivePinia } from 'pinia'
10 | import { useMainStore } from '../../../store.js'
11 |
12 | describe('Device', () => {
13 | let pinia
14 |
15 | beforeEach(() => {
16 | pinia = createPinia()
17 | setActivePinia(pinia)
18 | })
19 |
20 | it('renders devices without a name', () => {
21 | const mainStore = useMainStore()
22 | mainStore.$patch({
23 | devices: [{
24 | id: 'k1',
25 | name: undefined,
26 | }],
27 | })
28 |
29 | const device = shallowMount(Device, {
30 | global: {
31 | plugins: [pinia],
32 | mixins: [Nextcloud],
33 | },
34 | })
35 |
36 | expect(device.text()).to.have.string('Unnamed key')
37 | })
38 | })
39 |
--------------------------------------------------------------------------------
/img/device-disabled.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/lib/Migration/Version000203Date20200322201800.php:
--------------------------------------------------------------------------------
1 | hasTable('twofactor_webauthn_registrations')) {
29 | $table = $schema->getTable('twofactor_webauthn_registrations');
30 | $table->dropColumn('aaguid_transform');
31 | }
32 |
33 | return $schema;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/lib/Migration/Version000400Date20220524125249.php:
--------------------------------------------------------------------------------
1 | hasTable('twofactor_webauthn_registrations')) {
30 | $schema->dropTable('twofactor_webauthn_registrations');
31 | }
32 |
33 | return $schema;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/lib/Migration/Version000203Date20200322200700.php:
--------------------------------------------------------------------------------
1 | hasTable('twofactor_webauthn_registrations')) {
30 | $table = $schema->getTable('twofactor_webauthn_registrations');
31 | $table->dropColumn('aaguid');
32 | }
33 |
34 | return $schema;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/LICENSES/MIT.txt:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c)
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6 |
7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8 |
9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
10 |
--------------------------------------------------------------------------------
/src/main-settings.js:
--------------------------------------------------------------------------------
1 | /**
2 | * SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors
3 | * SPDX-License-Identifier: AGPL-3.0-or-later
4 | */
5 |
6 | import { loadState } from '@nextcloud/initial-state'
7 | import { createApp } from 'vue'
8 | import { createPinia } from 'pinia'
9 |
10 | import Nextcloud from './mixins/Nextcloud.js'
11 | import PersonalSettings from './components/PersonalSettings.vue'
12 | import { useMainStore } from './store.js'
13 |
14 | import '@nextcloud/password-confirmation/style.css'
15 |
16 | const pinia = createPinia()
17 |
18 | const devices = loadState('twofactor_webauthn', 'devices')
19 | devices.sort((d1, d2) => {
20 | if (!d1.name) {
21 | return 1
22 | } else if (!d2.name) {
23 | return -1
24 | } else {
25 | return d1.name.localeCompare(d2.name)
26 | }
27 | })
28 | const mainStore = useMainStore(pinia)
29 | mainStore.$patch({
30 | devices,
31 | })
32 |
33 | const app = createApp(PersonalSettings, {
34 | httpWarning: document.location.protocol !== 'https:',
35 | })
36 | app.mixin(Nextcloud)
37 | app.use(pinia)
38 | app.mount('#twofactor-webauthn-settings')
39 |
--------------------------------------------------------------------------------
/lib/Migration/Version000200Date20200310200500.php:
--------------------------------------------------------------------------------
1 | hasTable('twofactor_webauthn_registrations')) {
30 | $table = $schema->getTable('twofactor_webauthn_registrations');
31 | $table->getColumn('credential_public_key')->setOptions(['length' => 2000]);
32 | }
33 |
34 | return $schema;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/lib/Migration/Version000103Date20200308114300.php:
--------------------------------------------------------------------------------
1 | hasTable('twofactor_webauthn_registrations')) {
30 | $table = $schema->getTable('twofactor_webauthn_registrations');
31 | $table->addColumn('active', 'boolean', [
32 | 'notnull' => true,
33 | 'default' => true,
34 | ]);
35 | }
36 |
37 | return $schema;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/lib/Migration/Version010000Date20220929073925.php:
--------------------------------------------------------------------------------
1 | getTable('twofactor_webauthn_regs');
30 | if (!$registrationsTable->hasColumn('created_at')) {
31 | $registrationsTable->addColumn('created_at', 'integer', [
32 | 'notnull' => false,
33 | 'length' => 8,
34 | ]);
35 | }
36 |
37 | return $schema;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/lib/Migration/Version010000Date20221227080000.php:
--------------------------------------------------------------------------------
1 | getTable('twofactor_webauthn_regs');
30 | /**
31 | * Fixes https://github.com/nextcloud/twofactor_webauthn/issues/233
32 | */
33 | $registrationsTable
34 | ->getColumn('public_key_credential_id')
35 | ->setLength(512);
36 |
37 | return $schema;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/.github/workflows/block-unconventional-commits.yml:
--------------------------------------------------------------------------------
1 | # This workflow is provided via the organization template repository
2 | #
3 | # https://github.com/nextcloud/.github
4 | # https://docs.github.com/en/actions/learn-github-actions/sharing-workflows-with-your-organization
5 | #
6 | # SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
7 | # SPDX-License-Identifier: MIT
8 |
9 | name: Block unconventional commits
10 |
11 | on:
12 | pull_request:
13 | types: [opened, ready_for_review, reopened, synchronize]
14 |
15 | permissions:
16 | contents: read
17 |
18 | concurrency:
19 | group: block-unconventional-commits-${{ github.head_ref || github.run_id }}
20 | cancel-in-progress: true
21 |
22 | jobs:
23 | block-unconventional-commits:
24 | name: Block unconventional commits
25 |
26 | runs-on: ubuntu-latest-low
27 |
28 | steps:
29 | - name: Checkout
30 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
31 | with:
32 | persist-credentials: false
33 |
34 | - uses: webiny/action-conventional-commits@8bc41ff4e7d423d56fa4905f6ff79209a78776c7 # v1.3.0
35 | with:
36 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
37 |
--------------------------------------------------------------------------------
/.github/workflows/lint-info-xml.yml:
--------------------------------------------------------------------------------
1 | # This workflow is provided via the organization template repository
2 | #
3 | # https://github.com/nextcloud/.github
4 | # https://docs.github.com/en/actions/learn-github-actions/sharing-workflows-with-your-organization
5 | #
6 | # SPDX-FileCopyrightText: 2021-2024 Nextcloud GmbH and Nextcloud contributors
7 | # SPDX-License-Identifier: MIT
8 |
9 | name: Lint info.xml
10 |
11 | on: pull_request
12 |
13 | permissions:
14 | contents: read
15 |
16 | concurrency:
17 | group: lint-info-xml-${{ github.head_ref || github.run_id }}
18 | cancel-in-progress: true
19 |
20 | jobs:
21 | xml-linters:
22 | runs-on: ubuntu-latest-low
23 |
24 | name: info.xml lint
25 | steps:
26 | - name: Checkout
27 | uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
28 |
29 | - name: Download schema
30 | run: wget https://raw.githubusercontent.com/nextcloud/appstore/master/nextcloudappstore/api/v1/release/info.xsd
31 |
32 | - name: Lint info.xml
33 | uses: ChristophWurst/xmllint-action@36f2a302f84f8c83fceea0b9c59e1eb4a616d3c1 # v1.2
34 | with:
35 | xml-file: ./appinfo/info.xml
36 | xml-schema-file: ./info.xsd
37 |
--------------------------------------------------------------------------------
/src/tests/e2e/login-setup.spec.js:
--------------------------------------------------------------------------------
1 | /**
2 | * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
3 | * SPDX-License-Identifier: AGPL-3.0-or-later
4 | */
5 |
6 | import { test } from '@playwright/test'
7 | import { createVirtualAuthenticator } from './virtualAuthenticator.js'
8 | import { disableTwofactorAuth, enforceTwofactorAuth } from './occ.js'
9 |
10 | test.beforeAll(async () => {
11 | await enforceTwofactorAuth(true)
12 | })
13 |
14 | test.beforeEach(async ({ page }) => {
15 | await disableTwofactorAuth(['admin'])
16 | await createVirtualAuthenticator(page)
17 | })
18 |
19 | test('setup and login', async ({ page }) => {
20 | await page.goto('./index.php/login')
21 | await page.locator('#user').fill('admin')
22 | await page.locator('#password').fill('admin')
23 | await page.locator('#password').press('Enter')
24 | await page.getByRole('link', { name: 'Security key Use WebAuthn for' }).click()
25 | await page.getByRole('button', { name: 'Add security key' }).click()
26 | await page.getByPlaceholder('Name your security key').fill('key')
27 | await page.getByRole('button', { name: 'Add' }).click()
28 | await page.getByRole('link', { name: 'Security key Use WebAuthn for' }).click()
29 |
30 | // Wait for log in to finish
31 | await page.waitForURL('**/apps/**')
32 | })
33 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/2_feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: 🚀 Feature request
3 | about: Suggest an idea for this app
4 | labels: 0. Needs triage, enhancement
5 | ---
6 |
7 |
8 |
9 | ### How to use GitHub
10 |
11 | * Please use the 👍 [reaction](https://blog.github.com/2016-03-10-add-reactions-to-pull-requests-issues-and-comments/) to show that you are interested into the same feature.
12 | * Please don't comment if you have no relevant information to add. It's just extra noise for everyone subscribed to this issue.
13 | * Subscribe to receive notifications on status change and new comments.
14 |
15 | ---
16 |
17 | ## Feature request
18 |
19 | **Which Nextcloud Version are you currently using:** (see administration page)
20 |
21 | **Is your feature request related to a problem? Please describe.**
22 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
23 |
24 | **Describe the solution you'd like**
25 | A clear and concise description of what you want to happen.
26 |
27 | **Describe alternatives you've considered**
28 | A clear and concise description of any alternative solutions or features you've considered.
29 |
30 | **Additional context**
31 | Add any other context or screenshots about the feature request here.
32 |
--------------------------------------------------------------------------------
/l10n/nl.json:
--------------------------------------------------------------------------------
1 | { "translations": {
2 | "You added an WebAuthn hardware token" : "Een WebAuthn hardware token is toegevoegd",
3 | "You removed an WebAuthn hardware token" : "Een WebAuthn hardware token is verwijderd",
4 | "WebAuthn disabled by the administration" : "WebAuthn uitgeschakeld door de beheerder",
5 | "Use WebAuthn for second factor authentication" : "WebAuthn gebruiken voor tweede factor authenticatie",
6 | "Two-Factor WebAuthn" : "Twee-factor WebAuthn",
7 | "WebAuthn two-factor provider" : "WebAuthn twee-factor provider",
8 | "A two-factor provider for WebAuthn devices" : "Een twee-factor provider voor WebAuthn-toestellen",
9 | "Add" : "Toevoegen",
10 | "An error occurred: {msg}" : "Er is een fout opgetreden: {msg}",
11 | "Retry" : "Opnieuw",
12 | "An error occurred. Please try again." : "Er is een fout opgetreden. Opnieuw.",
13 | "Your browser does not support WebAuthn." : "De browser ondersteunt geen WebAuthn.",
14 | "You are accessing this site via an insecure connection. Browsers might therefore refuse the WebAuthn authentication." : "Deze site wordt via een onveilige verbinding geopend. Browsers kunnen daarom de WebAuthn verificatie weigeren.",
15 | "Active" : "Actief",
16 | "Remove" : "Verwijderen"
17 | },"pluralForm" :"nplurals=2; plural=(n != 1);"
18 | }
--------------------------------------------------------------------------------
/src/services/RegistrationService.js:
--------------------------------------------------------------------------------
1 | /**
2 | * SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors
3 | * SPDX-License-Identifier: AGPL-3.0-or-later
4 | */
5 |
6 | import Axios from '@nextcloud/axios'
7 | import { generateUrl } from '@nextcloud/router'
8 |
9 | /**
10 | *
11 | */
12 | export async function startRegistration() {
13 | const url = generateUrl('/apps/twofactor_webauthn/settings/startregister')
14 |
15 | const res = await Axios.post(url)
16 | return res.data
17 | }
18 |
19 | /**
20 | * @param name
21 | * @param data
22 | */
23 | export async function finishRegistration(name, data) {
24 | const url = generateUrl('/apps/twofactor_webauthn/settings/finishregister')
25 |
26 | const res = await Axios.post(url, { name, data })
27 | return res.data
28 | }
29 |
30 | /**
31 | * @param id
32 | */
33 | export async function removeRegistration(id) {
34 | const url = generateUrl('/apps/twofactor_webauthn/settings/remove')
35 |
36 | const res = await Axios.post(url, { id })
37 | return res.data
38 | }
39 |
40 | /**
41 | * @param id
42 | * @param active
43 | */
44 | export async function changeActivationState(id, active) {
45 | const url = generateUrl('/apps/twofactor_webauthn/settings/active')
46 |
47 | const res = await Axios.post(url, { id, active: active ? 1 : 0 })
48 | return res.data
49 | }
50 |
--------------------------------------------------------------------------------
/l10n/ast.json:
--------------------------------------------------------------------------------
1 | { "translations": {
2 | "WebAuthn disabled by the administration" : "L'alministración desactivó WebAuthn",
3 | "Security key" : "Llave de seguranza",
4 | "WebAuthn two-factor provider" : "Fornidor de l'autenticación en dos pasos WebAuthn",
5 | "A two-factor provider for WebAuthn devices" : "Un fornidor d'autenticación en dos paasos pa preseos WebAuthn",
6 | "Add security key" : "Amestar una llave de seguranza",
7 | "Please use your security key to authorize." : "Usa la to llave de seguranza p'autorizar.",
8 | "Add" : "Amestar",
9 | "An error occurred: {msg}" : "Prodúxose un error: {msg}",
10 | "Retry" : "Retentar",
11 | "An error occurred. Please try again." : "Prodúxose un error. Volvi tentalo.",
12 | "Your browser does not support WebAuthn." : "El restolador nun ye compatible con WebAuthn.",
13 | "Unnamed key" : "Llave ensin nome",
14 | "Registered" : "Rexistróse",
15 | "Active" : "Activa",
16 | "Remove" : "Quitar",
17 | "No security keys configured. You are not using WebAuthn as second factor at the moment." : "Nun se configuró nenguna llave de seguranza. Pel momentu, nun tas usando WebAuthn como autenticación de dos pasos",
18 | "All security keys are deactivated." : "Toles llaves de seguranza tán desactivaes."
19 | },"pluralForm" :"nplurals=2; plural=(n != 1);"
20 | }
--------------------------------------------------------------------------------
/.github/workflows/lint-eslint-when-unrelated.yml:
--------------------------------------------------------------------------------
1 | # This workflow is provided via the organization template repository
2 | #
3 | # https://github.com/nextcloud/.github
4 | # https://docs.github.com/en/actions/learn-github-actions/sharing-workflows-with-your-organization
5 | #
6 | # Use lint-eslint together with lint-eslint-when-unrelated to make eslint a required check for GitHub actions
7 | # https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/defining-the-mergeability-of-pull-requests/troubleshooting-required-status-checks#handling-skipped-but-required-checks
8 | #
9 | # SPDX-FileCopyrightText: 2021-2024 Nextcloud GmbH and Nextcloud contributors
10 | # SPDX-License-Identifier: MIT
11 |
12 | name: Lint eslint
13 |
14 | on:
15 | pull_request:
16 | paths-ignore:
17 | - '.github/workflows/**'
18 | - 'src/**'
19 | - 'appinfo/info.xml'
20 | - 'package.json'
21 | - 'package-lock.json'
22 | - 'tsconfig.json'
23 | - '.eslintrc.*'
24 | - '.eslintignore'
25 | - '**.js'
26 | - '**.ts'
27 | - '**.vue'
28 |
29 | permissions:
30 | contents: read
31 |
32 | jobs:
33 | lint:
34 | permissions:
35 | contents: none
36 |
37 | runs-on: ubuntu-latest
38 |
39 | name: eslint
40 |
41 | steps:
42 | - run: 'echo "No eslint required"'
43 |
--------------------------------------------------------------------------------
/l10n/nl.js:
--------------------------------------------------------------------------------
1 | OC.L10N.register(
2 | "twofactor_webauthn",
3 | {
4 | "You added an WebAuthn hardware token" : "Een WebAuthn hardware token is toegevoegd",
5 | "You removed an WebAuthn hardware token" : "Een WebAuthn hardware token is verwijderd",
6 | "WebAuthn disabled by the administration" : "WebAuthn uitgeschakeld door de beheerder",
7 | "Use WebAuthn for second factor authentication" : "WebAuthn gebruiken voor tweede factor authenticatie",
8 | "Two-Factor WebAuthn" : "Twee-factor WebAuthn",
9 | "WebAuthn two-factor provider" : "WebAuthn twee-factor provider",
10 | "A two-factor provider for WebAuthn devices" : "Een twee-factor provider voor WebAuthn-toestellen",
11 | "Add" : "Toevoegen",
12 | "An error occurred: {msg}" : "Er is een fout opgetreden: {msg}",
13 | "Retry" : "Opnieuw",
14 | "An error occurred. Please try again." : "Er is een fout opgetreden. Opnieuw.",
15 | "Your browser does not support WebAuthn." : "De browser ondersteunt geen WebAuthn.",
16 | "You are accessing this site via an insecure connection. Browsers might therefore refuse the WebAuthn authentication." : "Deze site wordt via een onveilige verbinding geopend. Browsers kunnen daarom de WebAuthn verificatie weigeren.",
17 | "Active" : "Actief",
18 | "Remove" : "Verwijderen"
19 | },
20 | "nplurals=2; plural=(n != 1);");
21 |
--------------------------------------------------------------------------------
/l10n/ast.js:
--------------------------------------------------------------------------------
1 | OC.L10N.register(
2 | "twofactor_webauthn",
3 | {
4 | "WebAuthn disabled by the administration" : "L'alministración desactivó WebAuthn",
5 | "Security key" : "Llave de seguranza",
6 | "WebAuthn two-factor provider" : "Fornidor de l'autenticación en dos pasos WebAuthn",
7 | "A two-factor provider for WebAuthn devices" : "Un fornidor d'autenticación en dos paasos pa preseos WebAuthn",
8 | "Add security key" : "Amestar una llave de seguranza",
9 | "Please use your security key to authorize." : "Usa la to llave de seguranza p'autorizar.",
10 | "Add" : "Amestar",
11 | "An error occurred: {msg}" : "Prodúxose un error: {msg}",
12 | "Retry" : "Retentar",
13 | "An error occurred. Please try again." : "Prodúxose un error. Volvi tentalo.",
14 | "Your browser does not support WebAuthn." : "El restolador nun ye compatible con WebAuthn.",
15 | "Unnamed key" : "Llave ensin nome",
16 | "Registered" : "Rexistróse",
17 | "Active" : "Activa",
18 | "Remove" : "Quitar",
19 | "No security keys configured. You are not using WebAuthn as second factor at the moment." : "Nun se configuró nenguna llave de seguranza. Pel momentu, nun tas usando WebAuthn como autenticación de dos pasos",
20 | "All security keys are deactivated." : "Toles llaves de seguranza tán desactivaes."
21 | },
22 | "nplurals=2; plural=(n != 1);");
23 |
--------------------------------------------------------------------------------
/src/store.js:
--------------------------------------------------------------------------------
1 | /**
2 | * SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors
3 | * SPDX-License-Identifier: AGPL-3.0-or-later
4 | */
5 |
6 | import { defineStore } from 'pinia'
7 | import * as RegistrationService from './services/RegistrationService.js'
8 |
9 | export const useMainStore = defineStore('main', {
10 | state: () => ({
11 | credentialRequestOptions: {},
12 | devices: [],
13 | }),
14 | actions: {
15 | addDevice(device) {
16 | this.devices.push(device)
17 | this.devices.sort((d1, d2) => d1.name.localeCompare(d2.name))
18 | },
19 |
20 | async removeDevice(entityId) {
21 | const device = this.devices.find(device => device.entityId === entityId)
22 |
23 | this.devices = this.devices.filter(device => device.entityId !== entityId)
24 |
25 | try {
26 | await RegistrationService.removeRegistration(entityId)
27 | } catch (err) {
28 | // Rollback
29 | this.addDevice(device)
30 |
31 | throw err
32 | }
33 | },
34 |
35 | async changeActivationState({ entityId, active }) {
36 | this.devices.find(device => device.entityId === entityId).active = active
37 |
38 | try {
39 | await RegistrationService.changeActivationState(entityId, active)
40 | } catch (err) {
41 | // Rollback
42 | this.changeActivationState({ entityId, active: !active })
43 |
44 | throw err
45 | }
46 | },
47 | },
48 | })
49 |
--------------------------------------------------------------------------------
/l10n/ro.json:
--------------------------------------------------------------------------------
1 | { "translations": {
2 | "You added an WebAuthn hardware token" : "Ați adăugat un token hardware de tip WebAuthn",
3 | "You removed an WebAuthn hardware token" : "Ați eliminat un token hardware de tip WebAuthn",
4 | "WebAuthn disabled by the administration" : "WebAuthn dezactivat de către administrație",
5 | "Use WebAuthn for second factor authentication" : "Utilizați WebAuthn pentru autentificarea în doi pași",
6 | "Two-Factor WebAuthn" : "WebAuthn în doi pași",
7 | "WebAuthn two-factor provider" : "Furnizor WebAuthn în doi pași",
8 | "A two-factor provider for WebAuthn devices" : "Un furnizor în doi pași pentru dispozitivele WebAuthn",
9 | "Add" : "Adaugă",
10 | "An error occurred: {msg}" : "S-a produs o eroare: {msg}",
11 | "Retry" : "Reîncearcă",
12 | "An error occurred. Please try again." : "S-a produs o eroare. Vă rugăm să încercați din nou.",
13 | "Your browser does not support WebAuthn." : "Browserul dvs. nu acceptă WebAuthn.",
14 | "You are accessing this site via an insecure connection. Browsers might therefore refuse the WebAuthn authentication." : "Accesați acest site prin intermediul unei conexiuni nesigure. Prin urmare, este posibil ca browserele să refuze autentificarea WebAuthn.",
15 | "Active" : "Activ",
16 | "Remove" : "Elimină"
17 | },"pluralForm" :"nplurals=3; plural=(n==1?0:(((n%100>19)||((n%100==0)&&(n!=0)))?2:1));"
18 | }
--------------------------------------------------------------------------------
/tests/Unit/Activity/SettingTest.php:
--------------------------------------------------------------------------------
1 | l10n = $this->createMock(IL10N::class);
26 |
27 | $this->setting = new Setting($this->l10n);
28 | }
29 |
30 | public function testAll(): void {
31 | self::assertEquals(false, $this->setting->canChangeMail());
32 | self::assertEquals(false, $this->setting->canChangeStream());
33 | self::assertEquals('twofactor_webauthn', $this->setting->getIdentifier());
34 | $this->l10n->expects(self::once())
35 | ->method('t')
36 | ->with('Security key')
37 | ->willReturn('Sicherheitsschlüssel');
38 | self::assertEquals('Sicherheitsschlüssel', $this->setting->getName());
39 | self::assertEquals(30, $this->setting->getPriority());
40 | self::assertEquals(true, $this->setting->isDefaultEnabledMail());
41 | self::assertEquals(true, $this->setting->isDefaultEnabledStream());
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/lib/Activity/Setting.php:
--------------------------------------------------------------------------------
1 | l10n = $l10n;
25 | }
26 |
27 | /**
28 | * @return boolean
29 | */
30 | public function canChangeMail() {
31 | return false;
32 | }
33 |
34 | /**
35 | * @return boolean
36 | */
37 | public function canChangeStream() {
38 | return false;
39 | }
40 |
41 | /**
42 | * @return string
43 | */
44 | public function getIdentifier() {
45 | return 'twofactor_webauthn';
46 | }
47 |
48 | /**
49 | * @return string
50 | */
51 | public function getName() {
52 | return $this->l10n->t('Security key');
53 | }
54 |
55 | /**
56 | * @return int
57 | */
58 | public function getPriority() {
59 | return 30;
60 | }
61 |
62 | /**
63 | * @return boolean
64 | */
65 | public function isDefaultEnabledMail() {
66 | return true;
67 | }
68 |
69 | /**
70 | * @return boolean
71 | */
72 | public function isDefaultEnabledStream() {
73 | return true;
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/lib/Listener/StateChangeActivity.php:
--------------------------------------------------------------------------------
1 |
19 | */
20 | class StateChangeActivity implements IEventListener {
21 |
22 | /** @var IManager */
23 | private $activityManager;
24 |
25 | public function __construct(IManager $activityManager) {
26 | $this->activityManager = $activityManager;
27 | }
28 |
29 | public function handle(Event $event): void {
30 | if ($event instanceof StateChanged) {
31 | if ($event->isByAdmin()) {
32 | $subject = 'webauthn_disabled_by_admin';
33 | } else {
34 | $subject = $event->isEnabled() ? 'webauthn_device_added' : 'webauthn_device_removed';
35 | }
36 |
37 | $activity = $this->activityManager->generateEvent();
38 | $activity->setApp('twofactor_webauthn')
39 | ->setType('security')
40 | ->setAuthor($event->getUser()->getUID())
41 | ->setAffectedUser($event->getUser()->getUID())
42 | ->setSubject($subject);
43 | $this->activityManager->publish($activity);
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/l10n/ro.js:
--------------------------------------------------------------------------------
1 | OC.L10N.register(
2 | "twofactor_webauthn",
3 | {
4 | "You added an WebAuthn hardware token" : "Ați adăugat un token hardware de tip WebAuthn",
5 | "You removed an WebAuthn hardware token" : "Ați eliminat un token hardware de tip WebAuthn",
6 | "WebAuthn disabled by the administration" : "WebAuthn dezactivat de către administrație",
7 | "Use WebAuthn for second factor authentication" : "Utilizați WebAuthn pentru autentificarea în doi pași",
8 | "Two-Factor WebAuthn" : "WebAuthn în doi pași",
9 | "WebAuthn two-factor provider" : "Furnizor WebAuthn în doi pași",
10 | "A two-factor provider for WebAuthn devices" : "Un furnizor în doi pași pentru dispozitivele WebAuthn",
11 | "Add" : "Adaugă",
12 | "An error occurred: {msg}" : "S-a produs o eroare: {msg}",
13 | "Retry" : "Reîncearcă",
14 | "An error occurred. Please try again." : "S-a produs o eroare. Vă rugăm să încercați din nou.",
15 | "Your browser does not support WebAuthn." : "Browserul dvs. nu acceptă WebAuthn.",
16 | "You are accessing this site via an insecure connection. Browsers might therefore refuse the WebAuthn authentication." : "Accesați acest site prin intermediul unei conexiuni nesigure. Prin urmare, este posibil ca browserele să refuze autentificarea WebAuthn.",
17 | "Active" : "Activ",
18 | "Remove" : "Elimină"
19 | },
20 | "nplurals=3; plural=(n==1?0:(((n%100>19)||((n%100==0)&&(n!=0)))?2:1));");
21 |
--------------------------------------------------------------------------------
/lib/Listener/UserDeleted.php:
--------------------------------------------------------------------------------
1 |
21 | */
22 | class UserDeleted implements IEventListener {
23 |
24 | /** @var PublicKeyCredentialEntityMapper */
25 | private $publicKeyCredentialEntityMapper;
26 |
27 | /** @var LoggerInterface */
28 | private $logger;
29 |
30 | public function __construct(PublicKeyCredentialEntityMapper $publicKeyCredentialEntityMapper, LoggerInterface $logger) {
31 | $this->publicKeyCredentialEntityMapper = $publicKeyCredentialEntityMapper;
32 | $this->logger = $logger;
33 | }
34 |
35 | public function handle(Event $event): void {
36 | if ($event instanceof UserDeletedEvent) {
37 | try {
38 | $this->publicKeyCredentialEntityMapper->deletePublicKeyCredentialsByUserId($event->getUser()->getUID());
39 | } catch (Exception $e) {
40 | $this->logger->warning($e->getMessage(), ['uid' => $event->getUser()->getUID()]);
41 | }
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/lib/AppInfo/Application.php:
--------------------------------------------------------------------------------
1 | registerEventListener(StateChanged::class, StateChangeActivity::class);
33 | $context->registerEventListener(StateChanged::class, StateChangeRegistryUpdater::class);
34 | $context->registerEventListener(UserDeletedEvent::class, UserDeleted::class);
35 | }
36 |
37 | public function boot(IBootContext $context): void {
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/lib/Db/Registration.php:
--------------------------------------------------------------------------------
1 | addType('counter', 'integer');
39 | }
40 |
41 | public function jsonSerialize(): array {
42 | return [
43 | 'id' => $this->getId(),
44 | 'userId' => $this->getUserId(),
45 | 'keyHandle' => $this->getKeyHandle(),
46 | 'publicKey' => $this->getPublicKey(),
47 | 'certificate' => $this->getCertificate(),
48 | 'counter' => $this->getCounter(),
49 | 'name' => $this->getName(),
50 | ];
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/psalm.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/src/tests/e2e/occ.js:
--------------------------------------------------------------------------------
1 | /**
2 | * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
3 | * SPDX-License-Identifier: AGPL-3.0-or-later
4 | */
5 |
6 | import { exec as execCallback } from 'child_process'
7 | import util from 'util'
8 |
9 | const exec = util.promisify(execCallback)
10 |
11 | /**
12 | * Helper to execute the occ command.
13 | *
14 | * @param {string} args Arguments ot pass to occ
15 | * @return {Promise<{stdout: string, stderr: string}>} The result of the command
16 | */
17 | export async function occ(args) {
18 | return exec(`php ../../occ ${args}`)
19 | }
20 |
21 | /**
22 | * Enforce twofactor auth for all users.
23 | *
24 | * @param {boolean} enforce True to enforce twofactor auth, false to disable it
25 | * @return {Promise}
26 | */
27 | export async function enforceTwofactorAuth(enforce) {
28 | const flag = enforce ? '--on' : '--off'
29 | try {
30 | await occ(`twofactorauth:enforce ${flag}`)
31 | } catch (error) {
32 | console.error(`Failed to enfore twofactor auth: ${error}`)
33 | throw error
34 | }
35 | }
36 |
37 | /**
38 | * Disable webauthn twofactor auth for all given users.
39 | *
40 | * @param {string[]} users List of uids to disable twofactor auth for
41 | * @return {Promise}
42 | */
43 | export async function disableTwofactorAuth(users) {
44 | for (const user of users) {
45 | try {
46 | await occ(`twofactorauth:disable ${user} webauthn`)
47 | } catch (error) {
48 | console.error(`Failed to disable twofactor webauthn for ${user}: ${error}`)
49 | throw error
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/lib/Model/Device.php:
--------------------------------------------------------------------------------
1 | getId(),
27 | $entity->getPublicKeyCredentialId(),
28 | $entity->getName(),
29 | $entity->getCreatedAt(),
30 | $entity->isActive() === true,
31 | );
32 | }
33 |
34 | public function getEntityId(): int {
35 | return $this->entityId;
36 | }
37 |
38 | public function getId(): string {
39 | return $this->id;
40 | }
41 |
42 | public function getName(): string {
43 | return $this->name;
44 | }
45 |
46 | public function getCreatedAt(): ?int {
47 | return $this->createdAt;
48 | }
49 |
50 | public function isActive(): bool {
51 | return $this->active;
52 | }
53 |
54 | #[\ReturnTypeWillChange]
55 | public function jsonSerialize() {
56 | return [
57 | 'entityId' => $this->getEntityId(),
58 | 'id' => $this->getId(),
59 | 'name' => $this->getName(),
60 | 'createdAt' => $this->getCreatedAt(),
61 | 'active' => $this->isActive(),
62 | ];
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/l10n/fi.json:
--------------------------------------------------------------------------------
1 | { "translations": {
2 | "WebAuthn disabled by the administration" : "WebAuthn on poistettu käytöstä ylläpitäjän toimesta",
3 | "Security key" : "Turva-avain",
4 | "Use WebAuthn for second factor authentication" : "Käytä WebAuthnia kaksivaiheiseen todentamiseen",
5 | "Server error while trying to complete security key registration" : "Palvelinvirhe turva-avaimen rekisteröinnin aikana",
6 | "Add security key" : "Lisää turva-avain",
7 | "Name your security key" : "Anna turva-avaimellesi nimi",
8 | "Add" : "Lisä",
9 | "Adding your security key …" : "Lisätään turva-avaimesi…",
10 | "An error occurred: {msg}" : "Tapahtui virhe: {msg}",
11 | "Retry" : "Yritä uudelleen",
12 | "Use security key" : "Käytä turva-avainta",
13 | "An error occurred. Please try again." : "Tapahtui virhe. Yritä myöhemmin uudelleen.",
14 | "Your browser does not support WebAuthn." : "Selaimesi ei tue WebAuthn-standardia.",
15 | "Unnamed key" : "Nimetön avain",
16 | "Active" : "Aktiivinen",
17 | "Remove" : "Poista",
18 | "Your security key was added successfully. You are now being redirected to the login page." : "Turva-avaimesi liitettiin onnistuneesti. Sinut uudelleenohjataan nyt kirjautumissivulle.",
19 | "No security keys configured. You are not using WebAuthn as second factor at the moment." : "Turva-avaimia ei ole määritetty. Et käytä kaksivaiheista WebAuthn-todennusta tällä hetkellä.",
20 | "The following security keys are configured for WebAuthn two-factor authentication:" : "Seuraavat turva-avaimet on määritetty kaksivaiheista WebAuthn-todennusta varten:"
21 | },"pluralForm" :"nplurals=2; plural=(n != 1);"
22 | }
--------------------------------------------------------------------------------
/src/components/LoginSetup.vue:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
{{ t('twofactor_webauthn', 'Set up a security key as a second factor.') }}
9 |
10 |
12 |
13 |
14 | {{ t('twofactor_webauthn', 'Your security key was added successfully. You are now being redirected to the login page.') }}
15 |
16 |
17 | {{ t('twofactor_webauthn', 'Your browser does not support WebAuthn.') }}
18 |
19 |
21 | {{ t('twofactor_webauthn', 'You are accessing this site via an insecure connection. Browsers might therefore refuse the WebAuthn authentication.') }}
22 |
23 |
24 |
25 |
26 |
27 |
54 |
55 |
61 |
--------------------------------------------------------------------------------
/l10n/fi.js:
--------------------------------------------------------------------------------
1 | OC.L10N.register(
2 | "twofactor_webauthn",
3 | {
4 | "WebAuthn disabled by the administration" : "WebAuthn on poistettu käytöstä ylläpitäjän toimesta",
5 | "Security key" : "Turva-avain",
6 | "Use WebAuthn for second factor authentication" : "Käytä WebAuthnia kaksivaiheiseen todentamiseen",
7 | "Server error while trying to complete security key registration" : "Palvelinvirhe turva-avaimen rekisteröinnin aikana",
8 | "Add security key" : "Lisää turva-avain",
9 | "Name your security key" : "Anna turva-avaimellesi nimi",
10 | "Add" : "Lisä",
11 | "Adding your security key …" : "Lisätään turva-avaimesi…",
12 | "An error occurred: {msg}" : "Tapahtui virhe: {msg}",
13 | "Retry" : "Yritä uudelleen",
14 | "Use security key" : "Käytä turva-avainta",
15 | "An error occurred. Please try again." : "Tapahtui virhe. Yritä myöhemmin uudelleen.",
16 | "Your browser does not support WebAuthn." : "Selaimesi ei tue WebAuthn-standardia.",
17 | "Unnamed key" : "Nimetön avain",
18 | "Active" : "Aktiivinen",
19 | "Remove" : "Poista",
20 | "Your security key was added successfully. You are now being redirected to the login page." : "Turva-avaimesi liitettiin onnistuneesti. Sinut uudelleenohjataan nyt kirjautumissivulle.",
21 | "No security keys configured. You are not using WebAuthn as second factor at the moment." : "Turva-avaimia ei ole määritetty. Et käytä kaksivaiheista WebAuthn-todennusta tällä hetkellä.",
22 | "The following security keys are configured for WebAuthn two-factor authentication:" : "Seuraavat turva-avaimet on määritetty kaksivaiheista WebAuthn-todennusta varten:"
23 | },
24 | "nplurals=2; plural=(n != 1);");
25 |
--------------------------------------------------------------------------------
/lib/Db/RegistrationMapper.php:
--------------------------------------------------------------------------------
1 |
19 | */
20 | class RegistrationMapper extends QBMapper {
21 | public function __construct(IDBConnection $db) {
22 | parent::__construct($db, 'twofactor_u2f_registrations');
23 | }
24 |
25 | /**
26 | * @param IUser $user
27 | * @param int $id
28 | */
29 | public function findRegistration(IUser $user, $id): Registration {
30 | /* @var $qb IQueryBuilder */
31 | $qb = $this->db->getQueryBuilder();
32 |
33 | $qb->select('id', 'user_id', 'key_handle', 'public_key', 'certificate', 'counter', 'name')
34 | ->from('twofactor_u2f_registrations')
35 | ->where($qb->expr()->eq('user_id', $qb->createNamedParameter($user->getUID())))
36 | ->andWhere($qb->expr()->eq('id', $qb->createNamedParameter($id)));
37 | return $this->findEntity($qb);
38 | }
39 |
40 | /**
41 | * @param IUser $user
42 | * @return Registration[]
43 | */
44 | public function findRegistrations(IUser $user): array {
45 | /* @var $qb IQueryBuilder */
46 | $qb = $this->db->getQueryBuilder();
47 |
48 | $qb->select('id', 'user_id', 'key_handle', 'public_key', 'certificate', 'counter', 'name')
49 | ->from('twofactor_u2f_registrations')
50 | ->where($qb->expr()->eq('user_id', $qb->createNamedParameter($user->getUID())));
51 | return $this->findEntities($qb);
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/.github/workflows/lint-php-cs.yml:
--------------------------------------------------------------------------------
1 | # This workflow is provided via the organization template repository
2 | #
3 | # https://github.com/nextcloud/.github
4 | # https://docs.github.com/en/actions/learn-github-actions/sharing-workflows-with-your-organization
5 | #
6 | # SPDX-FileCopyrightText: 2021-2024 Nextcloud GmbH and Nextcloud contributors
7 | # SPDX-License-Identifier: MIT
8 |
9 | name: Lint php-cs
10 |
11 | on: pull_request
12 |
13 | permissions:
14 | contents: read
15 |
16 | concurrency:
17 | group: lint-php-cs-${{ github.head_ref || github.run_id }}
18 | cancel-in-progress: true
19 |
20 | jobs:
21 | lint:
22 | runs-on: ubuntu-latest
23 |
24 | name: php-cs
25 |
26 | steps:
27 | - name: Checkout
28 | uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
29 |
30 | - name: Get php version
31 | id: versions
32 | uses: icewind1991/nextcloud-version-matrix@58becf3b4bb6dc6cef677b15e2fd8e7d48c0908f # v1.3.1
33 |
34 | - name: Set up php${{ steps.versions.outputs.php-min }}
35 | uses: shivammathur/setup-php@cf4cade2721270509d5b1c766ab3549210a39a2a # 2.33.0
36 | with:
37 | php-version: ${{ steps.versions.outputs.php-min }}
38 | extensions: bz2, ctype, curl, dom, fileinfo, gd, iconv, intl, json, libxml, mbstring, openssl, pcntl, posix, session, simplexml, xmlreader, xmlwriter, zip, zlib, sqlite, pdo_sqlite
39 | coverage: none
40 | ini-file: development
41 | env:
42 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
43 |
44 | - name: Install dependencies
45 | run: composer i
46 |
47 | - name: Lint
48 | run: composer run cs:check || ( echo 'Please run `composer run cs:fix` to format your code' && exit 1 )
49 |
--------------------------------------------------------------------------------
/lib/Activity/Provider.php:
--------------------------------------------------------------------------------
1 | getApp() !== 'twofactor_webauthn') {
39 | throw new InvalidArgumentException();
40 | }
41 |
42 | $l = $this->l10n->get('twofactor_webauthn', $language);
43 |
44 | $event->setIcon($this->urlGenerator->getAbsoluteURL($this->urlGenerator->imagePath('core', 'actions/password.svg')));
45 | switch ($event->getSubject()) {
46 | case 'webauthn_device_added':
47 | $event->setSubject($l->t('You added an WebAuthn hardware token'));
48 | break;
49 | case 'webauthn_device_removed':
50 | $event->setSubject($l->t('You removed an WebAuthn hardware token'));
51 | break;
52 | case 'webauthn_disabled_by_admin':
53 | $event->setSubject($l->t('WebAuthn disabled by the administration'));
54 | break;
55 | }
56 | return $event;
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
5 | # WebAuthn second factor provider for Nextcloud
6 |
7 | [](https://api.reuse.software/info/github.com/nextcloud/twofactor_webauthn)
8 |
9 | ## Requirements
10 |
11 | In order to use this app for authentication, you have to use a browser that supports the WebAuthn standard.
12 |
13 | ## Migration from Two-Factor U2F
14 |
15 | It is possible to migrate U2F device registrations to WebAuthn devices registrations. For the migratation, you need command line access to run [occ](https://docs.nextcloud.com/server/stable/admin_manual/configuration_server/occ_command.html).
16 |
17 | ```shell
18 | # View options – you can run this for all or only specific users
19 | php occ twofactor_webauthn:migrate-u2f --help
20 |
21 | # Migrate all users
22 | php occ twofactor_webauthn:migrate-u2f --all
23 |
24 | # Disable the U2F app
25 | php occ app:disable twofactor_u2f
26 |
27 | # Clean up any U2F registrations
28 | php occ twofactorauth:cleanup u2f
29 | ```
30 |
31 | ## Login with external apps
32 |
33 | Once you enable WebAuthn with Two Factor WebAuthn, your applications (for example your GNOME app) will need to login using device passwords. Find out more about this in the [user documentation](https://docs.nextcloud.com/server/stable/user_manual/en/user_2fa.html#using-client-applications-with-two-factor-authentication).
34 |
35 | ## Development Setup
36 |
37 | This app uses [composer](https://getcomposer.org/) and [npm](https://www.npmjs.com/) to manage dependencies. Use
38 |
39 | ```bash
40 | composer install
41 | npm install
42 | npm run build
43 | ```
44 |
45 | to set up a development version of this app.
46 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "nextcloud/twofactor_webauthn",
3 | "description": "A two factor provider for WebAuthn devices for Nextcloud",
4 | "type": "project",
5 | "license": "agplv3",
6 | "authors": [
7 | {
8 | "name": "Christoph Wurst"
9 | },
10 | {
11 | "name": "Michael Blumenstein"
12 | }
13 | ],
14 | "require": {
15 | "php": ">=8.1.0",
16 | "ext-json": "*",
17 | "bamarni/composer-bin-plugin": "^1.8.2",
18 | "psr/log": "^2||^3",
19 | "web-auth/webauthn-lib": "^4.9.2"
20 | },
21 | "require-dev": {
22 | "christophwurst/nextcloud_testing": "^1.1.0",
23 | "phpunit/phpunit": "^9.6.31",
24 | "roave/security-advisories": "dev-master"
25 | },
26 | "scripts": {
27 | "lint": "find . -name \\*.php -not -path './vendor/*' -print0 | xargs -0 -n1 php -l",
28 | "cs:check": "php-cs-fixer fix --dry-run --diff",
29 | "cs:fix": "php-cs-fixer fix",
30 | "psalm": "psalm",
31 | "test": "phpunit -c tests/phpunit.xml",
32 | "test:acceptance": "phpunit -c tests/phpunit.xml tests/Acceptance",
33 | "test:integration": "phpunit -c tests/phpunit.xml tests/Integration",
34 | "test:unit": "phpunit -c tests/phpunit.xml tests/Unit",
35 | "test:acceptance:dev": "phpunit -c tests/phpunit.xml tests/Acceptance --no-coverage",
36 | "test:unit:dev": "phpunit -c tests/phpunit.xml tests/Unit --no-coverage --order-by=defects --stop-on-defect --fail-on-warning --stop-on-error --stop-on-failure",
37 | "post-install-cmd": [
38 | "@composer bin all install --ansi"
39 | ],
40 | "post-update-cmd": [
41 | "@composer bin all update --ansi"
42 | ]
43 | },
44 | "config": {
45 | "optimize-autoloader": true,
46 | "classmap-authoritative": true,
47 | "platform": {
48 | "php": "8.1.0"
49 | },
50 | "sort-packages": true,
51 | "allow-plugins": {
52 | "bamarni/composer-bin-plugin": true
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/tests/unit/components/PersonalSettings.spec.js:
--------------------------------------------------------------------------------
1 | /**
2 | * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors
3 | * SPDX-License-Identifier: AGPL-3.0-or-later
4 | */
5 |
6 | import { shallowMount } from '@vue/test-utils'
7 | import { createPinia, setActivePinia } from 'pinia'
8 | import Nextcloud from '../../../mixins/Nextcloud.js'
9 | import PersonalSettings from '../../../components/PersonalSettings.vue'
10 | import { useMainStore } from '../../../store.js'
11 |
12 | describe('PersonalSettings', () => {
13 | let pinia
14 |
15 | beforeEach(() => {
16 | pinia = createPinia()
17 | setActivePinia(pinia)
18 | })
19 |
20 | it('shows text if no devices are configured', () => {
21 | const settings = shallowMount(PersonalSettings, {
22 | global: {
23 | plugins: [pinia],
24 | mixins: [Nextcloud],
25 | },
26 | })
27 |
28 | expect(settings.text()).to.contain('No security keys configured. You are not using WebAuthn as second factor at the moment.')
29 | })
30 |
31 | it('shows no info text if devices are configured', () => {
32 | const mainStore = useMainStore()
33 | mainStore.$patch({
34 | devices: [{
35 | id: 'k1',
36 | name: 'a',
37 | }],
38 | })
39 |
40 | const settings = shallowMount(PersonalSettings, {
41 | global: {
42 | plugins: [pinia],
43 | mixins: [Nextcloud],
44 | },
45 | })
46 |
47 | expect(settings.text()).to.not.contain('No security keys configured. You are not using WebAuthn as second factor at the moment.')
48 | })
49 |
50 | it('shows a HTTP warning', () => {
51 | const settings = shallowMount(PersonalSettings, {
52 | global: {
53 | plugins: [pinia],
54 | mixins: [Nextcloud],
55 | },
56 | propsData: {
57 | httpWarning: true,
58 | },
59 | })
60 |
61 | expect(settings.text()).to.contain('You are accessing this site via an')
62 | })
63 | })
64 |
--------------------------------------------------------------------------------
/lib/Listener/StateChangeRegistryUpdater.php:
--------------------------------------------------------------------------------
1 |
22 | */
23 | class StateChangeRegistryUpdater implements IEventListener {
24 |
25 | /** @var IRegistry */
26 | private $providerRegistry;
27 |
28 | /** @var WebAuthnManager */
29 | private $manager;
30 |
31 | /** @var WebAuthnProvider */
32 | private $provider;
33 |
34 | public function __construct(IRegistry $providerRegistry, WebAuthnManager $manager, WebAuthnProvider $provider) {
35 | $this->providerRegistry = $providerRegistry;
36 | $this->provider = $provider;
37 | $this->manager = $manager;
38 | }
39 |
40 | public function handle(Event $event): void {
41 | if ($event instanceof StateChanged) {
42 | $devices = array_filter(
43 | $this->manager->getDevices($event->getUser()),
44 | static fn (Device $device) => $device->isActive(),
45 | );
46 | $hasDevices = !empty($devices);
47 | if ($hasDevices && $event->isEnabled()) {
48 | // The first device was enabled -> enable provider for this user
49 | $this->providerRegistry->enableProviderFor($this->provider, $event->getUser());
50 | } elseif (!$hasDevices && !$event->isEnabled()) {
51 | // The last device was removed -> disable provider for this user
52 | $this->providerRegistry->disableProviderFor($this->provider, $event->getUser());
53 | }
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/1_bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: 🐞 Bug report
3 | about: Help us to improve by reporting a bug
4 | labels: 0. Needs triage, bug
5 | ---
6 |
7 |
8 |
9 | ### How to use GitHub
10 |
11 | * Please use the 👍 [reaction](https://blog.github.com/2016-03-10-add-reactions-to-pull-requests-issues-and-comments/) to show that you are affected by the same issue.
12 | * Please don't comment if you have no relevant information to add. It's just extra noise for everyone subscribed to this issue.
13 | * Subscribe to receive notifications on status change and new comments.
14 |
15 | ---
16 |
17 | ### Steps to reproduce
18 | 1.
19 | 2.
20 | 3.
21 |
22 | ### Expected behaviour
23 | Tell us what should happen
24 |
25 | ### Actual behaviour
26 | Tell us what happens instead, if possible also add a screenshot
27 |
28 | ### Server configuration
29 |
30 | **Web server:** Apache/Nginx
31 |
32 | **Database:** MySQL/Maria/SQLite/PostgreSQL
33 |
34 | **PHP version:** 8.1/8.2/8.3
35 |
36 | **Nextcloud version:** (see Nextcloud admin page)
37 |
38 |
39 | List of activated apps
40 |
41 | ```
42 | If you have access to your command line run e.g.:
43 | sudo -u www-data php occ app:list
44 | from within your Nextcloud installation folder
45 | ```
46 |
47 |
48 |
49 | Nextcloud configuration
50 |
51 | ```
52 | If you have access to your command line run e.g.:
53 | sudo -u www-data php occ config:list system
54 | from within your Nextcloud installation folder
55 | ```
56 |
57 |
58 | ### Browser
59 |
60 | **Browser name:** Firefox/Chrome/Safari/…
61 |
62 | **Browser version:** 124/125/…
63 |
64 | **Operating system:** Windows/Ubuntu/Mac/…
65 |
66 |
67 | Browser log
68 |
69 | ```
70 | Insert your browser log here, this could for example include:
71 | a) The javascript console log
72 | b) The network log
73 | c) ...
74 | ```
75 |
76 |
77 |
--------------------------------------------------------------------------------
/l10n/zh_CN.json:
--------------------------------------------------------------------------------
1 | { "translations": {
2 | "You added an WebAuthn hardware token" : "您新增了一个 WebAuthn 硬件设备",
3 | "You removed an WebAuthn hardware token" : "您移除了一个 WebAuthn 硬件设备",
4 | "WebAuthn disabled by the administration" : "WebAuthn 已被管理员禁用",
5 | "Security key" : "安全密钥",
6 | "Use WebAuthn for second factor authentication" : "将 WebAuthn 用于两步验证",
7 | "Two-Factor WebAuthn" : "WebAuthn 两步验证",
8 | "WebAuthn two-factor provider" : "WebAuthn 两步验证提供程序",
9 | "A two-factor provider for WebAuthn devices" : "使用 WebAuthn 设备的两步验证提供程序",
10 | "Server error while trying to complete security key registration" : "完成安全密钥注册的过程中发生了服务器错误",
11 | "Add security key" : "添加安全密钥",
12 | "Please use your security key to authorize." : "请使用您的安全密钥进行授权",
13 | "Name your security key" : "命名您的密钥",
14 | "Add" : "添加",
15 | "Adding your security key …" : "正在添加您的安全密钥...",
16 | "Authentication cancelled" : "验证已取消",
17 | "An error occurred: {msg}" : "发生了错误:{msg}",
18 | "Retry" : "重试",
19 | "Use security key" : "使用安全密钥",
20 | "An error occurred. Please try again." : "发生错误。请重试。",
21 | "Your browser does not support WebAuthn." : "您的浏览器不支持 WebAuthn。",
22 | "You are accessing this site via an insecure connection. Browsers might therefore refuse the WebAuthn authentication." : "您正在通过不安全的连接访问此网站。浏览器可能因此拒绝使用 WebAuthn 验证。",
23 | "Unnamed key" : "未命名的密钥",
24 | "Registered" : "已注册",
25 | "Active" : "活动",
26 | "Remove" : "移除",
27 | "Set up a security key as a second factor." : "使用安全密钥进行两步验证",
28 | "Your security key was added successfully. You are now being redirected to the login page." : "您的安全密钥已添加成功。您将被重定向到登录页面。",
29 | "No security keys configured. You are not using WebAuthn as second factor at the moment." : "没有已配置的安全密钥。您目前没有将 WebAuthn 用于两步验证。",
30 | "The following security keys are configured for WebAuthn two-factor authentication:" : "配置用于 WebAuthn 两步验证的安全密钥列表如下:",
31 | "All security keys are deactivated." : "所有安全密钥均已停用。"
32 | },"pluralForm" :"nplurals=1; plural=0;"
33 | }
--------------------------------------------------------------------------------
/l10n/zh_TW.json:
--------------------------------------------------------------------------------
1 | { "translations": {
2 | "You added an WebAuthn hardware token" : "您已新增一個 WebAuthn 硬體權杖",
3 | "You removed an WebAuthn hardware token" : "您已移除一個 WebAuthn 硬體權杖",
4 | "WebAuthn disabled by the administration" : "管理員已停用 WebAuthn",
5 | "Security key" : "安全金鑰",
6 | "Use WebAuthn for second factor authentication" : "使用 WebAuthn 作為第二步驟驗證",
7 | "Two-Factor WebAuthn" : "兩步驟 WebAuthn",
8 | "WebAuthn two-factor provider" : "WebAuthn 兩步驟提供者",
9 | "A two-factor provider for WebAuthn devices" : "WebAuthn 裝置的兩步驟提供者",
10 | "Server error while trying to complete security key registration" : "嘗試完成安全金鑰註冊時發生伺服器錯誤。",
11 | "Add security key" : "新增安全金鑰",
12 | "Please use your security key to authorize." : "請使用您的安全金鑰驗證。",
13 | "Name your security key" : "為您的安全金鑰命名",
14 | "Add" : "新增",
15 | "Adding your security key …" : "正在心憎您的安全金鑰……",
16 | "Authentication cancelled" : "驗證已取消",
17 | "An error occurred: {msg}" : "遇到錯誤:{msg}",
18 | "Retry" : "重試",
19 | "Use security key" : "使用安全金鑰",
20 | "An error occurred. Please try again." : "發生錯誤。請再試一次。",
21 | "Your browser does not support WebAuthn." : "您的瀏覽器不支援 WebAuthn。",
22 | "You are accessing this site via an insecure connection. Browsers might therefore refuse the WebAuthn authentication." : "您正在透過不安全的連線存取此網站。瀏覽器可能會因此拒絕 WebAuthn 驗證。",
23 | "Unnamed key" : "未命名的金鑰",
24 | "Registered" : "已註冊",
25 | "Active" : "作用中",
26 | "Remove" : "移除",
27 | "Set up a security key as a second factor." : "設定安全金鑰作為第二步驟。",
28 | "Your security key was added successfully. You are now being redirected to the login page." : "您的安全金鑰已新增成功。您現在會被重新導向至登入頁面。",
29 | "No security keys configured. You are not using WebAuthn as second factor at the moment." : "尚未設定安全金鑰。您目前無法使用 WebAuthn 作為第二步驟的驗證方式。",
30 | "The following security keys are configured for WebAuthn two-factor authentication:" : "下列安全金鑰已被設定為 WebAuthn 第二步驟驗證使用:",
31 | "All security keys are deactivated." : "所有安全金鑰均已停用。"
32 | },"pluralForm" :"nplurals=1; plural=0;"
33 | }
--------------------------------------------------------------------------------
/l10n/zh_HK.json:
--------------------------------------------------------------------------------
1 | { "translations": {
2 | "You added an WebAuthn hardware token" : "你已新增一個 WebAuthn 硬體檢驗代碼。",
3 | "You removed an WebAuthn hardware token" : "你已移除一個 WebAuthn 硬體檢驗代碼。",
4 | "WebAuthn disabled by the administration" : "WebAuthn 已被管理員停用",
5 | "Security key" : "私密密鑰",
6 | "Use WebAuthn for second factor authentication" : "使用 WebAuthn 進行第二因數身份驗證",
7 | "Two-Factor WebAuthn" : "雙步驟 Webauthn",
8 | "WebAuthn two-factor provider" : "Webauthn 雙步驟認證供應商",
9 | "A two-factor provider for WebAuthn devices" : "Webauthn 裝置的雙步驟驟驗證供應商",
10 | "Server error while trying to complete security key registration" : "嘗試完成私密密鑰註冊時發生伺服器錯誤。",
11 | "Add security key" : "添加私密密鑰",
12 | "Please use your security key to authorize." : "請使用您的私密密鑰授權。",
13 | "Name your security key" : "命名您的私密密鑰",
14 | "Add" : "添加",
15 | "Adding your security key …" : "正在新增你的私密密鑰 …",
16 | "Authentication cancelled" : "驗證已取消",
17 | "An error occurred: {msg}" : "發生錯誤:{msg}",
18 | "Retry" : "重試",
19 | "Use security key" : "使用私密密鑰",
20 | "An error occurred. Please try again." : "發生錯誤,請再試一次。",
21 | "Your browser does not support WebAuthn." : "您的瀏覽器不支援 WebAuthn。",
22 | "You are accessing this site via an insecure connection. Browsers might therefore refuse the WebAuthn authentication." : "您正使用不安全的連線。瀏覽器可能會因此拒絕 WebAuthn 驗證。",
23 | "Unnamed key" : "未命名的密鑰",
24 | "Registered" : "已註冊",
25 | "Active" : "活動的",
26 | "Remove" : "移除",
27 | "Set up a security key as a second factor." : "設置安全密鑰作為第二個因素。",
28 | "Your security key was added successfully. You are now being redirected to the login page." : "您的私密密鑰已添加成功。您現在會被重新導向到登入頁面。",
29 | "No security keys configured. You are not using WebAuthn as second factor at the moment." : "尚未設定私密密鑰。您現階段無法使用 WebAuthn 進行雙重認證。",
30 | "The following security keys are configured for WebAuthn two-factor authentication:" : "下列私密密鑰已被設定為 WebAuthn 雙重認證使用。",
31 | "All security keys are deactivated." : "所有私密密鑰均已停用。"
32 | },"pluralForm" :"nplurals=1; plural=0;"
33 | }
--------------------------------------------------------------------------------
/l10n/zh_CN.js:
--------------------------------------------------------------------------------
1 | OC.L10N.register(
2 | "twofactor_webauthn",
3 | {
4 | "You added an WebAuthn hardware token" : "您新增了一个 WebAuthn 硬件设备",
5 | "You removed an WebAuthn hardware token" : "您移除了一个 WebAuthn 硬件设备",
6 | "WebAuthn disabled by the administration" : "WebAuthn 已被管理员禁用",
7 | "Security key" : "安全密钥",
8 | "Use WebAuthn for second factor authentication" : "将 WebAuthn 用于两步验证",
9 | "Two-Factor WebAuthn" : "WebAuthn 两步验证",
10 | "WebAuthn two-factor provider" : "WebAuthn 两步验证提供程序",
11 | "A two-factor provider for WebAuthn devices" : "使用 WebAuthn 设备的两步验证提供程序",
12 | "Server error while trying to complete security key registration" : "完成安全密钥注册的过程中发生了服务器错误",
13 | "Add security key" : "添加安全密钥",
14 | "Please use your security key to authorize." : "请使用您的安全密钥进行授权",
15 | "Name your security key" : "命名您的密钥",
16 | "Add" : "添加",
17 | "Adding your security key …" : "正在添加您的安全密钥...",
18 | "Authentication cancelled" : "验证已取消",
19 | "An error occurred: {msg}" : "发生了错误:{msg}",
20 | "Retry" : "重试",
21 | "Use security key" : "使用安全密钥",
22 | "An error occurred. Please try again." : "发生错误。请重试。",
23 | "Your browser does not support WebAuthn." : "您的浏览器不支持 WebAuthn。",
24 | "You are accessing this site via an insecure connection. Browsers might therefore refuse the WebAuthn authentication." : "您正在通过不安全的连接访问此网站。浏览器可能因此拒绝使用 WebAuthn 验证。",
25 | "Unnamed key" : "未命名的密钥",
26 | "Registered" : "已注册",
27 | "Active" : "活动",
28 | "Remove" : "移除",
29 | "Set up a security key as a second factor." : "使用安全密钥进行两步验证",
30 | "Your security key was added successfully. You are now being redirected to the login page." : "您的安全密钥已添加成功。您将被重定向到登录页面。",
31 | "No security keys configured. You are not using WebAuthn as second factor at the moment." : "没有已配置的安全密钥。您目前没有将 WebAuthn 用于两步验证。",
32 | "The following security keys are configured for WebAuthn two-factor authentication:" : "配置用于 WebAuthn 两步验证的安全密钥列表如下:",
33 | "All security keys are deactivated." : "所有安全密钥均已停用。"
34 | },
35 | "nplurals=1; plural=0;");
36 |
--------------------------------------------------------------------------------
/l10n/zh_TW.js:
--------------------------------------------------------------------------------
1 | OC.L10N.register(
2 | "twofactor_webauthn",
3 | {
4 | "You added an WebAuthn hardware token" : "您已新增一個 WebAuthn 硬體權杖",
5 | "You removed an WebAuthn hardware token" : "您已移除一個 WebAuthn 硬體權杖",
6 | "WebAuthn disabled by the administration" : "管理員已停用 WebAuthn",
7 | "Security key" : "安全金鑰",
8 | "Use WebAuthn for second factor authentication" : "使用 WebAuthn 作為第二步驟驗證",
9 | "Two-Factor WebAuthn" : "兩步驟 WebAuthn",
10 | "WebAuthn two-factor provider" : "WebAuthn 兩步驟提供者",
11 | "A two-factor provider for WebAuthn devices" : "WebAuthn 裝置的兩步驟提供者",
12 | "Server error while trying to complete security key registration" : "嘗試完成安全金鑰註冊時發生伺服器錯誤。",
13 | "Add security key" : "新增安全金鑰",
14 | "Please use your security key to authorize." : "請使用您的安全金鑰驗證。",
15 | "Name your security key" : "為您的安全金鑰命名",
16 | "Add" : "新增",
17 | "Adding your security key …" : "正在心憎您的安全金鑰……",
18 | "Authentication cancelled" : "驗證已取消",
19 | "An error occurred: {msg}" : "遇到錯誤:{msg}",
20 | "Retry" : "重試",
21 | "Use security key" : "使用安全金鑰",
22 | "An error occurred. Please try again." : "發生錯誤。請再試一次。",
23 | "Your browser does not support WebAuthn." : "您的瀏覽器不支援 WebAuthn。",
24 | "You are accessing this site via an insecure connection. Browsers might therefore refuse the WebAuthn authentication." : "您正在透過不安全的連線存取此網站。瀏覽器可能會因此拒絕 WebAuthn 驗證。",
25 | "Unnamed key" : "未命名的金鑰",
26 | "Registered" : "已註冊",
27 | "Active" : "作用中",
28 | "Remove" : "移除",
29 | "Set up a security key as a second factor." : "設定安全金鑰作為第二步驟。",
30 | "Your security key was added successfully. You are now being redirected to the login page." : "您的安全金鑰已新增成功。您現在會被重新導向至登入頁面。",
31 | "No security keys configured. You are not using WebAuthn as second factor at the moment." : "尚未設定安全金鑰。您目前無法使用 WebAuthn 作為第二步驟的驗證方式。",
32 | "The following security keys are configured for WebAuthn two-factor authentication:" : "下列安全金鑰已被設定為 WebAuthn 第二步驟驗證使用:",
33 | "All security keys are deactivated." : "所有安全金鑰均已停用。"
34 | },
35 | "nplurals=1; plural=0;");
36 |
--------------------------------------------------------------------------------
/appinfo/info.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 | twofactor_webauthn
8 | Two-Factor WebAuthn
9 | WebAuthn two-factor provider
10 | A two-factor provider for WebAuthn devices
11 | 2.5.0-dev.0
12 | agpl
13 | Christoph Wurst
14 | Michael Blumenstein
15 | Richard Steinmetz
16 | TwoFactorWebauthn
17 | security
18 |
19 | https://github.com/nextcloud/twofactor_webauthn#readme
20 | https://github.com/nextcloud/twofactor_webauthn/issues
21 | https://github.com/nextcloud/twofactor_webauthn.git
22 |
23 | https://raw.githubusercontent.com/nextcloud/twofactor_webauthn/main/screenshots/challenge.png
24 |
25 |
26 |
27 | gmp
28 |
29 |
30 |
31 |
32 |
33 | OCA\TwoFactorWebauthn\Migration\RepairProviderRegistrations
34 |
35 |
36 |
37 |
38 | OCA\TwoFactorWebauthn\Provider\WebAuthnProvider
39 |
40 |
41 |
42 | OCA\TwoFactorWebauthn\Command\CleanUp
43 | OCA\TwoFactorWebauthn\Command\MigrateU2F
44 |
45 |
46 |
47 |
48 | OCA\TwoFactorWebauthn\Activity\Setting
49 |
50 |
51 | OCA\TwoFactorWebauthn\Activity\Provider
52 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/l10n/zh_HK.js:
--------------------------------------------------------------------------------
1 | OC.L10N.register(
2 | "twofactor_webauthn",
3 | {
4 | "You added an WebAuthn hardware token" : "你已新增一個 WebAuthn 硬體檢驗代碼。",
5 | "You removed an WebAuthn hardware token" : "你已移除一個 WebAuthn 硬體檢驗代碼。",
6 | "WebAuthn disabled by the administration" : "WebAuthn 已被管理員停用",
7 | "Security key" : "私密密鑰",
8 | "Use WebAuthn for second factor authentication" : "使用 WebAuthn 進行第二因數身份驗證",
9 | "Two-Factor WebAuthn" : "雙步驟 Webauthn",
10 | "WebAuthn two-factor provider" : "Webauthn 雙步驟認證供應商",
11 | "A two-factor provider for WebAuthn devices" : "Webauthn 裝置的雙步驟驟驗證供應商",
12 | "Server error while trying to complete security key registration" : "嘗試完成私密密鑰註冊時發生伺服器錯誤。",
13 | "Add security key" : "添加私密密鑰",
14 | "Please use your security key to authorize." : "請使用您的私密密鑰授權。",
15 | "Name your security key" : "命名您的私密密鑰",
16 | "Add" : "添加",
17 | "Adding your security key …" : "正在新增你的私密密鑰 …",
18 | "Authentication cancelled" : "驗證已取消",
19 | "An error occurred: {msg}" : "發生錯誤:{msg}",
20 | "Retry" : "重試",
21 | "Use security key" : "使用私密密鑰",
22 | "An error occurred. Please try again." : "發生錯誤,請再試一次。",
23 | "Your browser does not support WebAuthn." : "您的瀏覽器不支援 WebAuthn。",
24 | "You are accessing this site via an insecure connection. Browsers might therefore refuse the WebAuthn authentication." : "您正使用不安全的連線。瀏覽器可能會因此拒絕 WebAuthn 驗證。",
25 | "Unnamed key" : "未命名的密鑰",
26 | "Registered" : "已註冊",
27 | "Active" : "活動的",
28 | "Remove" : "移除",
29 | "Set up a security key as a second factor." : "設置安全密鑰作為第二個因素。",
30 | "Your security key was added successfully. You are now being redirected to the login page." : "您的私密密鑰已添加成功。您現在會被重新導向到登入頁面。",
31 | "No security keys configured. You are not using WebAuthn as second factor at the moment." : "尚未設定私密密鑰。您現階段無法使用 WebAuthn 進行雙重認證。",
32 | "The following security keys are configured for WebAuthn two-factor authentication:" : "下列私密密鑰已被設定為 WebAuthn 雙重認證使用。",
33 | "All security keys are deactivated." : "所有私密密鑰均已停用。"
34 | },
35 | "nplurals=1; plural=0;");
36 |
--------------------------------------------------------------------------------
/lib/Controller/SettingsController.php:
--------------------------------------------------------------------------------
1 | manager = $manager;
29 | $this->userSession = $userSession;
30 | }
31 |
32 | /**
33 | * @NoAdminRequired
34 | * @PasswordConfirmationRequired
35 | * @UseSession
36 | */
37 | public function startRegister(): JSONResponse {
38 | return new JSONResponse($this->manager->startRegistration($this->userSession->getUser(), $this->request->getServerHost()));
39 | }
40 |
41 | /**
42 | * @NoAdminRequired
43 | * @PasswordConfirmationRequired
44 | *
45 | * @param string $name
46 | * @param string $data
47 | */
48 | public function finishRegister(string $name, string $data): JSONResponse {
49 | return new JSONResponse(
50 | $this->manager->finishRegister(
51 | $this->userSession->getUser(),
52 | $name,
53 | $data
54 | )
55 | );
56 | }
57 |
58 | /**
59 | * @NoAdminRequired
60 | * @PasswordConfirmationRequired
61 | */
62 | public function remove(int $id): JSONResponse {
63 | $this->manager->removeDevice($this->userSession->getUser(), $id);
64 | return new JSONResponse([]);
65 | }
66 |
67 | /**
68 | * @NoAdminRequired
69 | * @PasswordConfirmationRequired
70 | */
71 | public function changeActivationState(int $id, bool $active): JSONResponse {
72 | $this->manager->changeActivationState($this->userSession->getUser(), $id, $active);
73 | return new JSONResponse([]);
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/src/components/PersonalSettings.vue:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 | {{ t('twofactor_webauthn', 'No security keys configured. You are not using WebAuthn as second factor at the moment.') }}
10 |
11 |
12 | {{ t('twofactor_webauthn', 'The following security keys are configured for WebAuthn two-factor authentication:') }}
13 |
28 |
29 | {{ t('twofactor_webauthn', 'Your browser does not support WebAuthn.') }}
30 |
31 |
32 |
33 | {{ t('twofactor_webauthn', 'You are accessing this site via an insecure connection. Browsers might therefore refuse the WebAuthn authentication.') }}
34 |
35 |
36 |
37 |
38 |
66 |
67 |
69 |
--------------------------------------------------------------------------------
/lib/Service/U2FMigrator.php:
--------------------------------------------------------------------------------
1 | base64_urlsafe_decode($registration->getKeyHandle());
45 |
46 | // AAGUID is not required for legacy U2F sources and should be all zeros
47 | $aaguid = $this->zeroUuid();
48 |
49 | // Decode U2F key and reuse it
50 | // Raw format of u2f key: 0x4 . [x: 32 bytes] . [y: 32 bytes]
51 | $decodedPublicKey = base64_decode($registration->getPublicKey(), true);
52 |
53 | return new PublicKeyCredentialSource(
54 | $credentialId,
55 | PublicKeyCredentialDescriptor::CREDENTIAL_TYPE_PUBLIC_KEY,
56 | [],
57 | $attestationType,
58 | $trustPath,
59 | $aaguid,
60 | $decodedPublicKey,
61 | $registration->getUserId(),
62 | $registration->getCounter(),
63 | );
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/.github/workflows/lint-php.yml:
--------------------------------------------------------------------------------
1 | # This workflow is provided via the organization template repository
2 | #
3 | # https://github.com/nextcloud/.github
4 | # https://docs.github.com/en/actions/learn-github-actions/sharing-workflows-with-your-organization
5 | #
6 | # SPDX-FileCopyrightText: 2021-2024 Nextcloud GmbH and Nextcloud contributors
7 | # SPDX-License-Identifier: MIT
8 |
9 | name: Lint php
10 |
11 | on: pull_request
12 |
13 | permissions:
14 | contents: read
15 |
16 | concurrency:
17 | group: lint-php-${{ github.head_ref || github.run_id }}
18 | cancel-in-progress: true
19 |
20 | jobs:
21 | matrix:
22 | runs-on: ubuntu-latest-low
23 | outputs:
24 | php-versions: ${{ steps.versions.outputs.php-versions }}
25 | steps:
26 | - name: Checkout app
27 | uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
28 | - name: Get version matrix
29 | id: versions
30 | uses: icewind1991/nextcloud-version-matrix@58becf3b4bb6dc6cef677b15e2fd8e7d48c0908f # v1.3.1
31 |
32 | php-lint:
33 | runs-on: ubuntu-latest
34 | needs: matrix
35 | strategy:
36 | matrix:
37 | php-versions: ${{fromJson(needs.matrix.outputs.php-versions)}}
38 |
39 | name: php-lint
40 |
41 | steps:
42 | - name: Checkout
43 | uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
44 |
45 | - name: Set up php ${{ matrix.php-versions }}
46 | uses: shivammathur/setup-php@cf4cade2721270509d5b1c766ab3549210a39a2a # 2.33.0
47 | with:
48 | php-version: ${{ matrix.php-versions }}
49 | extensions: bz2, ctype, curl, dom, fileinfo, gd, iconv, intl, json, libxml, mbstring, openssl, pcntl, posix, session, simplexml, xmlreader, xmlwriter, zip, zlib, sqlite, pdo_sqlite
50 | coverage: none
51 | ini-file: development
52 | env:
53 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
54 |
55 | - name: Lint
56 | run: composer run lint
57 |
58 | summary:
59 | permissions:
60 | contents: none
61 | runs-on: ubuntu-latest-low
62 | needs: php-lint
63 |
64 | if: always()
65 |
66 | name: php-lint-summary
67 |
68 | steps:
69 | - name: Summary status
70 | run: if ${{ needs.php-lint.result != 'success' && needs.php-lint.result != 'skipped' }}; then exit 1; fi
71 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "twofactor_webauthn",
3 | "version": "2.5.0-dev.0",
4 | "description": "WebAuthn second factor provider for Nextcloud",
5 | "private": true,
6 | "dependencies": {
7 | "@nextcloud/auth": "^2.5.3",
8 | "@nextcloud/axios": "^2.5.2",
9 | "@nextcloud/initial-state": "^3.0.0",
10 | "@nextcloud/logger": "^3.0.2",
11 | "@nextcloud/moment": "^1.3.5",
12 | "@nextcloud/password-confirmation": "^6.0.2",
13 | "@nextcloud/router": "^3.1.0",
14 | "@nextcloud/vue": "^9.3.0",
15 | "@simplewebauthn/browser": "^13.2.2",
16 | "pinia": "^3.0.4",
17 | "vue": "^3.5.25",
18 | "vue-material-design-icons": "^5.3.1"
19 | },
20 | "devDependencies": {
21 | "@nextcloud/babel-config": "^1.2.0",
22 | "@nextcloud/eslint-config": "^8.4.2",
23 | "@nextcloud/webpack-vue-config": "^6.3.0",
24 | "@playwright/test": "^1.55.0",
25 | "@vue/test-utils": "^2.4.6",
26 | "chai": "^4.5.0",
27 | "jsdom": "^21.1.2",
28 | "jsdom-global": "^3.0.2",
29 | "mocha": "^10.8.2",
30 | "mochapack": "^2.1.5"
31 | },
32 | "scripts": {
33 | "dev": "webpack --node-env development --progress",
34 | "watch": "webpack --node-env development --progress --watch",
35 | "build": "webpack --node-env production --progress",
36 | "lint": "eslint --ext .js,.vue src",
37 | "lint:fix": "eslint --ext .js,.vue src --fix",
38 | "test:unit": "mochapack --mode development --webpack-config webpack.test.config.js --require src/tests/unit/setup.js src/tests/unit/**/*.spec.js",
39 | "test:unit:watch": "mochapack --mode development -w --webpack-config webpack.test.config.js --require src/tests/unit/setup.js src/tests/unit/**/*.spec.js",
40 | "test:e2e": "playwright test",
41 | "test:e2e:ui": "playwright test --ui"
42 | },
43 | "browserslist": [
44 | "last 2 versions",
45 | "ie >= 11"
46 | ],
47 | "engines": {
48 | "node": "^22.0.0",
49 | "npm": "^10.5.0"
50 | },
51 | "jshintConfig": {
52 | "esversion": 6
53 | },
54 | "repository": {
55 | "type": "git",
56 | "url": "git+https://github.com/nextcloud/twofactor_webauthn.git"
57 | },
58 | "author": "Christoph Wurst",
59 | "license": "AGPL-3.0-or-later",
60 | "bugs": {
61 | "url": "https://github.com/nextcloud/twofactor_webauthn/issues"
62 | },
63 | "homepage": "https://github.com/nextcloud/twofactor_webauthn#readme"
64 | }
65 |
--------------------------------------------------------------------------------
/AUTHORS.md:
--------------------------------------------------------------------------------
1 |
5 | # Authors
6 |
7 | - Alexander Paetzelt <36155797+alex-nitrokey@users.noreply.github.com>
8 | - Andy Scherzinger
9 | - Ashutosh Verma <81686677+ashuio@users.noreply.github.com>
10 | - Austin Bohannon
11 | - Ben Schumacher
12 | - Christoph Wurst
13 | - Christopher Ng
14 | - comradekingu
15 | - Daniel Kesselberg
16 | - danielkr123
17 | - Ferdinand Thiessen
18 | - j-ed
19 | - Jan-Christoph Borchardt
20 | - Joas Schilling
21 | - John Molakvoæ
22 | - Lukas Reschke
23 | - Michael Blumenstein
24 | - mjanssens <24758392+mjanssens@users.noreply.github.com>
25 | - Morris Jobke
26 | - Oliv4945
27 | - Pablo Hinojosa
28 | - rakekniven
29 | - Richard Steinmetz
30 | - Robin Appelman
31 | - Roeland Jago Douma
32 | - Simon Dellenbach
33 | - Simon Spannagel
34 | - Somebodyisnobody <35230554+Somebodyisnobody@users.noreply.github.com>
35 | - Valdnet <47037905+Valdnet@users.noreply.github.com>
36 | - Vincent Petry
37 | - Xaver Maierhofer
38 | - Zev Lee <60147316+zevlee@users.noreply.github.com>
39 | # Authors
40 |
41 | - 2018 Christoph Wurst
42 | - 2022 Christoph Wurst
43 | - 2023 Richard Steinmetz
44 | - Christoph Wurst
45 | - Christoph Wurst
46 | - Daniel Kesselberg
47 | - Daniel Kesselberg
48 | - Michael Blumenstein
49 | - Richard Steinmetz
50 | - Richard Steinmetz
51 | - Richard Steinmetz
52 | - Zev Lee <60147316+zevlee@users.noreply.github.com>
53 | - Zev Lee <60147316+zevlee@users.noreply.github.com>
54 |
--------------------------------------------------------------------------------
/REUSE.toml:
--------------------------------------------------------------------------------
1 | # SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
2 | # SPDX-License-Identifier: AGPL-3.0-or-later
3 | version = 1
4 | SPDX-PackageName = "twofactor_webauthn"
5 | SPDX-PackageSupplier = "Nextcloud "
6 | SPDX-PackageDownloadLocation = "https://github.com/nextcloud/twofactor_webauthn"
7 |
8 | [[annotations]]
9 | path = ["l10n/**.js", "l10n/**.json"]
10 | precedence = "aggregate"
11 | SPDX-FileCopyrightText = "2016-2024 Nextcloud translators"
12 | SPDX-License-Identifier = "AGPL-3.0-or-later"
13 |
14 | [[annotations]]
15 | path = ["composer.json", "composer.lock"]
16 | precedence = "aggregate"
17 | SPDX-FileCopyrightText = "2016 Nextcloud GmbH and Nextcloud contributors"
18 | SPDX-License-Identifier = "AGPL-3.0-or-later"
19 |
20 | [[annotations]]
21 | path = ["package.json", "package-lock.json"]
22 | precedence = "aggregate"
23 | SPDX-FileCopyrightText = "2017 Nextcloud GmbH and Nextcloud contributors"
24 | SPDX-License-Identifier = "AGPL-3.0-or-later"
25 |
26 | [[annotations]]
27 | path = [".tx/config", ".babelrc"]
28 | precedence = "aggregate"
29 | SPDX-FileCopyrightText = "2018 Nextcloud GmbH and Nextcloud contributors"
30 | SPDX-License-Identifier = "AGPL-3.0-or-later"
31 |
32 | [[annotations]]
33 | path = [".jshintrc", ".babelrc"]
34 | precedence = "aggregate"
35 | SPDX-FileCopyrightText = "2019 Nextcloud GmbH and Nextcloud contributors"
36 | SPDX-License-Identifier = "AGPL-3.0-or-later"
37 |
38 | [[annotations]]
39 | path = ["vendor-bin/cs-fixer/composer.json", "vendor-bin/cs-fixer/composer.lock"]
40 | precedence = "aggregate"
41 | SPDX-FileCopyrightText = "2022 Nextcloud GmbH and Nextcloud contributors"
42 | SPDX-License-Identifier = "AGPL-3.0-or-later"
43 |
44 | [[annotations]]
45 | path = ["vendor-bin/psalm/composer.json", "vendor-bin/psalm/composer.lock"]
46 | precedence = "aggregate"
47 | SPDX-FileCopyrightText = "2025 Nextcloud GmbH and Nextcloud contributors"
48 | SPDX-License-Identifier = "AGPL-3.0-or-later"
49 |
50 | [[annotations]]
51 | path = ["renovate.json"]
52 | precedence = "aggregate"
53 | SPDX-FileCopyrightText = "2023 Nextcloud GmbH and Nextcloud contributors"
54 | SPDX-License-Identifier = "AGPL-3.0-or-later"
55 |
56 | [[annotations]]
57 | path = ["img/app.svg", "img/app-dark.svg", "img/device-disabled.svg"]
58 | precedence = "aggregate"
59 | SPDX-FileCopyrightText = "2018-2024 Google LLC"
60 | SPDX-License-Identifier = "Apache-2.0"
61 |
62 | [[annotations]]
63 | path = ".github/CODEOWNERS"
64 | precedence = "aggregate"
65 | SPDX-FileCopyrightText = "2025 Nextcloud GmbH and Nextcloud contributors"
66 | SPDX-License-Identifier = "AGPL-3.0-or-later"
67 |
--------------------------------------------------------------------------------
/l10n/ru.json:
--------------------------------------------------------------------------------
1 | { "translations": {
2 | "You added an WebAuthn hardware token" : "Вы добавили аппаратный токен WebAuthn",
3 | "You removed an WebAuthn hardware token" : "Вы удалили аппаратный токен WebAuthn",
4 | "WebAuthn disabled by the administration" : "WebAuthn отключен администрацией",
5 | "Security key" : "Ключ безопасности",
6 | "Use WebAuthn for second factor authentication" : "Используйте WebAuthn для двухфакторной аутентификации",
7 | "Two-Factor WebAuthn" : "Двухфакторный WebAuthn",
8 | "WebAuthn two-factor provider" : "Двухфакторный провайдер WebAuthn",
9 | "A two-factor provider for WebAuthn devices" : "Двухфакторный провайдер для устройств WebAuthn",
10 | "Server error while trying to complete security key registration" : "Ошибка сервера при попытке завершить регистрацию ключа безопасности",
11 | "Add security key" : "Добавить ключ безопасности",
12 | "Name your security key" : "Назовите свой ключ безопасности",
13 | "Add" : "Добавить",
14 | "Adding your security key …" : "Добавление вашего ключа безопасности …",
15 | "An error occurred: {msg}" : "Произошла ошибка: {msg}",
16 | "Retry" : "Повторить",
17 | "Use security key" : "Использовать ключ безопасности",
18 | "An error occurred. Please try again." : "Произошла ошибка. Попробуйте ещё раз.",
19 | "Your browser does not support WebAuthn." : "Ваш браузер не поддерживает WebAuthn.",
20 | "You are accessing this site via an insecure connection. Browsers might therefore refuse the WebAuthn authentication." : "Вы заходите на этот сайт через небезопасное соединение. Поэтому браузеры могут отказаться от проверки подлинности WebAuthn.",
21 | "Unnamed key" : "Безымянный ключ",
22 | "Active" : "Активный",
23 | "Remove" : "Удалить",
24 | "Your security key was added successfully. You are now being redirected to the login page." : "Ваш ключ безопасности был успешно добавлен. Теперь вы перенаправлены на страницу входа в систему.",
25 | "No security keys configured. You are not using WebAuthn as second factor at the moment." : "Ключи безопасности не настроены. В данный момент вы не используете WebAuthn в качестве двухэтапной авторизации.",
26 | "The following security keys are configured for WebAuthn two-factor authentication:" : "Следующие ключи безопасности настроены для двухфакторной аутентификации WebAuthn:",
27 | "All security keys are deactivated." : "Все ключи безопасности деактивированы."
28 | },"pluralForm" :"nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);"
29 | }
--------------------------------------------------------------------------------
/lib/Command/CleanUp.php:
--------------------------------------------------------------------------------
1 | db = $db;
39 | $this->userManager = $userManager;
40 | $this->webauthnMapper = $webauthnMapper;
41 | }
42 |
43 | protected function configure(): void {
44 | $this
45 | ->setName('twofactor_webauthn:cleanup')
46 | ->setDescription('Remove orphaned webauthn credentials');
47 | }
48 |
49 | protected function execute(InputInterface $input, OutputInterface $output): int {
50 | $io = new SymfonyStyle($input, $output);
51 | $io->title('Remove webauthn credentials for deleted users');
52 |
53 | foreach ($this->findUserIds() as $userId) {
54 | if ($this->userManager->userExists($userId) === false) {
55 | try {
56 | $io->text('Delete credentials for uid "' . $userId . '"');
57 | $this->webauthnMapper->deletePublicKeyCredentialsByUserId($userId);
58 | } catch (Exception $e) {
59 | $io->caution('Error deleting credentials: ' . $e->getMessage());
60 | }
61 | }
62 | }
63 |
64 | $io->success('Orphaned webauthn credentials removed.');
65 |
66 | $io->text('Thank you for using Two-Factor WebAuthn!');
67 | return 0;
68 | }
69 |
70 | /**
71 | * @throws Exception
72 | */
73 | private function findUserIds(): array {
74 | $userIds = [];
75 |
76 | $qb = $this->db->getQueryBuilder()
77 | ->selectDistinct('user_handle')
78 | ->from($this->webauthnMapper->getTableName());
79 |
80 | $result = $qb->executeQuery();
81 |
82 | while ($row = $result->fetch()) {
83 | $userIds[] = $row['user_handle'];
84 | }
85 |
86 | $result->closeCursor();
87 |
88 | return $userIds;
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/l10n/ru.js:
--------------------------------------------------------------------------------
1 | OC.L10N.register(
2 | "twofactor_webauthn",
3 | {
4 | "You added an WebAuthn hardware token" : "Вы добавили аппаратный токен WebAuthn",
5 | "You removed an WebAuthn hardware token" : "Вы удалили аппаратный токен WebAuthn",
6 | "WebAuthn disabled by the administration" : "WebAuthn отключен администрацией",
7 | "Security key" : "Ключ безопасности",
8 | "Use WebAuthn for second factor authentication" : "Используйте WebAuthn для двухфакторной аутентификации",
9 | "Two-Factor WebAuthn" : "Двухфакторный WebAuthn",
10 | "WebAuthn two-factor provider" : "Двухфакторный провайдер WebAuthn",
11 | "A two-factor provider for WebAuthn devices" : "Двухфакторный провайдер для устройств WebAuthn",
12 | "Server error while trying to complete security key registration" : "Ошибка сервера при попытке завершить регистрацию ключа безопасности",
13 | "Add security key" : "Добавить ключ безопасности",
14 | "Name your security key" : "Назовите свой ключ безопасности",
15 | "Add" : "Добавить",
16 | "Adding your security key …" : "Добавление вашего ключа безопасности …",
17 | "An error occurred: {msg}" : "Произошла ошибка: {msg}",
18 | "Retry" : "Повторить",
19 | "Use security key" : "Использовать ключ безопасности",
20 | "An error occurred. Please try again." : "Произошла ошибка. Попробуйте ещё раз.",
21 | "Your browser does not support WebAuthn." : "Ваш браузер не поддерживает WebAuthn.",
22 | "You are accessing this site via an insecure connection. Browsers might therefore refuse the WebAuthn authentication." : "Вы заходите на этот сайт через небезопасное соединение. Поэтому браузеры могут отказаться от проверки подлинности WebAuthn.",
23 | "Unnamed key" : "Безымянный ключ",
24 | "Active" : "Активный",
25 | "Remove" : "Удалить",
26 | "Your security key was added successfully. You are now being redirected to the login page." : "Ваш ключ безопасности был успешно добавлен. Теперь вы перенаправлены на страницу входа в систему.",
27 | "No security keys configured. You are not using WebAuthn as second factor at the moment." : "Ключи безопасности не настроены. В данный момент вы не используете WebAuthn в качестве двухэтапной авторизации.",
28 | "The following security keys are configured for WebAuthn two-factor authentication:" : "Следующие ключи безопасности настроены для двухфакторной аутентификации WebAuthn:",
29 | "All security keys are deactivated." : "Все ключи безопасности деактивированы."
30 | },
31 | "nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);");
32 |
--------------------------------------------------------------------------------
/l10n/en_GB.json:
--------------------------------------------------------------------------------
1 | { "translations": {
2 | "You added an WebAuthn hardware token" : "You added an WebAuthn hardware token",
3 | "You removed an WebAuthn hardware token" : "You removed an WebAuthn hardware token",
4 | "WebAuthn disabled by the administration" : "WebAuthn disabled by the administration",
5 | "Security key" : "Security key",
6 | "Use WebAuthn for second factor authentication" : "Use WebAuthn for second factor authentication",
7 | "Two-Factor WebAuthn" : "Two-Factor WebAuthn",
8 | "WebAuthn two-factor provider" : "WebAuthn two-factor provider",
9 | "A two-factor provider for WebAuthn devices" : "A two-factor provider for WebAuthn devices",
10 | "Server error while trying to complete security key registration" : "Server error while trying to complete security key registration",
11 | "Add security key" : "Add security key",
12 | "Please use your security key to authorize." : "Please use your security key to authorise.",
13 | "Name your security key" : "Name your security key",
14 | "Add" : "Add",
15 | "Adding your security key …" : "Adding your security key …",
16 | "Authentication cancelled" : "Authentication cancelled",
17 | "An error occurred: {msg}" : "An error occurred: {msg}",
18 | "Retry" : "Retry",
19 | "Use security key" : "Use security key",
20 | "An error occurred. Please try again." : "An error occurred. Please try again.",
21 | "Your browser does not support WebAuthn." : "Your browser does not support WebAuthn.",
22 | "You are accessing this site via an insecure connection. Browsers might therefore refuse the WebAuthn authentication." : "You are accessing this site via an insecure connection. Browsers might therefore refuse the WebAuthn authentication.",
23 | "Unnamed key" : "Unnamed key",
24 | "Registered" : "Registered",
25 | "Active" : "Active",
26 | "Remove" : "Remove",
27 | "Set up a security key as a second factor." : "Set up a security key as a second factor.",
28 | "Your security key was added successfully. You are now being redirected to the login page." : "Your security key was added successfully. You are now being redirected to the login page.",
29 | "No security keys configured. You are not using WebAuthn as second factor at the moment." : "No security keys configured. You are not using WebAuthn as second factor at the moment.",
30 | "The following security keys are configured for WebAuthn two-factor authentication:" : "The following security keys are configured for WebAuthn two-factor authentication:",
31 | "All security keys are deactivated." : "All security keys are deactivated."
32 | },"pluralForm" :"nplurals=2; plural=(n != 1);"
33 | }
--------------------------------------------------------------------------------
/lib/Migration/Version000102Date20191004200147.php:
--------------------------------------------------------------------------------
1 | hasTable('twofactor_webauthn_registrations')) {
31 | $table = $schema->createTable('twofactor_webauthn_registrations');
32 | $table->addColumn('id', 'integer', [
33 | 'autoincrement' => true,
34 | 'notnull' => true,
35 | 'length' => 255,
36 | ]);
37 | $table->addColumn('name', 'string', [
38 | 'notnull' => true,
39 | 'length' => 64,
40 | 'default' => 'default'
41 | ]);
42 | $table->addColumn('public_key_credential_id', 'string', [
43 | 'notnull' => true,
44 | 'length' => 255
45 | ]);
46 | $table->addColumn('type', 'string', [
47 | 'notnull' => true,
48 | 'length' => 30,
49 | ]);
50 | $table->addColumn('transports', 'string', [
51 | 'notnull' => true,
52 | 'length' => 30,
53 | ]);
54 | $table->addColumn('attestation_type', 'string', [
55 | 'notnull' => true,
56 | 'length' => 6,
57 | ]);
58 | $table->addColumn('trust_path', 'string', [
59 | 'notnull' => true,
60 | 'length' => 2500,
61 | ]);
62 | $table->addColumn('aaguid', 'string', [
63 | 'notnull' => false,
64 | 'length' => 36,
65 | ]);
66 | $table->addColumn('credential_public_key', 'string', [
67 | 'notnull' => true,
68 | 'length' => 2000,
69 | ]);
70 | $table->addColumn('user_handle', 'string', [
71 | 'notnull' => true,
72 | 'length' => 64
73 | ]);
74 | $table->addColumn('counter', 'integer', [
75 | 'notnull' => true,
76 | 'length' => 255
77 | ]);
78 | $table->setPrimaryKey(['id']);
79 | $table->addIndex(['user_handle'], 'webauthn_registrations_userHandle');
80 | $table->addIndex(['public_key_credential_id'], 'webauthn_registrations_publicKeyCredentialId');
81 | }
82 | */
83 |
84 | return $schema;
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/l10n/fa.json:
--------------------------------------------------------------------------------
1 | { "translations": {
2 | "You added an WebAuthn hardware token" : "You added an WebAuthn hardware token",
3 | "You removed an WebAuthn hardware token" : "You removed an WebAuthn hardware token",
4 | "WebAuthn disabled by the administration" : "WebAuthn disabled by the administration",
5 | "Security key" : "Security key",
6 | "Use WebAuthn for second factor authentication" : "Use WebAuthn for second factor authentication",
7 | "Two-Factor WebAuthn" : "Two-Factor WebAuthn",
8 | "WebAuthn two-factor provider" : "WebAuthn two-factor provider",
9 | "A two-factor provider for WebAuthn devices" : "A two-factor provider for WebAuthn devices",
10 | "Server error while trying to complete security key registration" : "Server error while trying to complete security key registration",
11 | "Add security key" : "Add security key",
12 | "Please use your security key to authorize." : "Please use your security key to authorize.",
13 | "Name your security key" : "Name your security key",
14 | "Add" : "افزودن",
15 | "Adding your security key …" : "Adding your security key …",
16 | "Authentication cancelled" : "Authentication cancelled",
17 | "An error occurred: {msg}" : "An error occurred: {msg}",
18 | "Retry" : "تلاش دوباره",
19 | "Use security key" : "Use security key",
20 | "An error occurred. Please try again." : "An error occurred. Please try again.",
21 | "Your browser does not support WebAuthn." : "Your browser does not support WebAuthn.",
22 | "You are accessing this site via an insecure connection. Browsers might therefore refuse the WebAuthn authentication." : "You are accessing this site via an insecure connection. Browsers might therefore refuse the WebAuthn authentication.",
23 | "Unnamed key" : "Unnamed key",
24 | "Registered" : "Registered",
25 | "Active" : "فعال کردن",
26 | "Remove" : "حذف",
27 | "Set up a security key as a second factor." : "Set up a security key as a second factor.",
28 | "Your security key was added successfully. You are now being redirected to the login page." : "Your security key was added successfully. You are now being redirected to the login page.",
29 | "No security keys configured. You are not using WebAuthn as second factor at the moment." : "No security keys configured. You are not using WebAuthn as second factor at the moment.",
30 | "The following security keys are configured for WebAuthn two-factor authentication:" : "The following security keys are configured for WebAuthn two-factor authentication:",
31 | "All security keys are deactivated." : "All security keys are deactivated."
32 | },"pluralForm" :"nplurals=2; plural=(n > 1);"
33 | }
--------------------------------------------------------------------------------
/.github/workflows/psalm-matrix.yml:
--------------------------------------------------------------------------------
1 | # This workflow is provided via the organization template repository
2 | #
3 | # https://github.com/nextcloud/.github
4 | # https://docs.github.com/en/actions/learn-github-actions/sharing-workflows-with-your-organization
5 | #
6 | # SPDX-FileCopyrightText: 2022-2024 Nextcloud GmbH and Nextcloud contributors
7 | # SPDX-License-Identifier: MIT
8 |
9 | name: Static analysis
10 |
11 | on: pull_request
12 |
13 | concurrency:
14 | group: psalm-${{ github.head_ref || github.run_id }}
15 | cancel-in-progress: true
16 |
17 | jobs:
18 | matrix:
19 | runs-on: ubuntu-latest-low
20 | outputs:
21 | ocp-matrix: ${{ steps.versions.outputs.ocp-matrix }}
22 | php-min: ${{ steps.versions.outputs.php-min }}
23 | steps:
24 | - name: Checkout app
25 | uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
26 | - name: Get version matrix
27 | id: versions
28 | uses: icewind1991/nextcloud-version-matrix@58becf3b4bb6dc6cef677b15e2fd8e7d48c0908f # v1.3.1
29 |
30 | static-analysis:
31 | runs-on: ubuntu-latest
32 | needs: matrix
33 | strategy:
34 | # do not stop on another job's failure
35 | fail-fast: false
36 | matrix: ${{ fromJson(needs.matrix.outputs.ocp-matrix) }}
37 |
38 | name: static-psalm-analysis ${{ matrix.ocp-version }}
39 | steps:
40 | - name: Checkout
41 | uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
42 |
43 | - name: Set up php${{ needs.matrix.outputs.php-min }}
44 | uses: shivammathur/setup-php@cf4cade2721270509d5b1c766ab3549210a39a2a # 2.33.0
45 | with:
46 | php-version: ${{ needs.matrix.outputs.php-min }}
47 | extensions: bz2, ctype, curl, dom, fileinfo, gd, iconv, intl, json, libxml, mbstring, openssl, pcntl, posix, session, simplexml, xmlreader, xmlwriter, zip, zlib, sqlite, pdo_sqlite
48 | coverage: none
49 | ini-file: development
50 | env:
51 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
52 |
53 | - name: Install dependencies
54 | run: composer i
55 |
56 | - name: Install dependencies
57 | run: composer require --dev 'nextcloud/ocp:${{ matrix.ocp-version }}' --ignore-platform-reqs --with-all-dependencies
58 |
59 | - name: Run coding standards check
60 | run: composer run psalm
61 |
62 | summary:
63 | runs-on: ubuntu-latest-low
64 | needs: static-analysis
65 |
66 | if: always()
67 |
68 | name: static-psalm-analysis-summary
69 |
70 | steps:
71 | - name: Summary status
72 | run: if ${{ needs.static-analysis.result != 'success' }}; then exit 1; fi
73 |
--------------------------------------------------------------------------------
/l10n/en_GB.js:
--------------------------------------------------------------------------------
1 | OC.L10N.register(
2 | "twofactor_webauthn",
3 | {
4 | "You added an WebAuthn hardware token" : "You added an WebAuthn hardware token",
5 | "You removed an WebAuthn hardware token" : "You removed an WebAuthn hardware token",
6 | "WebAuthn disabled by the administration" : "WebAuthn disabled by the administration",
7 | "Security key" : "Security key",
8 | "Use WebAuthn for second factor authentication" : "Use WebAuthn for second factor authentication",
9 | "Two-Factor WebAuthn" : "Two-Factor WebAuthn",
10 | "WebAuthn two-factor provider" : "WebAuthn two-factor provider",
11 | "A two-factor provider for WebAuthn devices" : "A two-factor provider for WebAuthn devices",
12 | "Server error while trying to complete security key registration" : "Server error while trying to complete security key registration",
13 | "Add security key" : "Add security key",
14 | "Please use your security key to authorize." : "Please use your security key to authorise.",
15 | "Name your security key" : "Name your security key",
16 | "Add" : "Add",
17 | "Adding your security key …" : "Adding your security key …",
18 | "Authentication cancelled" : "Authentication cancelled",
19 | "An error occurred: {msg}" : "An error occurred: {msg}",
20 | "Retry" : "Retry",
21 | "Use security key" : "Use security key",
22 | "An error occurred. Please try again." : "An error occurred. Please try again.",
23 | "Your browser does not support WebAuthn." : "Your browser does not support WebAuthn.",
24 | "You are accessing this site via an insecure connection. Browsers might therefore refuse the WebAuthn authentication." : "You are accessing this site via an insecure connection. Browsers might therefore refuse the WebAuthn authentication.",
25 | "Unnamed key" : "Unnamed key",
26 | "Registered" : "Registered",
27 | "Active" : "Active",
28 | "Remove" : "Remove",
29 | "Set up a security key as a second factor." : "Set up a security key as a second factor.",
30 | "Your security key was added successfully. You are now being redirected to the login page." : "Your security key was added successfully. You are now being redirected to the login page.",
31 | "No security keys configured. You are not using WebAuthn as second factor at the moment." : "No security keys configured. You are not using WebAuthn as second factor at the moment.",
32 | "The following security keys are configured for WebAuthn two-factor authentication:" : "The following security keys are configured for WebAuthn two-factor authentication:",
33 | "All security keys are deactivated." : "All security keys are deactivated."
34 | },
35 | "nplurals=2; plural=(n != 1);");
36 |
--------------------------------------------------------------------------------
/l10n/fa.js:
--------------------------------------------------------------------------------
1 | OC.L10N.register(
2 | "twofactor_webauthn",
3 | {
4 | "You added an WebAuthn hardware token" : "You added an WebAuthn hardware token",
5 | "You removed an WebAuthn hardware token" : "You removed an WebAuthn hardware token",
6 | "WebAuthn disabled by the administration" : "WebAuthn disabled by the administration",
7 | "Security key" : "Security key",
8 | "Use WebAuthn for second factor authentication" : "Use WebAuthn for second factor authentication",
9 | "Two-Factor WebAuthn" : "Two-Factor WebAuthn",
10 | "WebAuthn two-factor provider" : "WebAuthn two-factor provider",
11 | "A two-factor provider for WebAuthn devices" : "A two-factor provider for WebAuthn devices",
12 | "Server error while trying to complete security key registration" : "Server error while trying to complete security key registration",
13 | "Add security key" : "Add security key",
14 | "Please use your security key to authorize." : "Please use your security key to authorize.",
15 | "Name your security key" : "Name your security key",
16 | "Add" : "افزودن",
17 | "Adding your security key …" : "Adding your security key …",
18 | "Authentication cancelled" : "Authentication cancelled",
19 | "An error occurred: {msg}" : "An error occurred: {msg}",
20 | "Retry" : "تلاش دوباره",
21 | "Use security key" : "Use security key",
22 | "An error occurred. Please try again." : "An error occurred. Please try again.",
23 | "Your browser does not support WebAuthn." : "Your browser does not support WebAuthn.",
24 | "You are accessing this site via an insecure connection. Browsers might therefore refuse the WebAuthn authentication." : "You are accessing this site via an insecure connection. Browsers might therefore refuse the WebAuthn authentication.",
25 | "Unnamed key" : "Unnamed key",
26 | "Registered" : "Registered",
27 | "Active" : "فعال کردن",
28 | "Remove" : "حذف",
29 | "Set up a security key as a second factor." : "Set up a security key as a second factor.",
30 | "Your security key was added successfully. You are now being redirected to the login page." : "Your security key was added successfully. You are now being redirected to the login page.",
31 | "No security keys configured. You are not using WebAuthn as second factor at the moment." : "No security keys configured. You are not using WebAuthn as second factor at the moment.",
32 | "The following security keys are configured for WebAuthn two-factor authentication:" : "The following security keys are configured for WebAuthn two-factor authentication:",
33 | "All security keys are deactivated." : "All security keys are deactivated."
34 | },
35 | "nplurals=2; plural=(n > 1);");
36 |
--------------------------------------------------------------------------------
/l10n/nb.json:
--------------------------------------------------------------------------------
1 | { "translations": {
2 | "You added an WebAuthn hardware token" : "Du har lagt til et WebAuthn-maskinvaretoken",
3 | "You removed an WebAuthn hardware token" : "Du fjernet et WebAuthn-maskinvaretoken",
4 | "WebAuthn disabled by the administration" : "WebAuthn deaktivert av administrasjonen",
5 | "Security key" : "Sikkerhetsnøkkel",
6 | "Use WebAuthn for second factor authentication" : "Bruk WebAuthn for tofaktorautentisering",
7 | "Two-Factor WebAuthn" : "Tofaktor WebAuthn",
8 | "WebAuthn two-factor provider" : "WebAuthn tofaktorleverandør",
9 | "A two-factor provider for WebAuthn devices" : "En tofaktorleverandør for WebAuthn-enheter",
10 | "Server error while trying to complete security key registration" : "Serverfeil under forsøk på å fullføre registrering av sikkerhetsnøkkel",
11 | "Add security key" : "Legg til sikkerhetsnøkkel",
12 | "Please use your security key to authorize." : "Vennligst bruk sikkerhetsnøkkelen din for å autentisere.",
13 | "Name your security key" : "Navngi sikkerhetsnøkkelen din",
14 | "Add" : "Legg til",
15 | "Adding your security key …" : "Legger til sikkerhetsnøkkelen din...",
16 | "Authentication cancelled" : "Autentisering avbrutt",
17 | "An error occurred: {msg}" : "En feil oppsto: {msg}",
18 | "Retry" : "Prøv igjen",
19 | "Use security key" : "Bruk sikkerhetsnøkkel",
20 | "An error occurred. Please try again." : "Det oppsto en feil. Prøv igjen.",
21 | "Your browser does not support WebAuthn." : "Nettleseren din støtter ikke WebAuthn.",
22 | "You are accessing this site via an insecure connection. Browsers might therefore refuse the WebAuthn authentication." : "Du får tilgang til dette nettstedet via en usikker tilkobling. Nettlesere kan derfor nekte WebAuthn-autentisering.",
23 | "Unnamed key" : "Ikke navngitt nøkkel",
24 | "Registered" : "Registrert",
25 | "Active" : "Aktiv",
26 | "Remove" : "Fjern",
27 | "Set up a security key as a second factor." : "Sett opp en sikkerhetsnøkkel som en tofaktor.",
28 | "Your security key was added successfully. You are now being redirected to the login page." : "Sikkerhetsnøkkelen din ble lagt til. Du blir nå omdirigert til påloggingssiden.",
29 | "No security keys configured. You are not using WebAuthn as second factor at the moment." : "Ingen sikkerhetsnøkler konfigurert. Du bruker for øyeblikket ikke WebAuthn som tofaktor.",
30 | "The following security keys are configured for WebAuthn two-factor authentication:" : "Følgende sikkerhetsnøkler er konfigurert for WebAuthns tofaktorautentisering:",
31 | "All security keys are deactivated." : "Alle sikkerhetsnøkler er deaktivert."
32 | },"pluralForm" :"nplurals=2; plural=(n != 1);"
33 | }
--------------------------------------------------------------------------------
/tests/Unit/Activity/ProviderTest.php:
--------------------------------------------------------------------------------
1 | l10n = $this->createMock(IFactory::class);
32 | $this->urlGenerator = $this->createMock(IURLGenerator::class);
33 |
34 | $this->provider = new Provider($this->l10n, $this->urlGenerator);
35 | }
36 |
37 | public function testParseUnrelated(): void {
38 | $lang = 'ru';
39 | $event = $this->createMock(IEvent::class);
40 | $event->expects(self::once())
41 | ->method('getApp')
42 | ->willReturn('comments');
43 | $this->expectException(InvalidArgumentException::class);
44 |
45 | $this->provider->parse($lang, $event);
46 | }
47 |
48 | public function subjectData(): array {
49 | return [
50 | ['webauthn_device_added'],
51 | ['webauthn_device_removed'],
52 | ['webauthn_disabled_by_admin'],
53 | ];
54 | }
55 |
56 | /**
57 | * @dataProvider subjectData
58 | */
59 | public function testParse($subject): void {
60 | $lang = 'ru';
61 | $event = $this->createMock(IEvent::class);
62 | $l = $this->createMock(IL10N::class);
63 |
64 | $event->expects(self::once())
65 | ->method('getApp')
66 | ->willReturn('twofactor_webauthn');
67 | $this->l10n->expects(self::once())
68 | ->method('get')
69 | ->with('twofactor_webauthn', $lang)
70 | ->willReturn($l);
71 | $this->urlGenerator->expects(self::once())
72 | ->method('imagePath')
73 | ->with('core', 'actions/password.svg')
74 | ->willReturn('path/to/image');
75 | $this->urlGenerator->expects(self::once())
76 | ->method('getAbsoluteURL')
77 | ->with('path/to/image')
78 | ->willReturn('absolute/path/to/image');
79 | $event->expects(self::once())
80 | ->method('setIcon')
81 | ->with('absolute/path/to/image');
82 | $event->expects(self::once())
83 | ->method('getSubject')
84 | ->willReturn($subject);
85 | $event->expects(self::once())
86 | ->method('setSubject');
87 |
88 | $this->provider->parse($lang, $event);
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/l10n/et_EE.json:
--------------------------------------------------------------------------------
1 | { "translations": {
2 | "You added an WebAuthn hardware token" : "Sa lisasid WebAuthni raudvaralise pääsmiku",
3 | "You removed an WebAuthn hardware token" : "Sa eemaldasid WebAuthni raudvaralise pääsmiku",
4 | "WebAuthn disabled by the administration" : "WebAuthn on peakasutaja poolt välja lülitatud",
5 | "Security key" : "Turvavõti",
6 | "Use WebAuthn for second factor authentication" : "Kasuta WebAuthni kaheastmeline autentimise jaoks",
7 | "Two-Factor WebAuthn" : " Kaheastmeline autentimine WebAuthni abil",
8 | "WebAuthn two-factor provider" : "WebAuthni kaheastmelise autentimise teenusepakkuja",
9 | "A two-factor provider for WebAuthn devices" : "Kaheastmelise autentimise teenusepakkuja WebAuthni sedamete jaoks",
10 | "Server error while trying to complete security key registration" : "Serveriviga turvavõtme registreerimise lõpetamisel",
11 | "Add security key" : "Lisa turvavõti",
12 | "Please use your security key to authorize." : "Palun kasuta tuvastamiseks turvavõtit.",
13 | "Name your security key" : "Turvavõtme nimi",
14 | "Add" : "Lisa",
15 | "Adding your security key …" : "Turvavõti on lisamisel…",
16 | "Authentication cancelled" : "Autentimine on katkestatud",
17 | "An error occurred: {msg}" : "Tekkis viga: {msg}",
18 | "Retry" : "Proovi uuesti",
19 | "Use security key" : "Kasuta turvavõtit",
20 | "An error occurred. Please try again." : "Tekkis viga. Palun proovi uuesti",
21 | "Your browser does not support WebAuthn." : "Sinu veebibrauseril puudub WebAuthni tugi.",
22 | "You are accessing this site via an insecure connection. Browsers might therefore refuse the WebAuthn authentication." : "Sa kasutad seda veebisaiti ebaturvalise ühenduse abil. Veebibrauserid võivad keelduda WebAuthni abil tuvastamisest.",
23 | "Unnamed key" : "Ilma nimeta turvavõti",
24 | "Registered" : "Registreeritud",
25 | "Active" : "Aktiivne",
26 | "Remove" : "Eemalda",
27 | "Set up a security key as a second factor." : "Seadista turvavõti autentimise teise sammuna.",
28 | "Your security key was added successfully. You are now being redirected to the login page." : "Sinu turvavõtme lisamine õnnestus. Suunan sind edasi sisselogimise lehele.",
29 | "No security keys configured. You are not using WebAuthn as second factor at the moment." : "Ühtegi turvavõtit pole registreeritud. Sa hetkel ei kasuta WebAuthni teise sammuna.",
30 | "The following security keys are configured for WebAuthn two-factor authentication:" : "Järgnevad turvavõtmed on sedaistatud WebAuthni kaheastmeline autentimise jaoks:",
31 | "All security keys are deactivated." : "Kõik turvavõtmed on kautuselt eemaldatud"
32 | },"pluralForm" :"nplurals=2; plural=(n != 1);"
33 | }
--------------------------------------------------------------------------------
/l10n/sv.json:
--------------------------------------------------------------------------------
1 | { "translations": {
2 | "You added an WebAuthn hardware token" : "Du har lagt till en WebAuthn enhets-token",
3 | "You removed an WebAuthn hardware token" : "Du tog bort en WebAuthn enhets-token",
4 | "WebAuthn disabled by the administration" : "WebAuthn inaktiverad av administratören",
5 | "Security key" : "Säkerhetsnyckel",
6 | "Use WebAuthn for second factor authentication" : "Använd WebAuthn för andra faktor autentisering",
7 | "Two-Factor WebAuthn" : "Tvåfaktors WebAuthn",
8 | "WebAuthn two-factor provider" : "WebAuthn tvåfaktor-leverantör",
9 | "A two-factor provider for WebAuthn devices" : "En tvåfaktor-leverantör för WebAuthn-enheter",
10 | "Server error while trying to complete security key registration" : "Serverfel vid försök att slutföra registreringen av säkerhetsnyckel",
11 | "Add security key" : "Lägg till säkerhetsnyckel",
12 | "Please use your security key to authorize." : "Använd din säkerhetsnyckel för att auktorisera.",
13 | "Name your security key" : "Namnge din säkerhetsnyckel",
14 | "Add" : "Lägg till",
15 | "Adding your security key …" : "Lägger till din säkerhetsnyckel ...",
16 | "Authentication cancelled" : "Autentiseringen avbröts",
17 | "An error occurred: {msg}" : "Ett fel uppstod: {msg}",
18 | "Retry" : "Försök igen",
19 | "Use security key" : "Använd säkerhetsnyckel",
20 | "An error occurred. Please try again." : "Ett fel har inträffat. Vänligen försök igen.",
21 | "Your browser does not support WebAuthn." : "Din webbläsare stödjer inte WebAuthn.",
22 | "You are accessing this site via an insecure connection. Browsers might therefore refuse the WebAuthn authentication." : "Din åtkomst till den här webbplatsen sker via en osäker anslutning. Webbläsaren kan därför vägra WebAuthn-autentisering.",
23 | "Unnamed key" : "Namnlös nyckel",
24 | "Registered" : "Registrerad",
25 | "Active" : "Aktiv",
26 | "Remove" : "Ta bort",
27 | "Set up a security key as a second factor." : "Ställ in en säkerhetsnyckel som andra faktor.",
28 | "Your security key was added successfully. You are now being redirected to the login page." : "Din säkerhetsnyckel har lagts till. Du omdirigeras nu till inloggningssidan.",
29 | "No security keys configured. You are not using WebAuthn as second factor at the moment." : "Inga säkerhetsnycklar är konfigurerade. Du använder inte WebAuthn som tvåfaktorautentisering just nu.",
30 | "The following security keys are configured for WebAuthn two-factor authentication:" : "Följande enheter är konfigurerade för WebAuthn tvåfaktorautentisering:",
31 | "All security keys are deactivated." : "Alla säkerhetsnycklar är avaktiverade."
32 | },"pluralForm" :"nplurals=2; plural=(n != 1);"
33 | }
--------------------------------------------------------------------------------
/l10n/nb.js:
--------------------------------------------------------------------------------
1 | OC.L10N.register(
2 | "twofactor_webauthn",
3 | {
4 | "You added an WebAuthn hardware token" : "Du har lagt til et WebAuthn-maskinvaretoken",
5 | "You removed an WebAuthn hardware token" : "Du fjernet et WebAuthn-maskinvaretoken",
6 | "WebAuthn disabled by the administration" : "WebAuthn deaktivert av administrasjonen",
7 | "Security key" : "Sikkerhetsnøkkel",
8 | "Use WebAuthn for second factor authentication" : "Bruk WebAuthn for tofaktorautentisering",
9 | "Two-Factor WebAuthn" : "Tofaktor WebAuthn",
10 | "WebAuthn two-factor provider" : "WebAuthn tofaktorleverandør",
11 | "A two-factor provider for WebAuthn devices" : "En tofaktorleverandør for WebAuthn-enheter",
12 | "Server error while trying to complete security key registration" : "Serverfeil under forsøk på å fullføre registrering av sikkerhetsnøkkel",
13 | "Add security key" : "Legg til sikkerhetsnøkkel",
14 | "Please use your security key to authorize." : "Vennligst bruk sikkerhetsnøkkelen din for å autentisere.",
15 | "Name your security key" : "Navngi sikkerhetsnøkkelen din",
16 | "Add" : "Legg til",
17 | "Adding your security key …" : "Legger til sikkerhetsnøkkelen din...",
18 | "Authentication cancelled" : "Autentisering avbrutt",
19 | "An error occurred: {msg}" : "En feil oppsto: {msg}",
20 | "Retry" : "Prøv igjen",
21 | "Use security key" : "Bruk sikkerhetsnøkkel",
22 | "An error occurred. Please try again." : "Det oppsto en feil. Prøv igjen.",
23 | "Your browser does not support WebAuthn." : "Nettleseren din støtter ikke WebAuthn.",
24 | "You are accessing this site via an insecure connection. Browsers might therefore refuse the WebAuthn authentication." : "Du får tilgang til dette nettstedet via en usikker tilkobling. Nettlesere kan derfor nekte WebAuthn-autentisering.",
25 | "Unnamed key" : "Ikke navngitt nøkkel",
26 | "Registered" : "Registrert",
27 | "Active" : "Aktiv",
28 | "Remove" : "Fjern",
29 | "Set up a security key as a second factor." : "Sett opp en sikkerhetsnøkkel som en tofaktor.",
30 | "Your security key was added successfully. You are now being redirected to the login page." : "Sikkerhetsnøkkelen din ble lagt til. Du blir nå omdirigert til påloggingssiden.",
31 | "No security keys configured. You are not using WebAuthn as second factor at the moment." : "Ingen sikkerhetsnøkler konfigurert. Du bruker for øyeblikket ikke WebAuthn som tofaktor.",
32 | "The following security keys are configured for WebAuthn two-factor authentication:" : "Følgende sikkerhetsnøkler er konfigurert for WebAuthns tofaktorautentisering:",
33 | "All security keys are deactivated." : "Alle sikkerhetsnøkler er deaktivert."
34 | },
35 | "nplurals=2; plural=(n != 1);");
36 |
--------------------------------------------------------------------------------
/l10n/sv.js:
--------------------------------------------------------------------------------
1 | OC.L10N.register(
2 | "twofactor_webauthn",
3 | {
4 | "You added an WebAuthn hardware token" : "Du har lagt till en WebAuthn enhets-token",
5 | "You removed an WebAuthn hardware token" : "Du tog bort en WebAuthn enhets-token",
6 | "WebAuthn disabled by the administration" : "WebAuthn inaktiverad av administratören",
7 | "Security key" : "Säkerhetsnyckel",
8 | "Use WebAuthn for second factor authentication" : "Använd WebAuthn för andra faktor autentisering",
9 | "Two-Factor WebAuthn" : "Tvåfaktors WebAuthn",
10 | "WebAuthn two-factor provider" : "WebAuthn tvåfaktor-leverantör",
11 | "A two-factor provider for WebAuthn devices" : "En tvåfaktor-leverantör för WebAuthn-enheter",
12 | "Server error while trying to complete security key registration" : "Serverfel vid försök att slutföra registreringen av säkerhetsnyckel",
13 | "Add security key" : "Lägg till säkerhetsnyckel",
14 | "Please use your security key to authorize." : "Använd din säkerhetsnyckel för att auktorisera.",
15 | "Name your security key" : "Namnge din säkerhetsnyckel",
16 | "Add" : "Lägg till",
17 | "Adding your security key …" : "Lägger till din säkerhetsnyckel ...",
18 | "Authentication cancelled" : "Autentiseringen avbröts",
19 | "An error occurred: {msg}" : "Ett fel uppstod: {msg}",
20 | "Retry" : "Försök igen",
21 | "Use security key" : "Använd säkerhetsnyckel",
22 | "An error occurred. Please try again." : "Ett fel har inträffat. Vänligen försök igen.",
23 | "Your browser does not support WebAuthn." : "Din webbläsare stödjer inte WebAuthn.",
24 | "You are accessing this site via an insecure connection. Browsers might therefore refuse the WebAuthn authentication." : "Din åtkomst till den här webbplatsen sker via en osäker anslutning. Webbläsaren kan därför vägra WebAuthn-autentisering.",
25 | "Unnamed key" : "Namnlös nyckel",
26 | "Registered" : "Registrerad",
27 | "Active" : "Aktiv",
28 | "Remove" : "Ta bort",
29 | "Set up a security key as a second factor." : "Ställ in en säkerhetsnyckel som andra faktor.",
30 | "Your security key was added successfully. You are now being redirected to the login page." : "Din säkerhetsnyckel har lagts till. Du omdirigeras nu till inloggningssidan.",
31 | "No security keys configured. You are not using WebAuthn as second factor at the moment." : "Inga säkerhetsnycklar är konfigurerade. Du använder inte WebAuthn som tvåfaktorautentisering just nu.",
32 | "The following security keys are configured for WebAuthn two-factor authentication:" : "Följande enheter är konfigurerade för WebAuthn tvåfaktorautentisering:",
33 | "All security keys are deactivated." : "Alla säkerhetsnycklar är avaktiverade."
34 | },
35 | "nplurals=2; plural=(n != 1);");
36 |
--------------------------------------------------------------------------------
/l10n/et_EE.js:
--------------------------------------------------------------------------------
1 | OC.L10N.register(
2 | "twofactor_webauthn",
3 | {
4 | "You added an WebAuthn hardware token" : "Sa lisasid WebAuthni raudvaralise pääsmiku",
5 | "You removed an WebAuthn hardware token" : "Sa eemaldasid WebAuthni raudvaralise pääsmiku",
6 | "WebAuthn disabled by the administration" : "WebAuthn on peakasutaja poolt välja lülitatud",
7 | "Security key" : "Turvavõti",
8 | "Use WebAuthn for second factor authentication" : "Kasuta WebAuthni kaheastmeline autentimise jaoks",
9 | "Two-Factor WebAuthn" : " Kaheastmeline autentimine WebAuthni abil",
10 | "WebAuthn two-factor provider" : "WebAuthni kaheastmelise autentimise teenusepakkuja",
11 | "A two-factor provider for WebAuthn devices" : "Kaheastmelise autentimise teenusepakkuja WebAuthni sedamete jaoks",
12 | "Server error while trying to complete security key registration" : "Serveriviga turvavõtme registreerimise lõpetamisel",
13 | "Add security key" : "Lisa turvavõti",
14 | "Please use your security key to authorize." : "Palun kasuta tuvastamiseks turvavõtit.",
15 | "Name your security key" : "Turvavõtme nimi",
16 | "Add" : "Lisa",
17 | "Adding your security key …" : "Turvavõti on lisamisel…",
18 | "Authentication cancelled" : "Autentimine on katkestatud",
19 | "An error occurred: {msg}" : "Tekkis viga: {msg}",
20 | "Retry" : "Proovi uuesti",
21 | "Use security key" : "Kasuta turvavõtit",
22 | "An error occurred. Please try again." : "Tekkis viga. Palun proovi uuesti",
23 | "Your browser does not support WebAuthn." : "Sinu veebibrauseril puudub WebAuthni tugi.",
24 | "You are accessing this site via an insecure connection. Browsers might therefore refuse the WebAuthn authentication." : "Sa kasutad seda veebisaiti ebaturvalise ühenduse abil. Veebibrauserid võivad keelduda WebAuthni abil tuvastamisest.",
25 | "Unnamed key" : "Ilma nimeta turvavõti",
26 | "Registered" : "Registreeritud",
27 | "Active" : "Aktiivne",
28 | "Remove" : "Eemalda",
29 | "Set up a security key as a second factor." : "Seadista turvavõti autentimise teise sammuna.",
30 | "Your security key was added successfully. You are now being redirected to the login page." : "Sinu turvavõtme lisamine õnnestus. Suunan sind edasi sisselogimise lehele.",
31 | "No security keys configured. You are not using WebAuthn as second factor at the moment." : "Ühtegi turvavõtit pole registreeritud. Sa hetkel ei kasuta WebAuthni teise sammuna.",
32 | "The following security keys are configured for WebAuthn two-factor authentication:" : "Järgnevad turvavõtmed on sedaistatud WebAuthni kaheastmeline autentimise jaoks:",
33 | "All security keys are deactivated." : "Kõik turvavõtmed on kautuselt eemaldatud"
34 | },
35 | "nplurals=2; plural=(n != 1);");
36 |
--------------------------------------------------------------------------------
/l10n/hu.json:
--------------------------------------------------------------------------------
1 | { "translations": {
2 | "You added an WebAuthn hardware token" : "Hozzáadott egy WebAuthn hardvertokent",
3 | "You removed an WebAuthn hardware token" : "Eltávolított egy WebAuthn hardvertokent",
4 | "WebAuthn disabled by the administration" : "A WebAuthnt letiltotta a rendszergazda",
5 | "Security key" : "Biztonsági kulcs",
6 | "Use WebAuthn for second factor authentication" : "WebAuthn használata a hitelesítés második lépéseként",
7 | "Two-Factor WebAuthn" : "Kétlépcsős WebAuthn",
8 | "WebAuthn two-factor provider" : "WebAuthn kétlépcsős szolgáltató",
9 | "A two-factor provider for WebAuthn devices" : "Kétlépcsős szolgáltató a WebAuthn-eszközökhöz",
10 | "Server error while trying to complete security key registration" : "Kiszolgálóhiba a biztonsági kulcs regisztrációjának befejezése során",
11 | "Add security key" : "Biztonsági kulcs hozzáadása",
12 | "Please use your security key to authorize." : "Használja a biztonsági kulcsát a jogosultság-ellenőrzéshez.",
13 | "Name your security key" : "Nevezze el a biztonsági kulcsot",
14 | "Add" : "Hozzáadás",
15 | "Adding your security key …" : "Biztonsági kulcs hozzáadása…",
16 | "Authentication cancelled" : "Hitelesítés megszakítva",
17 | "An error occurred: {msg}" : "Hiba történt: {msg}",
18 | "Retry" : "Újra",
19 | "Use security key" : "Biztonsági kulcs használata",
20 | "An error occurred. Please try again." : "Hiba történt. Próbálja újra.",
21 | "Your browser does not support WebAuthn." : "A böngészője nem támogatja a WebAuthn szabványt.",
22 | "You are accessing this site via an insecure connection. Browsers might therefore refuse the WebAuthn authentication." : "Nem biztonságos kapcsolaton keresztül éri el ezt az oldalt. A böngészők ezért megtagadhatják a WebAuthn-hitelesítést.",
23 | "Unnamed key" : "Névtelen kulcs",
24 | "Registered" : "Regisztrált",
25 | "Active" : "Aktív",
26 | "Remove" : "Eltávolítás",
27 | "Set up a security key as a second factor." : "Biztonsági kulcs beállítása második lépcsőként.",
28 | "Your security key was added successfully. You are now being redirected to the login page." : "A biztonsági kulcs sikeresen hozzáadva. Most át lesz irányítva a bejelentkezési oldalra.",
29 | "No security keys configured. You are not using WebAuthn as second factor at the moment." : "Nincsenek biztonsági kulcsok beállítva. Jelenleg nem használ WebAuthnt második lépésként.",
30 | "The following security keys are configured for WebAuthn two-factor authentication:" : "A következő biztonsági kulcsok lettek beállítva a WebAuthn kétlépcsős hitelesítéshez:",
31 | "All security keys are deactivated." : "Az összes biztonsági kulcsot deaktiválták."
32 | },"pluralForm" :"nplurals=2; plural=(n != 1);"
33 | }
--------------------------------------------------------------------------------