diff options
author | Kevin Decherf <kevin@kdecherf.com> | 2019-01-30 01:02:27 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-01-30 01:02:27 +0100 |
commit | 2e5b3fa361098498a9e42a65396a27e1eb487fba (patch) | |
tree | f20677c3d68c1ea756f0835ff179a0d7d3431a67 | |
parent | c6024246b744e411175318065f7c396bbb5a213e (diff) | |
parent | 4654a83b6438b88e3b7062a21d18999d9df2fb8e (diff) | |
download | wallabag-2e5b3fa361098498a9e42a65396a27e1eb487fba.tar.gz wallabag-2e5b3fa361098498a9e42a65396a27e1eb487fba.tar.zst wallabag-2e5b3fa361098498a9e42a65396a27e1eb487fba.zip |
Merge pull request #3798 from wallabag/update-two-factor-bundle
Enable OTP 2FA
41 files changed, 1094 insertions, 233 deletions
diff --git a/.editorconfig b/.editorconfig index 6553d30f..14044044 100644 --- a/.editorconfig +++ b/.editorconfig | |||
@@ -13,5 +13,5 @@ insert_final_newline = true | |||
13 | indent_style = space | 13 | indent_style = space |
14 | indent_size = 2 | 14 | indent_size = 2 |
15 | 15 | ||
16 | [Makefile] | 16 | [*akefile] |
17 | indent_style = tab | 17 | indent_style = tab |
diff --git a/.travis.yml b/.travis.yml index 0ca1e192..393d0033 100644 --- a/.travis.yml +++ b/.travis.yml | |||
@@ -51,13 +51,13 @@ install: | |||
51 | 51 | ||
52 | before_script: | 52 | before_script: |
53 | - PHP=$TRAVIS_PHP_VERSION | 53 | - PHP=$TRAVIS_PHP_VERSION |
54 | - if [[ ! $PHP = hhvm* ]]; then echo "memory_limit=-1" >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini; fi; | 54 | - echo "memory_limit=-1" >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini |
55 | # xdebug isn't enable for PHP 7.1 | 55 | - phpenv config-rm xdebug.ini || echo "xdebug not available" |
56 | - if [[ ! $PHP = hhvm* ]]; then phpenv config-rm xdebug.ini || echo "xdebug not available"; fi | ||
57 | - composer self-update --no-progress | 56 | - composer self-update --no-progress |
58 | 57 | ||
59 | script: | 58 | script: |
60 | - travis_wait bash composer install -o --no-interaction --no-progress --prefer-dist | 59 | - travis_wait bash composer install -o --no-interaction --no-progress --prefer-dist |
60 | |||
61 | - echo "travis_fold:start:prepare" | 61 | - echo "travis_fold:start:prepare" |
62 | - make prepare DB=$DB | 62 | - make prepare DB=$DB |
63 | - echo "travis_fold:end:prepare" | 63 | - echo "travis_fold:end:prepare" |
diff --git a/app/DoctrineMigrations/Version20181202073750.php b/app/DoctrineMigrations/Version20181202073750.php new file mode 100644 index 00000000..5978291e --- /dev/null +++ b/app/DoctrineMigrations/Version20181202073750.php | |||
@@ -0,0 +1,76 @@ | |||
1 | <?php | ||
2 | |||
3 | namespace Application\Migrations; | ||
4 | |||
5 | use Doctrine\DBAL\Schema\Schema; | ||
6 | use Wallabag\CoreBundle\Doctrine\WallabagMigration; | ||
7 | |||
8 | /** | ||
9 | * Add 2fa OTP stuff. | ||
10 | */ | ||
11 | final class Version20181202073750 extends WallabagMigration | ||
12 | { | ||
13 | public function up(Schema $schema): void | ||
14 | { | ||
15 | switch ($this->connection->getDatabasePlatform()->getName()) { | ||
16 | case 'sqlite': | ||
17 | $this->addSql('DROP INDEX UNIQ_1D63E7E5C05FB297'); | ||
18 | $this->addSql('DROP INDEX UNIQ_1D63E7E5A0D96FBF'); | ||
19 | $this->addSql('DROP INDEX UNIQ_1D63E7E592FC23A8'); | ||
20 | $this->addSql('CREATE TEMPORARY TABLE __temp__' . $this->getTable('user', true) . ' AS SELECT id, username, username_canonical, email, email_canonical, enabled, salt, password, last_login, confirmation_token, password_requested_at, roles, name, created_at, updated_at, authCode, twoFactorAuthentication FROM ' . $this->getTable('user', true) . ''); | ||
21 | $this->addSql('DROP TABLE ' . $this->getTable('user', true) . ''); | ||
22 | $this->addSql('CREATE TABLE ' . $this->getTable('user', true) . ' (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, username VARCHAR(180) NOT NULL COLLATE BINARY, username_canonical VARCHAR(180) NOT NULL COLLATE BINARY, email VARCHAR(180) NOT NULL COLLATE BINARY, email_canonical VARCHAR(180) NOT NULL COLLATE BINARY, enabled BOOLEAN NOT NULL, password VARCHAR(255) NOT NULL COLLATE BINARY, last_login DATETIME DEFAULT NULL, password_requested_at DATETIME DEFAULT NULL, name CLOB DEFAULT NULL COLLATE BINARY, created_at DATETIME NOT NULL, updated_at DATETIME NOT NULL, authCode INTEGER DEFAULT NULL, emailTwoFactor BOOLEAN NOT NULL, salt VARCHAR(255) DEFAULT NULL, confirmation_token VARCHAR(180) DEFAULT NULL, roles CLOB NOT NULL --(DC2Type:array) | ||
23 | , googleAuthenticatorSecret VARCHAR(255) DEFAULT NULL, backupCodes CLOB DEFAULT NULL --(DC2Type:json_array) | ||
24 | )'); | ||
25 | $this->addSql('INSERT INTO ' . $this->getTable('user', true) . ' (id, username, username_canonical, email, email_canonical, enabled, salt, password, last_login, confirmation_token, password_requested_at, roles, name, created_at, updated_at, authCode, emailTwoFactor) SELECT id, username, username_canonical, email, email_canonical, enabled, salt, password, last_login, confirmation_token, password_requested_at, roles, name, created_at, updated_at, authCode, twoFactorAuthentication FROM __temp__' . $this->getTable('user', true) . ''); | ||
26 | $this->addSql('DROP TABLE __temp__' . $this->getTable('user', true) . ''); | ||
27 | $this->addSql('CREATE UNIQUE INDEX UNIQ_1D63E7E5C05FB297 ON ' . $this->getTable('user', true) . ' (confirmation_token)'); | ||
28 | $this->addSql('CREATE UNIQUE INDEX UNIQ_1D63E7E5A0D96FBF ON ' . $this->getTable('user', true) . ' (email_canonical)'); | ||
29 | $this->addSql('CREATE UNIQUE INDEX UNIQ_1D63E7E592FC23A8 ON ' . $this->getTable('user', true) . ' (username_canonical)'); | ||
30 | break; | ||
31 | case 'mysql': | ||
32 | $this->addSql('ALTER TABLE ' . $this->getTable('user') . ' ADD googleAuthenticatorSecret VARCHAR(191) DEFAULT NULL'); | ||
33 | $this->addSql('ALTER TABLE ' . $this->getTable('user') . ' CHANGE twoFactorAuthentication emailTwoFactor BOOLEAN NOT NULL'); | ||
34 | $this->addSql('ALTER TABLE ' . $this->getTable('user') . ' DROP trusted'); | ||
35 | $this->addSql('ALTER TABLE ' . $this->getTable('user') . ' ADD backupCodes LONGTEXT DEFAULT NULL COMMENT \'(DC2Type:json_array)\''); | ||
36 | break; | ||
37 | case 'postgresql': | ||
38 | $this->addSql('ALTER TABLE ' . $this->getTable('user') . ' ADD googleAuthenticatorSecret VARCHAR(191) DEFAULT NULL'); | ||
39 | $this->addSql('ALTER TABLE ' . $this->getTable('user') . ' RENAME COLUMN twofactorauthentication TO emailTwoFactor'); | ||
40 | $this->addSql('ALTER TABLE ' . $this->getTable('user') . ' DROP trusted'); | ||
41 | $this->addSql('ALTER TABLE ' . $this->getTable('user') . ' ADD backupCodes TEXT DEFAULT NULL'); | ||
42 | break; | ||
43 | } | ||
44 | } | ||
45 | |||
46 | public function down(Schema $schema): void | ||
47 | { | ||
48 | switch ($this->connection->getDatabasePlatform()->getName()) { | ||
49 | case 'sqlite': | ||
50 | $this->addSql('DROP INDEX UNIQ_1D63E7E592FC23A8'); | ||
51 | $this->addSql('DROP INDEX UNIQ_1D63E7E5A0D96FBF'); | ||
52 | $this->addSql('DROP INDEX UNIQ_1D63E7E5C05FB297'); | ||
53 | $this->addSql('CREATE TEMPORARY TABLE __temp__' . $this->getTable('user', true) . ' AS SELECT id, username, username_canonical, email, email_canonical, enabled, salt, password, last_login, confirmation_token, password_requested_at, roles, name, created_at, updated_at, authCode, emailTwoFactor FROM "' . $this->getTable('user', true) . '"'); | ||
54 | $this->addSql('DROP TABLE "' . $this->getTable('user', true) . '"'); | ||
55 | $this->addSql('CREATE TABLE "' . $this->getTable('user', true) . '" (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, username VARCHAR(180) NOT NULL, username_canonical VARCHAR(180) NOT NULL, email VARCHAR(180) NOT NULL, email_canonical VARCHAR(180) NOT NULL, enabled BOOLEAN NOT NULL, password VARCHAR(255) NOT NULL, last_login DATETIME DEFAULT NULL, password_requested_at DATETIME DEFAULT NULL, name CLOB DEFAULT NULL, created_at DATETIME NOT NULL, updated_at DATETIME NOT NULL, authCode INTEGER DEFAULT NULL, twoFactorAuthentication BOOLEAN NOT NULL, salt VARCHAR(255) NOT NULL COLLATE BINARY, confirmation_token VARCHAR(255) DEFAULT NULL COLLATE BINARY, roles CLOB NOT NULL COLLATE BINARY, trusted CLOB DEFAULT NULL COLLATE BINARY)'); | ||
56 | $this->addSql('INSERT INTO "' . $this->getTable('user', true) . '" (id, username, username_canonical, email, email_canonical, enabled, salt, password, last_login, confirmation_token, password_requested_at, roles, name, created_at, updated_at, authCode, twoFactorAuthentication) SELECT id, username, username_canonical, email, email_canonical, enabled, salt, password, last_login, confirmation_token, password_requested_at, roles, name, created_at, updated_at, authCode, emailTwoFactor FROM __temp__' . $this->getTable('user', true) . ''); | ||
57 | $this->addSql('DROP TABLE __temp__' . $this->getTable('user', true) . ''); | ||
58 | $this->addSql('CREATE UNIQUE INDEX UNIQ_1D63E7E592FC23A8 ON "' . $this->getTable('user', true) . '" (username_canonical)'); | ||
59 | $this->addSql('CREATE UNIQUE INDEX UNIQ_1D63E7E5A0D96FBF ON "' . $this->getTable('user', true) . '" (email_canonical)'); | ||
60 | $this->addSql('CREATE UNIQUE INDEX UNIQ_1D63E7E5C05FB297 ON "' . $this->getTable('user', true) . '" (confirmation_token)'); | ||
61 | break; | ||
62 | case 'mysql': | ||
63 | $this->addSql('ALTER TABLE `' . $this->getTable('user') . '` DROP googleAuthenticatorSecret'); | ||
64 | $this->addSql('ALTER TABLE `' . $this->getTable('user') . '` CHANGE emailtwofactor twoFactorAuthentication BOOLEAN NOT NULL'); | ||
65 | $this->addSql('ALTER TABLE `' . $this->getTable('user') . '` ADD trusted TEXT DEFAULT NULL'); | ||
66 | $this->addSql('ALTER TABLE `' . $this->getTable('user') . '` DROP backupCodes'); | ||
67 | break; | ||
68 | case 'postgresql': | ||
69 | $this->addSql('ALTER TABLE ' . $this->getTable('user') . ' DROP googleAuthenticatorSecret'); | ||
70 | $this->addSql('ALTER TABLE ' . $this->getTable('user') . ' RENAME COLUMN emailTwoFactor TO twofactorauthentication'); | ||
71 | $this->addSql('ALTER TABLE ' . $this->getTable('user') . ' ADD trusted TEXT DEFAULT NULL'); | ||
72 | $this->addSql('ALTER TABLE ' . $this->getTable('user') . ' DROP backupCodes'); | ||
73 | break; | ||
74 | } | ||
75 | } | ||
76 | } | ||
diff --git a/app/Resources/static/themes/_global/index.js b/app/Resources/static/themes/_global/index.js index bb3e95b6..9ad96fc0 100644 --- a/app/Resources/static/themes/_global/index.js +++ b/app/Resources/static/themes/_global/index.js | |||
@@ -89,4 +89,22 @@ $(document).ready(() => { | |||
89 | } | 89 | } |
90 | }; | 90 | }; |
91 | }); | 91 | }); |
92 | |||
93 | // mimic radio button because emailTwoFactor is a boolean | ||
94 | $('#update_user_googleTwoFactor').on('change', () => { | ||
95 | $('#update_user_emailTwoFactor').prop('checked', false); | ||
96 | }); | ||
97 | |||
98 | $('#update_user_emailTwoFactor').on('change', () => { | ||
99 | $('#update_user_googleTwoFactor').prop('checked', false); | ||
100 | }); | ||
101 | |||
102 | // same mimic for super admin | ||
103 | $('#user_googleTwoFactor').on('change', () => { | ||
104 | $('#user_emailTwoFactor').prop('checked', false); | ||
105 | }); | ||
106 | |||
107 | $('#user_emailTwoFactor').on('change', () => { | ||
108 | $('#user_googleTwoFactor').prop('checked', false); | ||
109 | }); | ||
92 | }); | 110 | }); |
diff --git a/app/Resources/static/themes/material/index.js b/app/Resources/static/themes/material/index.js index 05794597..2926cad1 100755 --- a/app/Resources/static/themes/material/index.js +++ b/app/Resources/static/themes/material/index.js | |||
@@ -50,25 +50,30 @@ $(document).ready(() => { | |||
50 | $('#tag_label').focus(); | 50 | $('#tag_label').focus(); |
51 | return false; | 51 | return false; |
52 | }); | 52 | }); |
53 | |||
53 | $('#nav-btn-add').on('click', () => { | 54 | $('#nav-btn-add').on('click', () => { |
54 | toggleNav('.nav-panel-add', '#entry_url'); | 55 | toggleNav('.nav-panel-add', '#entry_url'); |
55 | return false; | 56 | return false; |
56 | }); | 57 | }); |
58 | |||
57 | const materialAddForm = $('.nav-panel-add'); | 59 | const materialAddForm = $('.nav-panel-add'); |
58 | materialAddForm.on('submit', () => { | 60 | materialAddForm.on('submit', () => { |
59 | materialAddForm.addClass('disabled'); | 61 | materialAddForm.addClass('disabled'); |
60 | $('input#entry_url', materialAddForm).prop('readonly', true).trigger('blur'); | 62 | $('input#entry_url', materialAddForm).prop('readonly', true).trigger('blur'); |
61 | }); | 63 | }); |
64 | |||
62 | $('#nav-btn-search').on('click', () => { | 65 | $('#nav-btn-search').on('click', () => { |
63 | toggleNav('.nav-panel-search', '#search_entry_term'); | 66 | toggleNav('.nav-panel-search', '#search_entry_term'); |
64 | return false; | 67 | return false; |
65 | }); | 68 | }); |
69 | |||
66 | $('.close').on('click', (e) => { | 70 | $('.close').on('click', (e) => { |
67 | $(e.target).parent('.nav-panel-item').hide(100); | 71 | $(e.target).parent('.nav-panel-item').hide(100); |
68 | $('.nav-panel-actions').show(100); | 72 | $('.nav-panel-actions').show(100); |
69 | $('.nav-panels').css('background', 'transparent'); | 73 | $('.nav-panels').css('background', 'transparent'); |
70 | return false; | 74 | return false; |
71 | }); | 75 | }); |
76 | |||
72 | $(window).scroll(() => { | 77 | $(window).scroll(() => { |
73 | const s = $(window).scrollTop(); | 78 | const s = $(window).scrollTop(); |
74 | const d = $(document).height(); | 79 | const d = $(document).height(); |
diff --git a/app/config/config.yml b/app/config/config.yml index 4b34af30..2d8f9bf0 100644 --- a/app/config/config.yml +++ b/app/config/config.yml | |||
@@ -198,10 +198,17 @@ fos_oauth_server: | |||
198 | refresh_token_lifetime: 1209600 | 198 | refresh_token_lifetime: 1209600 |
199 | 199 | ||
200 | scheb_two_factor: | 200 | scheb_two_factor: |
201 | trusted_computer: | 201 | trusted_device: |
202 | enabled: true | 202 | enabled: true |
203 | cookie_name: wllbg_trusted_computer | 203 | cookie_name: wllbg_trusted_computer |
204 | cookie_lifetime: 2592000 | 204 | lifetime: 2592000 |
205 | |||
206 | backup_codes: | ||
207 | enabled: "%twofactor_auth%" | ||
208 | |||
209 | google: | ||
210 | enabled: "%twofactor_auth%" | ||
211 | template: WallabagUserBundle:Authentication:form.html.twig | ||
205 | 212 | ||
206 | email: | 213 | email: |
207 | enabled: "%twofactor_auth%" | 214 | enabled: "%twofactor_auth%" |
diff --git a/app/config/routing.yml b/app/config/routing.yml index 0bd2d130..a7c0f7e9 100644 --- a/app/config/routing.yml +++ b/app/config/routing.yml | |||
@@ -51,3 +51,11 @@ craue_config_settings_modify: | |||
51 | 51 | ||
52 | fos_js_routing: | 52 | fos_js_routing: |
53 | resource: "@FOSJsRoutingBundle/Resources/config/routing/routing.xml" | 53 | resource: "@FOSJsRoutingBundle/Resources/config/routing/routing.xml" |
54 | |||
55 | 2fa_login: | ||
56 | path: /2fa | ||
57 | defaults: | ||
58 | _controller: "scheb_two_factor.form_controller:form" | ||
59 | |||
60 | 2fa_login_check: | ||
61 | path: /2fa_check | ||
diff --git a/app/config/security.yml b/app/config/security.yml index 96489e26..6a21b4e5 100644 --- a/app/config/security.yml +++ b/app/config/security.yml | |||
@@ -56,9 +56,17 @@ security: | |||
56 | path: /logout | 56 | path: /logout |
57 | target: / | 57 | target: / |
58 | 58 | ||
59 | two_factor: | ||
60 | provider: fos_userbundle | ||
61 | auth_form_path: 2fa_login | ||
62 | check_path: 2fa_login_check | ||
63 | |||
59 | access_control: | 64 | access_control: |
60 | - { path: ^/api/(doc|version|info|user), roles: IS_AUTHENTICATED_ANONYMOUSLY } | 65 | - { path: ^/api/(doc|version|info|user), roles: IS_AUTHENTICATED_ANONYMOUSLY } |
61 | - { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY } | 66 | - { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY } |
67 | # force role for logout otherwise when 2fa enable, you won't be able to logout | ||
68 | # https://github.com/scheb/two-factor-bundle/issues/168#issuecomment-430822478 | ||
69 | - { path: ^/logout, roles: [IS_AUTHENTICATED_ANONYMOUSLY, IS_AUTHENTICATED_2FA_IN_PROGRESS] } | ||
62 | - { path: ^/register, role: IS_AUTHENTICATED_ANONYMOUSLY } | 70 | - { path: ^/register, role: IS_AUTHENTICATED_ANONYMOUSLY } |
63 | - { path: ^/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY } | 71 | - { path: ^/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY } |
64 | - { path: /(unread|starred|archive|all).xml$, roles: IS_AUTHENTICATED_ANONYMOUSLY } | 72 | - { path: /(unread|starred|archive|all).xml$, roles: IS_AUTHENTICATED_ANONYMOUSLY } |
@@ -67,5 +75,6 @@ security: | |||
67 | - { path: ^/share, roles: IS_AUTHENTICATED_ANONYMOUSLY } | 75 | - { path: ^/share, roles: IS_AUTHENTICATED_ANONYMOUSLY } |
68 | - { path: ^/settings, roles: ROLE_SUPER_ADMIN } | 76 | - { path: ^/settings, roles: ROLE_SUPER_ADMIN } |
69 | - { path: ^/annotations, roles: ROLE_USER } | 77 | - { path: ^/annotations, roles: ROLE_USER } |
78 | - { path: ^/2fa, role: IS_AUTHENTICATED_2FA_IN_PROGRESS } | ||
70 | - { path: ^/users, roles: ROLE_SUPER_ADMIN } | 79 | - { path: ^/users, roles: ROLE_SUPER_ADMIN } |
71 | - { path: ^/, roles: ROLE_USER } | 80 | - { path: ^/, roles: ROLE_USER } |
diff --git a/composer.json b/composer.json index 21d71b74..7678d7b8 100644 --- a/composer.json +++ b/composer.json | |||
@@ -31,7 +31,7 @@ | |||
31 | "issues": "https://github.com/wallabag/wallabag/issues" | 31 | "issues": "https://github.com/wallabag/wallabag/issues" |
32 | }, | 32 | }, |
33 | "require": { | 33 | "require": { |
34 | "php": ">=7.1.0", | 34 | "php": ">=7.1.3", |
35 | "ext-pcre": "*", | 35 | "ext-pcre": "*", |
36 | "ext-dom": "*", | 36 | "ext-dom": "*", |
37 | "ext-curl": "*", | 37 | "ext-curl": "*", |
@@ -70,7 +70,7 @@ | |||
70 | "friendsofsymfony/user-bundle": "2.0.*", | 70 | "friendsofsymfony/user-bundle": "2.0.*", |
71 | "friendsofsymfony/oauth-server-bundle": "^1.5", | 71 | "friendsofsymfony/oauth-server-bundle": "^1.5", |
72 | "stof/doctrine-extensions-bundle": "^1.2", | 72 | "stof/doctrine-extensions-bundle": "^1.2", |
73 | "scheb/two-factor-bundle": "^2.14", | 73 | "scheb/two-factor-bundle": "^3.0", |
74 | "grandt/phpepub": "dev-master", | 74 | "grandt/phpepub": "dev-master", |
75 | "wallabag/php-mobi": "~1.0", | 75 | "wallabag/php-mobi": "~1.0", |
76 | "kphoen/rulerz-bundle": "~0.13", | 76 | "kphoen/rulerz-bundle": "~0.13", |
@@ -87,7 +87,8 @@ | |||
87 | "friendsofsymfony/jsrouting-bundle": "^2.2", | 87 | "friendsofsymfony/jsrouting-bundle": "^2.2", |
88 | "bdunogier/guzzle-site-authenticator": "^1.0.0", | 88 | "bdunogier/guzzle-site-authenticator": "^1.0.0", |
89 | "defuse/php-encryption": "^2.1", | 89 | "defuse/php-encryption": "^2.1", |
90 | "html2text/html2text": "^4.1" | 90 | "html2text/html2text": "^4.1", |
91 | "pragmarx/recovery": "^0.1.0" | ||
91 | }, | 92 | }, |
92 | "require-dev": { | 93 | "require-dev": { |
93 | "doctrine/doctrine-fixtures-bundle": "~3.0", | 94 | "doctrine/doctrine-fixtures-bundle": "~3.0", |
@@ -147,7 +148,7 @@ | |||
147 | "config": { | 148 | "config": { |
148 | "bin-dir": "bin", | 149 | "bin-dir": "bin", |
149 | "platform": { | 150 | "platform": { |
150 | "php": "7.1" | 151 | "php": "7.1.3" |
151 | } | 152 | } |
152 | }, | 153 | }, |
153 | "minimum-stability": "dev", | 154 | "minimum-stability": "dev", |
diff --git a/src/Wallabag/CoreBundle/Command/ShowUserCommand.php b/src/Wallabag/CoreBundle/Command/ShowUserCommand.php index a0184267..c95efbf3 100644 --- a/src/Wallabag/CoreBundle/Command/ShowUserCommand.php +++ b/src/Wallabag/CoreBundle/Command/ShowUserCommand.php | |||
@@ -57,7 +57,8 @@ class ShowUserCommand extends ContainerAwareCommand | |||
57 | sprintf('Display name: %s', $user->getName()), | 57 | sprintf('Display name: %s', $user->getName()), |
58 | sprintf('Creation date: %s', $user->getCreatedAt()->format('Y-m-d H:i:s')), | 58 | sprintf('Creation date: %s', $user->getCreatedAt()->format('Y-m-d H:i:s')), |
59 | sprintf('Last login: %s', null !== $user->getLastLogin() ? $user->getLastLogin()->format('Y-m-d H:i:s') : 'never'), | 59 | sprintf('Last login: %s', null !== $user->getLastLogin() ? $user->getLastLogin()->format('Y-m-d H:i:s') : 'never'), |
60 | sprintf('2FA activated: %s', $user->isTwoFactorAuthentication() ? 'yes' : 'no'), | 60 | sprintf('2FA (email) activated: %s', $user->isEmailTwoFactor() ? 'yes' : 'no'), |
61 | sprintf('2FA (OTP) activated: %s', $user->isGoogleAuthenticatorEnabled() ? 'yes' : 'no'), | ||
61 | ]); | 62 | ]); |
62 | } | 63 | } |
63 | 64 | ||
diff --git a/src/Wallabag/CoreBundle/Controller/ConfigController.php b/src/Wallabag/CoreBundle/Controller/ConfigController.php index be6feb7c..9257ab18 100644 --- a/src/Wallabag/CoreBundle/Controller/ConfigController.php +++ b/src/Wallabag/CoreBundle/Controller/ConfigController.php | |||
@@ -2,6 +2,7 @@ | |||
2 | 2 | ||
3 | namespace Wallabag\CoreBundle\Controller; | 3 | namespace Wallabag\CoreBundle\Controller; |
4 | 4 | ||
5 | use PragmaRX\Recovery\Recovery as BackupCodes; | ||
5 | use Symfony\Bundle\FrameworkBundle\Controller\Controller; | 6 | use Symfony\Bundle\FrameworkBundle\Controller\Controller; |
6 | use Symfony\Component\HttpFoundation\JsonResponse; | 7 | use Symfony\Component\HttpFoundation\JsonResponse; |
7 | use Symfony\Component\HttpFoundation\RedirectResponse; | 8 | use Symfony\Component\HttpFoundation\RedirectResponse; |
@@ -46,7 +47,7 @@ class ConfigController extends Controller | |||
46 | $activeTheme = $this->get('liip_theme.active_theme'); | 47 | $activeTheme = $this->get('liip_theme.active_theme'); |
47 | $activeTheme->setName($config->getTheme()); | 48 | $activeTheme->setName($config->getTheme()); |
48 | 49 | ||
49 | $this->get('session')->getFlashBag()->add( | 50 | $this->addFlash( |
50 | 'notice', | 51 | 'notice', |
51 | 'flashes.config.notice.config_saved' | 52 | 'flashes.config.notice.config_saved' |
52 | ); | 53 | ); |
@@ -68,7 +69,7 @@ class ConfigController extends Controller | |||
68 | $userManager->updateUser($user, true); | 69 | $userManager->updateUser($user, true); |
69 | } | 70 | } |
70 | 71 | ||
71 | $this->get('session')->getFlashBag()->add('notice', $message); | 72 | $this->addFlash('notice', $message); |
72 | 73 | ||
73 | return $this->redirect($this->generateUrl('config') . '#set4'); | 74 | return $this->redirect($this->generateUrl('config') . '#set4'); |
74 | } | 75 | } |
@@ -83,7 +84,7 @@ class ConfigController extends Controller | |||
83 | if ($userForm->isSubmitted() && $userForm->isValid()) { | 84 | if ($userForm->isSubmitted() && $userForm->isValid()) { |
84 | $userManager->updateUser($user, true); | 85 | $userManager->updateUser($user, true); |
85 | 86 | ||
86 | $this->get('session')->getFlashBag()->add( | 87 | $this->addFlash( |
87 | 'notice', | 88 | 'notice', |
88 | 'flashes.config.notice.user_updated' | 89 | 'flashes.config.notice.user_updated' |
89 | ); | 90 | ); |
@@ -99,7 +100,7 @@ class ConfigController extends Controller | |||
99 | $em->persist($config); | 100 | $em->persist($config); |
100 | $em->flush(); | 101 | $em->flush(); |
101 | 102 | ||
102 | $this->get('session')->getFlashBag()->add( | 103 | $this->addFlash( |
103 | 'notice', | 104 | 'notice', |
104 | 'flashes.config.notice.rss_updated' | 105 | 'flashes.config.notice.rss_updated' |
105 | ); | 106 | ); |
@@ -131,7 +132,7 @@ class ConfigController extends Controller | |||
131 | $em->persist($taggingRule); | 132 | $em->persist($taggingRule); |
132 | $em->flush(); | 133 | $em->flush(); |
133 | 134 | ||
134 | $this->get('session')->getFlashBag()->add( | 135 | $this->addFlash( |
135 | 'notice', | 136 | 'notice', |
136 | 'flashes.config.notice.tagging_rules_updated' | 137 | 'flashes.config.notice.tagging_rules_updated' |
137 | ); | 138 | ); |
@@ -153,12 +154,124 @@ class ConfigController extends Controller | |||
153 | ], | 154 | ], |
154 | 'twofactor_auth' => $this->getParameter('twofactor_auth'), | 155 | 'twofactor_auth' => $this->getParameter('twofactor_auth'), |
155 | 'wallabag_url' => $this->getParameter('domain_name'), | 156 | 'wallabag_url' => $this->getParameter('domain_name'), |
156 | 'enabled_users' => $this->get('wallabag_user.user_repository') | 157 | 'enabled_users' => $this->get('wallabag_user.user_repository')->getSumEnabledUsers(), |
157 | ->getSumEnabledUsers(), | ||
158 | ]); | 158 | ]); |
159 | } | 159 | } |
160 | 160 | ||
161 | /** | 161 | /** |
162 | * Enable 2FA using email. | ||
163 | * | ||
164 | * @Route("/config/otp/email", name="config_otp_email") | ||
165 | */ | ||
166 | public function otpEmailAction() | ||
167 | { | ||
168 | if (!$this->getParameter('twofactor_auth')) { | ||
169 | return $this->createNotFoundException('two_factor not enabled'); | ||
170 | } | ||
171 | |||
172 | $user = $this->getUser(); | ||
173 | |||
174 | $user->setGoogleAuthenticatorSecret(null); | ||
175 | $user->setBackupCodes(null); | ||
176 | $user->setEmailTwoFactor(true); | ||
177 | |||
178 | $this->container->get('fos_user.user_manager')->updateUser($user, true); | ||
179 | |||
180 | $this->addFlash( | ||
181 | 'notice', | ||
182 | 'flashes.config.notice.otp_enabled' | ||
183 | ); | ||
184 | |||
185 | return $this->redirect($this->generateUrl('config') . '#set3'); | ||
186 | } | ||
187 | |||
188 | /** | ||
189 | * Enable 2FA using OTP app, user will need to confirm the generated code from the app. | ||
190 | * | ||
191 | * @Route("/config/otp/app", name="config_otp_app") | ||
192 | */ | ||
193 | public function otpAppAction() | ||
194 | { | ||
195 | if (!$this->getParameter('twofactor_auth')) { | ||
196 | return $this->createNotFoundException('two_factor not enabled'); | ||
197 | } | ||
198 | |||
199 | $user = $this->getUser(); | ||
200 | $secret = $this->get('scheb_two_factor.security.google_authenticator')->generateSecret(); | ||
201 | |||
202 | $user->setGoogleAuthenticatorSecret($secret); | ||
203 | $user->setEmailTwoFactor(false); | ||
204 | |||
205 | $backupCodes = (new BackupCodes())->toArray(); | ||
206 | $backupCodesHashed = array_map( | ||
207 | function ($backupCode) { | ||
208 | return password_hash($backupCode, PASSWORD_DEFAULT); | ||
209 | }, | ||
210 | $backupCodes | ||
211 | ); | ||
212 | |||
213 | $user->setBackupCodes($backupCodesHashed); | ||
214 | |||
215 | $this->container->get('fos_user.user_manager')->updateUser($user, true); | ||
216 | |||
217 | return $this->render('WallabagCoreBundle:Config:otp_app.html.twig', [ | ||
218 | 'backupCodes' => $backupCodes, | ||
219 | 'qr_code' => $this->get('scheb_two_factor.security.google_authenticator')->getQRContent($user), | ||
220 | ]); | ||
221 | } | ||
222 | |||
223 | /** | ||
224 | * Cancelling 2FA using OTP app. | ||
225 | * | ||
226 | * @Route("/config/otp/app/cancel", name="config_otp_app_cancel") | ||
227 | */ | ||
228 | public function otpAppCancelAction() | ||
229 | { | ||
230 | if (!$this->getParameter('twofactor_auth')) { | ||
231 | return $this->createNotFoundException('two_factor not enabled'); | ||
232 | } | ||
233 | |||
234 | $user = $this->getUser(); | ||
235 | $user->setGoogleAuthenticatorSecret(null); | ||
236 | $user->setBackupCodes(null); | ||
237 | |||
238 | $this->container->get('fos_user.user_manager')->updateUser($user, true); | ||
239 | |||
240 | return $this->redirect($this->generateUrl('config') . '#set3'); | ||
241 | } | ||
242 | |||
243 | /** | ||
244 | * Validate OTP code. | ||
245 | * | ||
246 | * @param Request $request | ||
247 | * | ||
248 | * @Route("/config/otp/app/check", name="config_otp_app_check") | ||
249 | */ | ||
250 | public function otpAppCheckAction(Request $request) | ||
251 | { | ||
252 | $isValid = $this->get('scheb_two_factor.security.google_authenticator')->checkCode( | ||
253 | $this->getUser(), | ||
254 | $request->get('_auth_code') | ||
255 | ); | ||
256 | |||
257 | if (true === $isValid) { | ||
258 | $this->addFlash( | ||
259 | 'notice', | ||
260 | 'flashes.config.notice.otp_enabled' | ||
261 | ); | ||
262 | |||
263 | return $this->redirect($this->generateUrl('config') . '#set3'); | ||
264 | } | ||
265 | |||
266 | $this->addFlash( | ||
267 | 'two_factor', | ||
268 | 'scheb_two_factor.code_invalid' | ||
269 | ); | ||
270 | |||
271 | return $this->redirect($this->generateUrl('config_otp_app')); | ||
272 | } | ||
273 | |||
274 | /** | ||
162 | * @param Request $request | 275 | * @param Request $request |
163 | * | 276 | * |
164 | * @Route("/generate-token", name="generate_token") | 277 | * @Route("/generate-token", name="generate_token") |
@@ -178,7 +291,7 @@ class ConfigController extends Controller | |||
178 | return new JsonResponse(['token' => $config->getRssToken()]); | 291 | return new JsonResponse(['token' => $config->getRssToken()]); |
179 | } | 292 | } |
180 | 293 | ||
181 | $this->get('session')->getFlashBag()->add( | 294 | $this->addFlash( |
182 | 'notice', | 295 | 'notice', |
183 | 'flashes.config.notice.rss_token_updated' | 296 | 'flashes.config.notice.rss_token_updated' |
184 | ); | 297 | ); |
@@ -203,7 +316,7 @@ class ConfigController extends Controller | |||
203 | $em->remove($rule); | 316 | $em->remove($rule); |
204 | $em->flush(); | 317 | $em->flush(); |
205 | 318 | ||
206 | $this->get('session')->getFlashBag()->add( | 319 | $this->addFlash( |
207 | 'notice', | 320 | 'notice', |
208 | 'flashes.config.notice.tagging_rules_deleted' | 321 | 'flashes.config.notice.tagging_rules_deleted' |
209 | ); | 322 | ); |
@@ -269,7 +382,7 @@ class ConfigController extends Controller | |||
269 | break; | 382 | break; |
270 | } | 383 | } |
271 | 384 | ||
272 | $this->get('session')->getFlashBag()->add( | 385 | $this->addFlash( |
273 | 'notice', | 386 | 'notice', |
274 | 'flashes.config.notice.' . $type . '_reset' | 387 | 'flashes.config.notice.' . $type . '_reset' |
275 | ); | 388 | ); |
diff --git a/src/Wallabag/CoreBundle/Form/Type/UserInformationType.php b/src/Wallabag/CoreBundle/Form/Type/UserInformationType.php index 07c99949..6e4c9154 100644 --- a/src/Wallabag/CoreBundle/Form/Type/UserInformationType.php +++ b/src/Wallabag/CoreBundle/Form/Type/UserInformationType.php | |||
@@ -21,9 +21,14 @@ class UserInformationType extends AbstractType | |||
21 | ->add('email', EmailType::class, [ | 21 | ->add('email', EmailType::class, [ |
22 | 'label' => 'config.form_user.email_label', | 22 | 'label' => 'config.form_user.email_label', |
23 | ]) | 23 | ]) |
24 | ->add('twoFactorAuthentication', CheckboxType::class, [ | 24 | ->add('emailTwoFactor', CheckboxType::class, [ |
25 | 'required' => false, | 25 | 'required' => false, |
26 | 'label' => 'config.form_user.twoFactorAuthentication_label', | 26 | 'label' => 'config.form_user.emailTwoFactor_label', |
27 | ]) | ||
28 | ->add('googleTwoFactor', CheckboxType::class, [ | ||
29 | 'required' => false, | ||
30 | 'label' => 'config.form_user.googleTwoFactor_label', | ||
31 | 'mapped' => false, | ||
27 | ]) | 32 | ]) |
28 | ->add('save', SubmitType::class, [ | 33 | ->add('save', SubmitType::class, [ |
29 | 'label' => 'config.form.save', | 34 | 'label' => 'config.form.save', |
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.da.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.da.yml index 5a770dff..454f547d 100644 --- a/src/Wallabag/CoreBundle/Resources/translations/messages.da.yml +++ b/src/Wallabag/CoreBundle/Resources/translations/messages.da.yml | |||
@@ -59,6 +59,7 @@ config: | |||
59 | password: 'Adgangskode' | 59 | password: 'Adgangskode' |
60 | # rules: 'Tagging rules' | 60 | # rules: 'Tagging rules' |
61 | new_user: 'Tilføj bruger' | 61 | new_user: 'Tilføj bruger' |
62 | # reset: 'Reset area' | ||
62 | form: | 63 | form: |
63 | save: 'Gem' | 64 | save: 'Gem' |
64 | form_settings: | 65 | form_settings: |
@@ -98,11 +99,19 @@ config: | |||
98 | # all: 'All' | 99 | # all: 'All' |
99 | # rss_limit: 'Number of items in the feed' | 100 | # rss_limit: 'Number of items in the feed' |
100 | form_user: | 101 | form_user: |
101 | # two_factor_description: "Enabling two factor authentication means you'll receive an email with a code on every new untrusted connexion" | 102 | # two_factor_description: "Enabling two factor authentication means you'll receive an email with a code OR need to use an OTP app (like Google Authenticator, Authy or FreeOTP) to get a one time code on every new untrusted connection. You can't choose both option." |
102 | name_label: 'Navn' | 103 | name_label: 'Navn' |
103 | email_label: 'Emailadresse' | 104 | email_label: 'Emailadresse' |
104 | # twoFactorAuthentication_label: 'Two factor authentication' | 105 | two_factor: |
105 | # help_twoFactorAuthentication: "If you enable 2FA, each time you want to login to wallabag, you'll receive a code by email." | 106 | # emailTwoFactor_label: 'Using email (receive a code by email)' |
107 | # googleTwoFactor_label: 'Using an OTP app (open the app, like Google Authenticator, Authy or FreeOTP, to get a one time code)' | ||
108 | # table_method: Method | ||
109 | # table_state: State | ||
110 | # table_action: Action | ||
111 | # state_enabled: Enabled | ||
112 | # state_disabled: Disabled | ||
113 | # action_email: Use email | ||
114 | # action_app: Use OTP App | ||
106 | delete: | 115 | delete: |
107 | # title: Delete my account (a.k.a danger zone) | 116 | # title: Delete my account (a.k.a danger zone) |
108 | # description: If you remove your account, ALL your articles, ALL your tags, ALL your annotations and your account will be PERMANENTLY removed (it can't be UNDONE). You'll then be logged out. | 117 | # description: If you remove your account, ALL your articles, ALL your tags, ALL your annotations and your account will be PERMANENTLY removed (it can't be UNDONE). You'll then be logged out. |
@@ -160,6 +169,15 @@ config: | |||
160 | # and: 'One rule AND another' | 169 | # and: 'One rule AND another' |
161 | # matches: 'Tests that a <i>subject</i> matches a <i>search</i> (case-insensitive).<br />Example: <code>title matches "football"</code>' | 170 | # matches: 'Tests that a <i>subject</i> matches a <i>search</i> (case-insensitive).<br />Example: <code>title matches "football"</code>' |
162 | # notmatches: 'Tests that a <i>subject</i> doesn''t match match a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>' | 171 | # notmatches: 'Tests that a <i>subject</i> doesn''t match match a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>' |
172 | otp: | ||
173 | # page_title: Two-factor authentication | ||
174 | # app: | ||
175 | # two_factor_code_description_1: You just enabled the OTP two factor authentication, open your OTP app and use that code to get a one time password. It'll disapear after a page reload. | ||
176 | # two_factor_code_description_2: 'You can scan that QR Code with your app:' | ||
177 | # two_factor_code_description_3: 'Also, save these backup codes in a safe place, you can use them in case you lose access to your OTP app:' | ||
178 | # two_factor_code_description_4: 'Test an OTP code from your configured app:' | ||
179 | # cancel: Cancel | ||
180 | # enable: Enable | ||
163 | 181 | ||
164 | entry: | 182 | entry: |
165 | # default_title: 'Title of the entry' | 183 | # default_title: 'Title of the entry' |
@@ -532,7 +550,8 @@ user: | |||
532 | email_label: 'Emailadresse' | 550 | email_label: 'Emailadresse' |
533 | # enabled_label: 'Enabled' | 551 | # enabled_label: 'Enabled' |
534 | # last_login_label: 'Last login' | 552 | # last_login_label: 'Last login' |
535 | # twofactor_label: Two factor authentication | 553 | # twofactor_email_label: Two factor authentication by email |
554 | # twofactor_google_label: Two factor authentication by OTP app | ||
536 | # save: Save | 555 | # save: Save |
537 | # delete: Delete | 556 | # delete: Delete |
538 | # delete_confirm: Are you sure? | 557 | # delete_confirm: Are you sure? |
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.de.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.de.yml index 2ae8f08e..dc1d4723 100644 --- a/src/Wallabag/CoreBundle/Resources/translations/messages.de.yml +++ b/src/Wallabag/CoreBundle/Resources/translations/messages.de.yml | |||
@@ -59,6 +59,7 @@ config: | |||
59 | password: 'Kennwort' | 59 | password: 'Kennwort' |
60 | rules: 'Tagging-Regeln' | 60 | rules: 'Tagging-Regeln' |
61 | new_user: 'Benutzer hinzufügen' | 61 | new_user: 'Benutzer hinzufügen' |
62 | reset: 'Zurücksetzen' | ||
62 | form: | 63 | form: |
63 | save: 'Speichern' | 64 | save: 'Speichern' |
64 | form_settings: | 65 | form_settings: |
@@ -98,11 +99,19 @@ config: | |||
98 | all: 'Alle' | 99 | all: 'Alle' |
99 | rss_limit: 'Anzahl der Einträge pro Feed' | 100 | rss_limit: 'Anzahl der Einträge pro Feed' |
100 | form_user: | 101 | form_user: |
101 | two_factor_description: "Wenn du die Zwei-Faktor-Authentifizierung aktivierst, erhältst du eine E-Mail mit einem Code bei jeder nicht vertrauenswürdigen Verbindung" | 102 | # two_factor_description: "Enabling two factor authentication means you'll receive an email with a code OR need to use an OTP app (like Google Authenticator, Authy or FreeOTP) to get a one time code on every new untrusted connection. You can't choose both option." |
102 | name_label: 'Name' | 103 | name_label: 'Name' |
103 | email_label: 'E-Mail-Adresse' | 104 | email_label: 'E-Mail-Adresse' |
104 | twoFactorAuthentication_label: 'Zwei-Faktor-Authentifizierung' | 105 | two_factor: |
105 | help_twoFactorAuthentication: "Wenn du 2FA aktivierst, wirst du bei jedem Login einen Code per E-Mail bekommen." | 106 | # emailTwoFactor_label: 'Using email (receive a code by email)' |
107 | # googleTwoFactor_label: 'Using an OTP app (open the app, like Google Authenticator, Authy or FreeOTP, to get a one time code)' | ||
108 | # table_method: Method | ||
109 | # table_state: State | ||
110 | # table_action: Action | ||
111 | # state_enabled: Enabled | ||
112 | # state_disabled: Disabled | ||
113 | # action_email: Use email | ||
114 | # action_app: Use OTP App | ||
106 | delete: | 115 | delete: |
107 | title: 'Lösche mein Konto (a.k.a Gefahrenzone)' | 116 | title: 'Lösche mein Konto (a.k.a Gefahrenzone)' |
108 | description: 'Wenn du dein Konto löschst, werden ALL deine Artikel, ALL deine Tags, ALL deine Anmerkungen und dein Konto dauerhaft gelöscht (kann NICHT RÜCKGÄNGIG gemacht werden). Du wirst anschließend ausgeloggt.' | 117 | description: 'Wenn du dein Konto löschst, werden ALL deine Artikel, ALL deine Tags, ALL deine Anmerkungen und dein Konto dauerhaft gelöscht (kann NICHT RÜCKGÄNGIG gemacht werden). Du wirst anschließend ausgeloggt.' |
@@ -532,7 +541,8 @@ user: | |||
532 | email_label: 'E-Mail-Adresse' | 541 | email_label: 'E-Mail-Adresse' |
533 | enabled_label: 'Aktiviert' | 542 | enabled_label: 'Aktiviert' |
534 | last_login_label: 'Letzter Login' | 543 | last_login_label: 'Letzter Login' |
535 | twofactor_label: 'Zwei-Faktor-Authentifizierung' | 544 | # twofactor_email_label: Two factor authentication by email |
545 | # twofactor_google_label: Two factor authentication by OTP app | ||
536 | save: 'Speichern' | 546 | save: 'Speichern' |
537 | delete: 'Löschen' | 547 | delete: 'Löschen' |
538 | delete_confirm: 'Bist du sicher?' | 548 | delete_confirm: 'Bist du sicher?' |
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.en.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.en.yml index d1d74159..45145c80 100644 --- a/src/Wallabag/CoreBundle/Resources/translations/messages.en.yml +++ b/src/Wallabag/CoreBundle/Resources/translations/messages.en.yml | |||
@@ -59,6 +59,7 @@ config: | |||
59 | password: 'Password' | 59 | password: 'Password' |
60 | rules: 'Tagging rules' | 60 | rules: 'Tagging rules' |
61 | new_user: 'Add a user' | 61 | new_user: 'Add a user' |
62 | reset: 'Reset area' | ||
62 | form: | 63 | form: |
63 | save: 'Save' | 64 | save: 'Save' |
64 | form_settings: | 65 | form_settings: |
@@ -98,11 +99,19 @@ config: | |||
98 | all: 'All' | 99 | all: 'All' |
99 | rss_limit: 'Number of items in the feed' | 100 | rss_limit: 'Number of items in the feed' |
100 | form_user: | 101 | form_user: |
101 | two_factor_description: "Enabling two factor authentication means you'll receive an email with a code on every new untrusted connection." | 102 | two_factor_description: "Enabling two factor authentication means you'll receive an email with a code OR need to use an OTP app (like Google Authenticator, Authy or FreeOTP) to get a one time code on every new untrusted connection. You can't choose both option." |
102 | name_label: 'Name' | 103 | name_label: 'Name' |
103 | email_label: 'Email' | 104 | email_label: 'Email' |
104 | twoFactorAuthentication_label: 'Two factor authentication' | 105 | two_factor: |
105 | help_twoFactorAuthentication: "If you enable 2FA, each time you want to login to wallabag, you'll receive a code by email." | 106 | emailTwoFactor_label: 'Using email (receive a code by email)' |
107 | googleTwoFactor_label: 'Using an OTP app (open the app, like Google Authenticator, Authy or FreeOTP, to get a one time code)' | ||
108 | table_method: Method | ||
109 | table_state: State | ||
110 | table_action: Action | ||
111 | state_enabled: Enabled | ||
112 | state_disabled: Disabled | ||
113 | action_email: Use email | ||
114 | action_app: Use OTP App | ||
106 | delete: | 115 | delete: |
107 | title: Delete my account (a.k.a danger zone) | 116 | title: Delete my account (a.k.a danger zone) |
108 | description: If you remove your account, ALL your articles, ALL your tags, ALL your annotations and your account will be PERMANENTLY removed (it can't be UNDONE). You'll then be logged out. | 117 | description: If you remove your account, ALL your articles, ALL your tags, ALL your annotations and your account will be PERMANENTLY removed (it can't be UNDONE). You'll then be logged out. |
@@ -160,6 +169,15 @@ config: | |||
160 | and: 'One rule AND another' | 169 | and: 'One rule AND another' |
161 | matches: 'Tests that a <i>subject</i> matches a <i>search</i> (case-insensitive).<br />Example: <code>title matches "football"</code>' | 170 | matches: 'Tests that a <i>subject</i> matches a <i>search</i> (case-insensitive).<br />Example: <code>title matches "football"</code>' |
162 | notmatches: 'Tests that a <i>subject</i> doesn''t match match a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>' | 171 | notmatches: 'Tests that a <i>subject</i> doesn''t match match a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>' |
172 | otp: | ||
173 | page_title: Two-factor authentication | ||
174 | app: | ||
175 | two_factor_code_description_1: You just enabled the OTP two factor authentication, open your OTP app and use that code to get a one time password. It'll disapear after a page reload. | ||
176 | two_factor_code_description_2: 'You can scan that QR Code with your app:' | ||
177 | two_factor_code_description_3: 'Also, save these backup codes in a safe place, you can use them in case you lose access to your OTP app:' | ||
178 | two_factor_code_description_4: 'Test an OTP code from your configured app:' | ||
179 | cancel: Cancel | ||
180 | enable: Enable | ||
163 | 181 | ||
164 | entry: | 182 | entry: |
165 | default_title: 'Title of the entry' | 183 | default_title: 'Title of the entry' |
@@ -532,7 +550,8 @@ user: | |||
532 | email_label: 'Email' | 550 | email_label: 'Email' |
533 | enabled_label: 'Enabled' | 551 | enabled_label: 'Enabled' |
534 | last_login_label: 'Last login' | 552 | last_login_label: 'Last login' |
535 | twofactor_label: Two factor authentication | 553 | twofactor_email_label: Two factor authentication by email |
554 | twofactor_google_label: Two factor authentication by OTP app | ||
536 | save: Save | 555 | save: Save |
537 | delete: Delete | 556 | delete: Delete |
538 | delete_confirm: Are you sure? | 557 | delete_confirm: Are you sure? |
@@ -578,6 +597,7 @@ flashes: | |||
578 | tags_reset: Tags reset | 597 | tags_reset: Tags reset |
579 | entries_reset: Entries reset | 598 | entries_reset: Entries reset |
580 | archived_reset: Archived entries deleted | 599 | archived_reset: Archived entries deleted |
600 | otp_enabled: Two-factor authentication enabled | ||
581 | entry: | 601 | entry: |
582 | notice: | 602 | notice: |
583 | entry_already_saved: 'Entry already saved on %date%' | 603 | entry_already_saved: 'Entry already saved on %date%' |
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.es.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.es.yml index 741d3e9f..c1047e55 100644 --- a/src/Wallabag/CoreBundle/Resources/translations/messages.es.yml +++ b/src/Wallabag/CoreBundle/Resources/translations/messages.es.yml | |||
@@ -59,6 +59,7 @@ config: | |||
59 | password: 'Contraseña' | 59 | password: 'Contraseña' |
60 | rules: 'Reglas de etiquetado automáticas' | 60 | rules: 'Reglas de etiquetado automáticas' |
61 | new_user: 'Añadir un usuario' | 61 | new_user: 'Añadir un usuario' |
62 | reset: 'Reiniciar mi cuenta' | ||
62 | form: | 63 | form: |
63 | save: 'Guardar' | 64 | save: 'Guardar' |
64 | form_settings: | 65 | form_settings: |
@@ -98,11 +99,19 @@ config: | |||
98 | # all: 'All' | 99 | # all: 'All' |
99 | rss_limit: 'Límite de artículos en feed RSS' | 100 | rss_limit: 'Límite de artículos en feed RSS' |
100 | form_user: | 101 | form_user: |
101 | two_factor_description: "Con la autenticación en dos pasos recibirá código por e-mail en cada nueva conexión que no sea de confianza." | 102 | # two_factor_description: "Enabling two factor authentication means you'll receive an email with a code OR need to use an OTP app (like Google Authenticator, Authy or FreeOTP) to get a one time code on every new untrusted connection. You can't choose both option." |
102 | name_label: 'Nombre' | 103 | name_label: 'Nombre' |
103 | email_label: 'Dirección de e-mail' | 104 | email_label: 'Dirección de e-mail' |
104 | twoFactorAuthentication_label: 'Autenticación en dos pasos' | 105 | two_factor: |
105 | help_twoFactorAuthentication: "Si activas la autenticación en dos pasos, cada vez que quieras iniciar sesión en wallabag recibirás un código por e-mail." | 106 | # emailTwoFactor_label: 'Using email (receive a code by email)' |
107 | # googleTwoFactor_label: 'Using an OTP app (open the app, like Google Authenticator, Authy or FreeOTP, to get a one time code)' | ||
108 | # table_method: Method | ||
109 | # table_state: State | ||
110 | # table_action: Action | ||
111 | # state_enabled: Enabled | ||
112 | # state_disabled: Disabled | ||
113 | # action_email: Use email | ||
114 | # action_app: Use OTP App | ||
106 | delete: | 115 | delete: |
107 | title: Eliminar mi cuenta (Zona peligrosa) | 116 | title: Eliminar mi cuenta (Zona peligrosa) |
108 | description: Si eliminas tu cuenta, TODOS tus artículos, TODAS tus etiquetas, TODAS tus anotaciones y tu cuenta serán eliminadas de forma PERMANENTE (no se puede deshacer). Después serás desconectado. | 117 | description: Si eliminas tu cuenta, TODOS tus artículos, TODAS tus etiquetas, TODAS tus anotaciones y tu cuenta serán eliminadas de forma PERMANENTE (no se puede deshacer). Después serás desconectado. |
@@ -160,6 +169,15 @@ config: | |||
160 | and: 'Una regla Y la otra' | 169 | and: 'Una regla Y la otra' |
161 | matches: 'Prueba si un <i>sujeto</i> corresponde a una <i>búsqueda</i> (insensible a mayusculas).<br />Ejemplo : <code>title matches "fútbol"</code>' | 170 | matches: 'Prueba si un <i>sujeto</i> corresponde a una <i>búsqueda</i> (insensible a mayusculas).<br />Ejemplo : <code>title matches "fútbol"</code>' |
162 | # notmatches: 'Tests that a <i>subject</i> doesn''t match match a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>' | 171 | # notmatches: 'Tests that a <i>subject</i> doesn''t match match a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>' |
172 | otp: | ||
173 | # page_title: Two-factor authentication | ||
174 | # app: | ||
175 | # two_factor_code_description_1: You just enabled the OTP two factor authentication, open your OTP app and use that code to get a one time password. It'll disapear after a page reload. | ||
176 | # two_factor_code_description_2: 'You can scan that QR Code with your app:' | ||
177 | # two_factor_code_description_3: 'Also, save these backup codes in a safe place, you can use them in case you lose access to your OTP app:' | ||
178 | # two_factor_code_description_4: 'Test an OTP code from your configured app:' | ||
179 | # cancel: Cancel | ||
180 | # enable: Enable | ||
163 | 181 | ||
164 | entry: | 182 | entry: |
165 | default_title: 'Título del artículo' | 183 | default_title: 'Título del artículo' |
@@ -532,7 +550,8 @@ user: | |||
532 | email_label: 'E-mail' | 550 | email_label: 'E-mail' |
533 | enabled_label: 'Activado' | 551 | enabled_label: 'Activado' |
534 | last_login_label: 'Último inicio de sesión' | 552 | last_login_label: 'Último inicio de sesión' |
535 | twofactor_label: Autenticación en dos pasos | 553 | # twofactor_email_label: Two factor authentication by email |
554 | # twofactor_google_label: Two factor authentication by OTP app | ||
536 | save: Guardar | 555 | save: Guardar |
537 | delete: Eliminar | 556 | delete: Eliminar |
538 | delete_confirm: ¿Estás seguro? | 557 | delete_confirm: ¿Estás seguro? |
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.fa.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.fa.yml index 2ef5dd52..3042de2e 100644 --- a/src/Wallabag/CoreBundle/Resources/translations/messages.fa.yml +++ b/src/Wallabag/CoreBundle/Resources/translations/messages.fa.yml | |||
@@ -59,6 +59,7 @@ config: | |||
59 | password: 'رمز' | 59 | password: 'رمز' |
60 | rules: 'برچسبگذاری خودکار' | 60 | rules: 'برچسبگذاری خودکار' |
61 | new_user: 'افزودن کاربر' | 61 | new_user: 'افزودن کاربر' |
62 | # reset: 'Reset area' | ||
62 | form: | 63 | form: |
63 | save: 'ذخیره' | 64 | save: 'ذخیره' |
64 | form_settings: | 65 | form_settings: |
@@ -98,11 +99,19 @@ config: | |||
98 | # all: 'All' | 99 | # all: 'All' |
99 | rss_limit: 'محدودیت آر-اس-اس' | 100 | rss_limit: 'محدودیت آر-اس-اس' |
100 | form_user: | 101 | form_user: |
101 | two_factor_description: "با فعالکردن تأیید ۲مرحلهای هر بار که اتصال تأییدنشدهای برقرار شد، به شما یک کد از راه ایمیل فرستاده میشود" | 102 | # two_factor_description: "Enabling two factor authentication means you'll receive an email with a code OR need to use an OTP app (like Google Authenticator, Authy or FreeOTP) to get a one time code on every new untrusted connection. You can't choose both option." |
102 | name_label: 'نام' | 103 | name_label: 'نام' |
103 | email_label: 'نشانی ایمیل' | 104 | email_label: 'نشانی ایمیل' |
104 | twoFactorAuthentication_label: 'تأیید ۲مرحلهای' | 105 | two_factor: |
105 | # help_twoFactorAuthentication: "If you enable 2FA, each time you want to login to wallabag, you'll receive a code by email." | 106 | # emailTwoFactor_label: 'Using email (receive a code by email)' |
107 | # googleTwoFactor_label: 'Using an OTP app (open the app, like Google Authenticator, Authy or FreeOTP, to get a one time code)' | ||
108 | # table_method: Method | ||
109 | # table_state: State | ||
110 | # table_action: Action | ||
111 | # state_enabled: Enabled | ||
112 | # state_disabled: Disabled | ||
113 | # action_email: Use email | ||
114 | # action_app: Use OTP App | ||
106 | delete: | 115 | delete: |
107 | # title: Delete my account (a.k.a danger zone) | 116 | # title: Delete my account (a.k.a danger zone) |
108 | # description: If you remove your account, ALL your articles, ALL your tags, ALL your annotations and your account will be PERMANENTLY removed (it can't be UNDONE). You'll then be logged out. | 117 | # description: If you remove your account, ALL your articles, ALL your tags, ALL your annotations and your account will be PERMANENTLY removed (it can't be UNDONE). You'll then be logged out. |
@@ -160,6 +169,15 @@ config: | |||
160 | # and: 'One rule AND another' | 169 | # and: 'One rule AND another' |
161 | # matches: 'Tests that a <i>subject</i> matches a <i>search</i> (case-insensitive).<br />Example: <code>title matches "football"</code>' | 170 | # matches: 'Tests that a <i>subject</i> matches a <i>search</i> (case-insensitive).<br />Example: <code>title matches "football"</code>' |
162 | # notmatches: 'Tests that a <i>subject</i> doesn''t match match a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>' | 171 | # notmatches: 'Tests that a <i>subject</i> doesn''t match match a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>' |
172 | otp: | ||
173 | # page_title: Two-factor authentication | ||
174 | # app: | ||
175 | # two_factor_code_description_1: You just enabled the OTP two factor authentication, open your OTP app and use that code to get a one time password. It'll disapear after a page reload. | ||
176 | # two_factor_code_description_2: 'You can scan that QR Code with your app:' | ||
177 | # two_factor_code_description_3: 'Also, save these backup codes in a safe place, you can use them in case you lose access to your OTP app:' | ||
178 | # two_factor_code_description_4: 'Test an OTP code from your configured app:' | ||
179 | # cancel: Cancel | ||
180 | # enable: Enable | ||
163 | 181 | ||
164 | entry: | 182 | entry: |
165 | # default_title: 'Title of the entry' | 183 | # default_title: 'Title of the entry' |
@@ -532,7 +550,8 @@ user: | |||
532 | email_label: 'نشانی ایمیل' | 550 | email_label: 'نشانی ایمیل' |
533 | # enabled_label: 'Enabled' | 551 | # enabled_label: 'Enabled' |
534 | # last_login_label: 'Last login' | 552 | # last_login_label: 'Last login' |
535 | # twofactor_label: Two factor authentication | 553 | # twofactor_email_label: Two factor authentication by email |
554 | # twofactor_google_label: Two factor authentication by OTP app | ||
536 | # save: Save | 555 | # save: Save |
537 | # delete: Delete | 556 | # delete: Delete |
538 | # delete_confirm: Are you sure? | 557 | # delete_confirm: Are you sure? |
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.fr.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.fr.yml index 7a2029b4..57740ba2 100644 --- a/src/Wallabag/CoreBundle/Resources/translations/messages.fr.yml +++ b/src/Wallabag/CoreBundle/Resources/translations/messages.fr.yml | |||
@@ -59,6 +59,7 @@ config: | |||
59 | password: "Mot de passe" | 59 | password: "Mot de passe" |
60 | rules: "Règles de tag automatiques" | 60 | rules: "Règles de tag automatiques" |
61 | new_user: "Créer un compte" | 61 | new_user: "Créer un compte" |
62 | reset: "Réinitialisation" | ||
62 | form: | 63 | form: |
63 | save: "Enregistrer" | 64 | save: "Enregistrer" |
64 | form_settings: | 65 | form_settings: |
@@ -98,11 +99,19 @@ config: | |||
98 | all: "Tous" | 99 | all: "Tous" |
99 | rss_limit: "Nombre d’articles dans le flux" | 100 | rss_limit: "Nombre d’articles dans le flux" |
100 | form_user: | 101 | form_user: |
101 | two_factor_description: "Activer l’authentification double-facteur veut dire que vous allez recevoir un code par courriel à chaque nouvelle connexion non approuvée." | 102 | two_factor_description: "Activer l’authentification double-facteur veut dire que vous allez recevoir un code par courriel OU que vous devriez utiliser une application de mot de passe à usage unique (comme Google Authenticator, Authy or FreeOTP) pour obtenir un code temporaire à chaque nouvelle connexion non approuvée. Vous ne pouvez pas choisir les deux options." |
102 | name_label: "Nom" | 103 | name_label: "Nom" |
103 | email_label: "Adresse courriel" | 104 | email_label: "Adresse courriel" |
104 | twoFactorAuthentication_label: "Double authentification" | 105 | two_factor: |
105 | help_twoFactorAuthentication: "Si vous activez 2FA, à chaque tentative de connexion à wallabag, vous recevrez un code par email." | 106 | emailTwoFactor_label: 'En utlisant l’email (recevez un code par email)' |
107 | googleTwoFactor_label: 'En utilisant une application de mot de passe à usage unique (ouvrez l’app, comme Google Authenticator, Authy or FreeOTP, pour obtenir un mot de passe à usage unique)' | ||
108 | table_method: Méthode | ||
109 | table_state: État | ||
110 | table_action: Action | ||
111 | state_enabled: Activé | ||
112 | state_disabled: Désactivé | ||
113 | action_email: Utiliser l'email | ||
114 | action_app: Utiliser une app OTP | ||
106 | delete: | 115 | delete: |
107 | title: "Supprimer mon compte (attention danger !)" | 116 | title: "Supprimer mon compte (attention danger !)" |
108 | description: "Si vous confirmez la suppression de votre compte, TOUS les articles, TOUS les tags, TOUTES les annotations et votre compte seront DÉFINITIVEMENT supprimé (c’est IRRÉVERSIBLE). Vous serez ensuite déconnecté." | 117 | description: "Si vous confirmez la suppression de votre compte, TOUS les articles, TOUS les tags, TOUTES les annotations et votre compte seront DÉFINITIVEMENT supprimé (c’est IRRÉVERSIBLE). Vous serez ensuite déconnecté." |
@@ -160,6 +169,15 @@ config: | |||
160 | and: "Une règle ET l’autre" | 169 | and: "Une règle ET l’autre" |
161 | matches: "Teste si un <i>sujet</i> correspond à une <i>recherche</i> (non sensible à la casse).<br />Exemple : <code>title matches \"football\"</code>" | 170 | matches: "Teste si un <i>sujet</i> correspond à une <i>recherche</i> (non sensible à la casse).<br />Exemple : <code>title matches \"football\"</code>" |
162 | notmatches: "Teste si un <i>sujet</i> ne correspond pas à une <i>recherche</i> (non sensible à la casse).<br />Exemple : <code>title notmatches \"football\"</code>" | 171 | notmatches: "Teste si un <i>sujet</i> ne correspond pas à une <i>recherche</i> (non sensible à la casse).<br />Exemple : <code>title notmatches \"football\"</code>" |
172 | otp: | ||
173 | page_title: Authentification double-facteur | ||
174 | app: | ||
175 | two_factor_code_description_1: Vous venez d’activer l’authentification double-facteur, ouvrez votre application OTP pour configurer la génération du mot de passe à usage unique. Ces informations disparaîtront après un rechargement de la page. | ||
176 | two_factor_code_description_2: 'Vous pouvez scanner le QR code avec votre application :' | ||
177 | two_factor_code_description_3: 'N’oubliez pas de sauvegarder ces codes de secours dans un endroit sûr, vous pourrez les utiliser si vous ne pouvez plus accéder à votre application OTP :' | ||
178 | two_factor_code_description_4: 'Testez un code généré par votre application OTP :' | ||
179 | cancel: Annuler | ||
180 | enable: Activer | ||
163 | 181 | ||
164 | entry: | 182 | entry: |
165 | default_title: "Titre de l’article" | 183 | default_title: "Titre de l’article" |
@@ -533,6 +551,8 @@ user: | |||
533 | enabled_label: "Activé" | 551 | enabled_label: "Activé" |
534 | last_login_label: "Dernière connexion" | 552 | last_login_label: "Dernière connexion" |
535 | twofactor_label: "Double authentification" | 553 | twofactor_label: "Double authentification" |
554 | twofactor_email_label: Double authentification par email | ||
555 | twofactor_google_label: Double authentification par OTP app | ||
536 | save: "Sauvegarder" | 556 | save: "Sauvegarder" |
537 | delete: "Supprimer" | 557 | delete: "Supprimer" |
538 | delete_confirm: "Êtes-vous sûr ?" | 558 | delete_confirm: "Êtes-vous sûr ?" |
@@ -578,6 +598,7 @@ flashes: | |||
578 | tags_reset: "Tags supprimés" | 598 | tags_reset: "Tags supprimés" |
579 | entries_reset: "Articles supprimés" | 599 | entries_reset: "Articles supprimés" |
580 | archived_reset: "Articles archivés supprimés" | 600 | archived_reset: "Articles archivés supprimés" |
601 | otp_enabled: "Authentification à double-facteur activée" | ||
581 | entry: | 602 | entry: |
582 | notice: | 603 | notice: |
583 | entry_already_saved: "Article déjà sauvegardé le %date%" | 604 | entry_already_saved: "Article déjà sauvegardé le %date%" |
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.it.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.it.yml index 3a459445..274e5338 100644 --- a/src/Wallabag/CoreBundle/Resources/translations/messages.it.yml +++ b/src/Wallabag/CoreBundle/Resources/translations/messages.it.yml | |||
@@ -59,6 +59,7 @@ config: | |||
59 | password: 'Password' | 59 | password: 'Password' |
60 | rules: 'Regole di etichettatura' | 60 | rules: 'Regole di etichettatura' |
61 | new_user: 'Aggiungi utente' | 61 | new_user: 'Aggiungi utente' |
62 | reset: 'Area di reset' | ||
62 | form: | 63 | form: |
63 | save: 'Salva' | 64 | save: 'Salva' |
64 | form_settings: | 65 | form_settings: |
@@ -98,11 +99,18 @@ config: | |||
98 | # all: 'All' | 99 | # all: 'All' |
99 | rss_limit: 'Numero di elementi nel feed' | 100 | rss_limit: 'Numero di elementi nel feed' |
100 | form_user: | 101 | form_user: |
101 | two_factor_description: "Abilitando l'autenticazione a due fattori riceverai una e-mail con un codice per ogni nuova connesione non verificata" | 102 | # two_factor_description: "Enabling two factor authentication means you'll receive an email with a code OR need to use an OTP app (like Google Authenticator, Authy or FreeOTP) to get a one time code on every new untrusted connection. You can't choose both option." |
102 | name_label: 'Nome' | 103 | name_label: 'Nome' |
103 | email_label: 'E-mail' | 104 | email_label: 'E-mail' |
104 | twoFactorAuthentication_label: 'Autenticazione a due fattori' | 105 | # emailTwoFactor_label: 'Using email (receive a code by email)' |
105 | help_twoFactorAuthentication: "Se abiliti l'autenticazione a due fattori, ogni volta che vorrai connetterti a wallabag, riceverai un codice via E-mail." | 106 | # googleTwoFactor_label: 'Using an OTP app (open the app, like Google Authenticator, Authy or FreeOTP, to get a one time code)' |
107 | # table_method: Method | ||
108 | # table_state: State | ||
109 | # table_action: Action | ||
110 | # state_enabled: Enabled | ||
111 | # state_disabled: Disabled | ||
112 | # action_email: Use email | ||
113 | # action_app: Use OTP App | ||
106 | delete: | 114 | delete: |
107 | title: Cancella il mio account (zona pericolosa) | 115 | title: Cancella il mio account (zona pericolosa) |
108 | description: Rimuovendo il tuo account, TUTTI i tuoi articoli, TUTTE le tue etichette, TUTTE le tue annotazioni ed il tuo account verranno rimossi PERMANENTEMENTE (impossibile da ANNULLARE). Verrai poi disconnesso. | 116 | description: Rimuovendo il tuo account, TUTTI i tuoi articoli, TUTTE le tue etichette, TUTTE le tue annotazioni ed il tuo account verranno rimossi PERMANENTEMENTE (impossibile da ANNULLARE). Verrai poi disconnesso. |
@@ -160,6 +168,15 @@ config: | |||
160 | and: "Una regola E un'altra" | 168 | and: "Una regola E un'altra" |
161 | matches: 'Verifica che un <i>oggetto</i> risulti in una <i>ricerca</i> (case-insensitive).<br />Esempio: <code>titolo contiene "football"</code>' | 169 | matches: 'Verifica che un <i>oggetto</i> risulti in una <i>ricerca</i> (case-insensitive).<br />Esempio: <code>titolo contiene "football"</code>' |
162 | # notmatches: 'Tests that a <i>subject</i> doesn''t match match a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>' | 170 | # notmatches: 'Tests that a <i>subject</i> doesn''t match match a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>' |
171 | otp: | ||
172 | # page_title: Two-factor authentication | ||
173 | # app: | ||
174 | # two_factor_code_description_1: You just enabled the OTP two factor authentication, open your OTP app and use that code to get a one time password. It'll disapear after a page reload. | ||
175 | # two_factor_code_description_2: 'You can scan that QR Code with your app:' | ||
176 | # two_factor_code_description_3: 'Also, save these backup codes in a safe place, you can use them in case you lose access to your OTP app:' | ||
177 | # two_factor_code_description_4: 'Test an OTP code from your configured app:' | ||
178 | # cancel: Cancel | ||
179 | # enable: Enable | ||
163 | 180 | ||
164 | entry: | 181 | entry: |
165 | default_title: "Titolo del contenuto" | 182 | default_title: "Titolo del contenuto" |
@@ -532,7 +549,8 @@ user: | |||
532 | email_label: 'E-mail' | 549 | email_label: 'E-mail' |
533 | enabled_label: 'Abilitato' | 550 | enabled_label: 'Abilitato' |
534 | last_login_label: 'Ultima connessione' | 551 | last_login_label: 'Ultima connessione' |
535 | twofactor_label: Autenticazione a due fattori | 552 | # twofactor_email_label: Two factor authentication by email |
553 | # twofactor_google_label: Two factor authentication by OTP app | ||
536 | save: Salva | 554 | save: Salva |
537 | delete: Cancella | 555 | delete: Cancella |
538 | delete_confirm: Sei sicuro? | 556 | delete_confirm: Sei sicuro? |
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.oc.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.oc.yml index 9df9e645..4e5370f9 100644 --- a/src/Wallabag/CoreBundle/Resources/translations/messages.oc.yml +++ b/src/Wallabag/CoreBundle/Resources/translations/messages.oc.yml | |||
@@ -59,6 +59,7 @@ config: | |||
59 | password: 'Senhal' | 59 | password: 'Senhal' |
60 | rules: "Règlas d'etiquetas automaticas" | 60 | rules: "Règlas d'etiquetas automaticas" |
61 | new_user: 'Crear un compte' | 61 | new_user: 'Crear un compte' |
62 | reset: 'Zòna de reïnicializacion' | ||
62 | form: | 63 | form: |
63 | save: 'Enregistrar' | 64 | save: 'Enregistrar' |
64 | form_settings: | 65 | form_settings: |
@@ -98,11 +99,18 @@ config: | |||
98 | all: 'Totes' | 99 | all: 'Totes' |
99 | rss_limit: "Nombre d'articles dins un flux RSS" | 100 | rss_limit: "Nombre d'articles dins un flux RSS" |
100 | form_user: | 101 | form_user: |
101 | two_factor_description: "Activar l'autentificacion en dos temps vòl dire que recebretz un còdi per corrièl per cada novèla connexion pas aprovada." | 102 | # two_factor_description: "Enabling two factor authentication means you'll receive an email with a code OR need to use an OTP app (like Google Authenticator, Authy or FreeOTP) to get a one time code on every new untrusted connection. You can't choose both option." |
102 | name_label: 'Nom' | 103 | name_label: 'Nom' |
103 | email_label: 'Adreça de corrièl' | 104 | email_label: 'Adreça de corrièl' |
104 | twoFactorAuthentication_label: 'Dobla autentificacion' | 105 | # emailTwoFactor_label: 'Using email (receive a code by email)' |
105 | help_twoFactorAuthentication: "S'avètz activat l'autentificacion en dos temps, cada còp que volètz vos connectar a wallabag, recebretz un còdi per corrièl." | 106 | # googleTwoFactor_label: 'Using an OTP app (open the app, like Google Authenticator, Authy or FreeOTP, to get a one time code)' |
107 | # table_method: Method | ||
108 | # table_state: State | ||
109 | # table_action: Action | ||
110 | # state_enabled: Enabled | ||
111 | # state_disabled: Disabled | ||
112 | # action_email: Use email | ||
113 | # action_app: Use OTP App | ||
106 | delete: | 114 | delete: |
107 | title: Suprimir mon compte (Mèfi zòna perilhosa) | 115 | title: Suprimir mon compte (Mèfi zòna perilhosa) |
108 | description: Se confirmatz la supression de vòstre compte, TOTES vòstres articles, TOTAS vòstras etiquetas, TOTAS vòstras anotacions e vòstre compte seràn suprimits per totjorn. E aquò es IRREVERSIBLE. Puèi seretz desconnectat. | 116 | description: Se confirmatz la supression de vòstre compte, TOTES vòstres articles, TOTAS vòstras etiquetas, TOTAS vòstras anotacions e vòstre compte seràn suprimits per totjorn. E aquò es IRREVERSIBLE. Puèi seretz desconnectat. |
@@ -160,6 +168,15 @@ config: | |||
160 | and: "Una règla E l'autra" | 168 | and: "Una règla E l'autra" |
161 | matches: 'Teste se un <i>subjècte</i> correspond a una <i>recèrca</i> (non sensibla a la cassa).<br />Exemple : <code>title matches \"football\"</code>' | 169 | matches: 'Teste se un <i>subjècte</i> correspond a una <i>recèrca</i> (non sensibla a la cassa).<br />Exemple : <code>title matches \"football\"</code>' |
162 | notmatches: 'Teste se <i>subjècte</i> correspond pas a una <i>recèrca</i> (sensibla a la cassa).<br />Example : <code>title notmatches "football"</code>' | 170 | notmatches: 'Teste se <i>subjècte</i> correspond pas a una <i>recèrca</i> (sensibla a la cassa).<br />Example : <code>title notmatches "football"</code>' |
171 | otp: | ||
172 | # page_title: Two-factor authentication | ||
173 | # app: | ||
174 | # two_factor_code_description_1: You just enabled the OTP two factor authentication, open your OTP app and use that code to get a one time password. It'll disapear after a page reload. | ||
175 | # two_factor_code_description_2: 'You can scan that QR Code with your app:' | ||
176 | # two_factor_code_description_3: 'Also, save these backup codes in a safe place, you can use them in case you lose access to your OTP app:' | ||
177 | # two_factor_code_description_4: 'Test an OTP code from your configured app:' | ||
178 | # cancel: Cancel | ||
179 | # enable: Enable | ||
163 | 180 | ||
164 | entry: | 181 | entry: |
165 | default_title: "Títol de l'article" | 182 | default_title: "Títol de l'article" |
@@ -532,7 +549,8 @@ user: | |||
532 | email_label: 'Adreça de corrièl' | 549 | email_label: 'Adreça de corrièl' |
533 | enabled_label: 'Actiu' | 550 | enabled_label: 'Actiu' |
534 | last_login_label: 'Darrièra connexion' | 551 | last_login_label: 'Darrièra connexion' |
535 | twofactor_label: 'Autentificacion doble-factor' | 552 | # twofactor_email_label: Two factor authentication by email |
553 | # twofactor_google_label: Two factor authentication by OTP app | ||
536 | save: 'Enregistrar' | 554 | save: 'Enregistrar' |
537 | delete: 'Suprimir' | 555 | delete: 'Suprimir' |
538 | delete_confirm: 'Sètz segur ?' | 556 | delete_confirm: 'Sètz segur ?' |
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.pl.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.pl.yml index 684c40e2..a7a4d6c3 100644 --- a/src/Wallabag/CoreBundle/Resources/translations/messages.pl.yml +++ b/src/Wallabag/CoreBundle/Resources/translations/messages.pl.yml | |||
@@ -59,6 +59,7 @@ config: | |||
59 | password: 'Hasło' | 59 | password: 'Hasło' |
60 | rules: 'Zasady tagowania' | 60 | rules: 'Zasady tagowania' |
61 | new_user: 'Dodaj użytkownika' | 61 | new_user: 'Dodaj użytkownika' |
62 | reset: 'Reset' | ||
62 | form: | 63 | form: |
63 | save: 'Zapisz' | 64 | save: 'Zapisz' |
64 | form_settings: | 65 | form_settings: |
@@ -98,11 +99,18 @@ config: | |||
98 | all: 'Wszystkie' | 99 | all: 'Wszystkie' |
99 | rss_limit: 'Link do RSS' | 100 | rss_limit: 'Link do RSS' |
100 | form_user: | 101 | form_user: |
101 | two_factor_description: "Włączenie autoryzacji dwuetapowej oznacza, że będziesz otrzymywał maile z kodem przy każdym nowym, niezaufanym połączeniu" | 102 | # two_factor_description: "Enabling two factor authentication means you'll receive an email with a code OR need to use an OTP app (like Google Authenticator, Authy or FreeOTP) to get a one time code on every new untrusted connection. You can't choose both option." |
102 | name_label: 'Nazwa' | 103 | name_label: 'Nazwa' |
103 | email_label: 'Adres email' | 104 | email_label: 'Adres email' |
104 | twoFactorAuthentication_label: 'Autoryzacja dwuetapowa' | 105 | # emailTwoFactor_label: 'Using email (receive a code by email)' |
105 | help_twoFactorAuthentication: "Jeżeli włączysz autoryzację dwuetapową. Za każdym razem, kiedy będziesz chciał się zalogować, dostaniesz kod na swój e-mail." | 106 | # googleTwoFactor_label: 'Using an OTP app (open the app, like Google Authenticator, Authy or FreeOTP, to get a one time code)' |
107 | # table_method: Method | ||
108 | # table_state: State | ||
109 | # table_action: Action | ||
110 | # state_enabled: Enabled | ||
111 | # state_disabled: Disabled | ||
112 | # action_email: Use email | ||
113 | # action_app: Use OTP App | ||
106 | delete: | 114 | delete: |
107 | title: Usuń moje konto (niebezpieczna strefa !) | 115 | title: Usuń moje konto (niebezpieczna strefa !) |
108 | description: Jeżeli usuniesz swoje konto, wszystkie twoje artykuły, tagi, adnotacje, oraz konto zostaną trwale usunięte (operacja jest NIEODWRACALNA). Następnie zostaniesz wylogowany. | 116 | description: Jeżeli usuniesz swoje konto, wszystkie twoje artykuły, tagi, adnotacje, oraz konto zostaną trwale usunięte (operacja jest NIEODWRACALNA). Następnie zostaniesz wylogowany. |
@@ -160,6 +168,15 @@ config: | |||
160 | and: 'Jedna reguła I inna' | 168 | and: 'Jedna reguła I inna' |
161 | matches: 'Sprawdź czy <i>temat</i> pasuje <i>szukaj</i> (duże lub małe litery).<br />Przykład: <code>tytuł zawiera "piłka nożna"</code>' | 169 | matches: 'Sprawdź czy <i>temat</i> pasuje <i>szukaj</i> (duże lub małe litery).<br />Przykład: <code>tytuł zawiera "piłka nożna"</code>' |
162 | notmatches: 'Sprawdź czy <i>temat</i> nie zawiera <i>szukaj</i> (duże lub małe litery).<br />Przykład: <code>tytuł nie zawiera "piłka nożna"</code>' | 170 | notmatches: 'Sprawdź czy <i>temat</i> nie zawiera <i>szukaj</i> (duże lub małe litery).<br />Przykład: <code>tytuł nie zawiera "piłka nożna"</code>' |
171 | otp: | ||
172 | # page_title: Two-factor authentication | ||
173 | # app: | ||
174 | # two_factor_code_description_1: You just enabled the OTP two factor authentication, open your OTP app and use that code to get a one time password. It'll disapear after a page reload. | ||
175 | # two_factor_code_description_2: 'You can scan that QR Code with your app:' | ||
176 | # two_factor_code_description_3: 'Also, save these backup codes in a safe place, you can use them in case you lose access to your OTP app:' | ||
177 | # two_factor_code_description_4: 'Test an OTP code from your configured app:' | ||
178 | # cancel: Cancel | ||
179 | # enable: Enable | ||
163 | 180 | ||
164 | entry: | 181 | entry: |
165 | default_title: 'Tytuł wpisu' | 182 | default_title: 'Tytuł wpisu' |
@@ -532,7 +549,8 @@ user: | |||
532 | email_label: 'Adres email' | 549 | email_label: 'Adres email' |
533 | enabled_label: 'Włączony' | 550 | enabled_label: 'Włączony' |
534 | last_login_label: 'Ostatnie logowanie' | 551 | last_login_label: 'Ostatnie logowanie' |
535 | twofactor_label: Autoryzacja dwuetapowa | 552 | # twofactor_email_label: Two factor authentication by email |
553 | # twofactor_google_label: Two factor authentication by OTP app | ||
536 | save: Zapisz | 554 | save: Zapisz |
537 | delete: Usuń | 555 | delete: Usuń |
538 | delete_confirm: Jesteś pewien? | 556 | delete_confirm: Jesteś pewien? |
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.pt.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.pt.yml index 7932d7ab..a5483a6d 100644 --- a/src/Wallabag/CoreBundle/Resources/translations/messages.pt.yml +++ b/src/Wallabag/CoreBundle/Resources/translations/messages.pt.yml | |||
@@ -59,6 +59,7 @@ config: | |||
59 | password: 'Senha' | 59 | password: 'Senha' |
60 | rules: 'Regras de tags' | 60 | rules: 'Regras de tags' |
61 | new_user: 'Adicionar um usuário' | 61 | new_user: 'Adicionar um usuário' |
62 | # reset: 'Reset area' | ||
62 | form: | 63 | form: |
63 | save: 'Salvar' | 64 | save: 'Salvar' |
64 | form_settings: | 65 | form_settings: |
@@ -98,11 +99,18 @@ config: | |||
98 | # all: 'All' | 99 | # all: 'All' |
99 | rss_limit: 'Número de itens no feed' | 100 | rss_limit: 'Número de itens no feed' |
100 | form_user: | 101 | form_user: |
101 | two_factor_description: 'Habilitar autenticação de dois passos significa que você receberá um e-mail com um código a cada nova conexão desconhecida.' | 102 | # two_factor_description: "Enabling two factor authentication means you'll receive an email with a code OR need to use an OTP app (like Google Authenticator, Authy or FreeOTP) to get a one time code on every new untrusted connection. You can't choose both option." |
102 | name_label: 'Nome' | 103 | name_label: 'Nome' |
103 | email_label: 'E-mail' | 104 | email_label: 'E-mail' |
104 | twoFactorAuthentication_label: 'Autenticação de dois passos' | 105 | # emailTwoFactor_label: 'Using email (receive a code by email)' |
105 | # help_twoFactorAuthentication: "If you enable 2FA, each time you want to login to wallabag, you'll receive a code by email." | 106 | # googleTwoFactor_label: 'Using an OTP app (open the app, like Google Authenticator, Authy or FreeOTP, to get a one time code)' |
107 | # table_method: Method | ||
108 | # table_state: State | ||
109 | # table_action: Action | ||
110 | # state_enabled: Enabled | ||
111 | # state_disabled: Disabled | ||
112 | # action_email: Use email | ||
113 | # action_app: Use OTP App | ||
106 | delete: | 114 | delete: |
107 | # title: Delete my account (a.k.a danger zone) | 115 | # title: Delete my account (a.k.a danger zone) |
108 | # description: If you remove your account, ALL your articles, ALL your tags, ALL your annotations and your account will be PERMANENTLY removed (it can't be UNDONE). You'll then be logged out. | 116 | # description: If you remove your account, ALL your articles, ALL your tags, ALL your annotations and your account will be PERMANENTLY removed (it can't be UNDONE). You'll then be logged out. |
@@ -160,6 +168,15 @@ config: | |||
160 | and: 'Uma regra E outra' | 168 | and: 'Uma regra E outra' |
161 | matches: 'Testa que um <i>assunto</i> corresponde a uma <i>pesquisa</i> (maiúscula ou minúscula).<br />Exemplo: <code>título corresponde a "futebol"</code>' | 169 | matches: 'Testa que um <i>assunto</i> corresponde a uma <i>pesquisa</i> (maiúscula ou minúscula).<br />Exemplo: <code>título corresponde a "futebol"</code>' |
162 | # notmatches: 'Tests that a <i>subject</i> doesn''t match match a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>' | 170 | # notmatches: 'Tests that a <i>subject</i> doesn''t match match a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>' |
171 | otp: | ||
172 | # page_title: Two-factor authentication | ||
173 | # app: | ||
174 | # two_factor_code_description_1: You just enabled the OTP two factor authentication, open your OTP app and use that code to get a one time password. It'll disapear after a page reload. | ||
175 | # two_factor_code_description_2: 'You can scan that QR Code with your app:' | ||
176 | # two_factor_code_description_3: 'Also, save these backup codes in a safe place, you can use them in case you lose access to your OTP app:' | ||
177 | # two_factor_code_description_4: 'Test an OTP code from your configured app:' | ||
178 | # cancel: Cancel | ||
179 | # enable: Enable | ||
163 | 180 | ||
164 | entry: | 181 | entry: |
165 | default_title: 'Título da entrada' | 182 | default_title: 'Título da entrada' |
@@ -532,7 +549,8 @@ user: | |||
532 | email_label: 'E-mail' | 549 | email_label: 'E-mail' |
533 | enabled_label: 'Habilitado' | 550 | enabled_label: 'Habilitado' |
534 | last_login_label: 'Último login' | 551 | last_login_label: 'Último login' |
535 | twofactor_label: 'Autenticação de dois passos' | 552 | # twofactor_email_label: Two factor authentication by email |
553 | # twofactor_google_label: Two factor authentication by OTP app | ||
536 | save: 'Salvar' | 554 | save: 'Salvar' |
537 | delete: 'Apagar' | 555 | delete: 'Apagar' |
538 | delete_confirm: 'Tem certeza?' | 556 | delete_confirm: 'Tem certeza?' |
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.ro.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.ro.yml index 4d091f03..3b7fbd69 100644 --- a/src/Wallabag/CoreBundle/Resources/translations/messages.ro.yml +++ b/src/Wallabag/CoreBundle/Resources/translations/messages.ro.yml | |||
@@ -59,6 +59,7 @@ config: | |||
59 | password: 'Parolă' | 59 | password: 'Parolă' |
60 | # rules: 'Tagging rules' | 60 | # rules: 'Tagging rules' |
61 | new_user: 'Crează un utilizator' | 61 | new_user: 'Crează un utilizator' |
62 | # reset: 'Reset area' | ||
62 | form: | 63 | form: |
63 | save: 'Salvează' | 64 | save: 'Salvează' |
64 | form_settings: | 65 | form_settings: |
@@ -98,11 +99,18 @@ config: | |||
98 | # all: 'All' | 99 | # all: 'All' |
99 | rss_limit: 'Limită RSS' | 100 | rss_limit: 'Limită RSS' |
100 | form_user: | 101 | form_user: |
101 | # two_factor_description: "Enabling two factor authentication means you'll receive an email with a code on every new untrusted connexion" | 102 | # two_factor_description: "Enabling two factor authentication means you'll receive an email with a code OR need to use an OTP app (like Google Authenticator, Authy or FreeOTP) to get a one time code on every new untrusted connection. You can't choose both option." |
102 | name_label: 'Nume' | 103 | name_label: 'Nume' |
103 | email_label: 'E-mail' | 104 | email_label: 'E-mail' |
104 | # twoFactorAuthentication_label: 'Two factor authentication' | 105 | # emailTwoFactor_label: 'Using email (receive a code by email)' |
105 | # help_twoFactorAuthentication: "If you enable 2FA, each time you want to login to wallabag, you'll receive a code by email." | 106 | # googleTwoFactor_label: 'Using an OTP app (open the app, like Google Authenticator, Authy or FreeOTP, to get a one time code)' |
107 | # table_method: Method | ||
108 | # table_state: State | ||
109 | # table_action: Action | ||
110 | # state_enabled: Enabled | ||
111 | # state_disabled: Disabled | ||
112 | # action_email: Use email | ||
113 | # action_app: Use OTP App | ||
106 | delete: | 114 | delete: |
107 | # title: Delete my account (a.k.a danger zone) | 115 | # title: Delete my account (a.k.a danger zone) |
108 | # description: If you remove your account, ALL your articles, ALL your tags, ALL your annotations and your account will be PERMANENTLY removed (it can't be UNDONE). You'll then be logged out. | 116 | # description: If you remove your account, ALL your articles, ALL your tags, ALL your annotations and your account will be PERMANENTLY removed (it can't be UNDONE). You'll then be logged out. |
@@ -160,6 +168,15 @@ config: | |||
160 | # and: 'One rule AND another' | 168 | # and: 'One rule AND another' |
161 | # matches: 'Tests that a <i>subject</i> matches a <i>search</i> (case-insensitive).<br />Example: <code>title matches "football"</code>' | 169 | # matches: 'Tests that a <i>subject</i> matches a <i>search</i> (case-insensitive).<br />Example: <code>title matches "football"</code>' |
162 | # notmatches: 'Tests that a <i>subject</i> doesn''t match match a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>' | 170 | # notmatches: 'Tests that a <i>subject</i> doesn''t match match a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>' |
171 | otp: | ||
172 | # page_title: Two-factor authentication | ||
173 | # app: | ||
174 | # two_factor_code_description_1: You just enabled the OTP two factor authentication, open your OTP app and use that code to get a one time password. It'll disapear after a page reload. | ||
175 | # two_factor_code_description_2: 'You can scan that QR Code with your app:' | ||
176 | # two_factor_code_description_3: 'Also, save these backup codes in a safe place, you can use them in case you lose access to your OTP app:' | ||
177 | # two_factor_code_description_4: 'Test an OTP code from your configured app:' | ||
178 | # cancel: Cancel | ||
179 | # enable: Enable | ||
163 | 180 | ||
164 | entry: | 181 | entry: |
165 | # default_title: 'Title of the entry' | 182 | # default_title: 'Title of the entry' |
@@ -532,7 +549,8 @@ user: | |||
532 | email_label: 'E-mail' | 549 | email_label: 'E-mail' |
533 | # enabled_label: 'Enabled' | 550 | # enabled_label: 'Enabled' |
534 | # last_login_label: 'Last login' | 551 | # last_login_label: 'Last login' |
535 | # twofactor_label: Two factor authentication | 552 | # twofactor_email_label: Two factor authentication by email |
553 | # twofactor_google_label: Two factor authentication by OTP app | ||
536 | # save: Save | 554 | # save: Save |
537 | # delete: Delete | 555 | # delete: Delete |
538 | # delete_confirm: Are you sure? | 556 | # delete_confirm: Are you sure? |
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.ru.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.ru.yml index cc327ae4..92746631 100644 --- a/src/Wallabag/CoreBundle/Resources/translations/messages.ru.yml +++ b/src/Wallabag/CoreBundle/Resources/translations/messages.ru.yml | |||
@@ -58,6 +58,7 @@ config: | |||
58 | password: 'Пароль' | 58 | password: 'Пароль' |
59 | rules: 'Правила настройки простановки тегов' | 59 | rules: 'Правила настройки простановки тегов' |
60 | new_user: 'Добавить пользователя' | 60 | new_user: 'Добавить пользователя' |
61 | reset: 'Сброс данных' | ||
61 | form: | 62 | form: |
62 | save: 'Сохранить' | 63 | save: 'Сохранить' |
63 | form_settings: | 64 | form_settings: |
@@ -95,11 +96,18 @@ config: | |||
95 | archive: 'архивные' | 96 | archive: 'архивные' |
96 | rss_limit: 'Количество записей в фиде' | 97 | rss_limit: 'Количество записей в фиде' |
97 | form_user: | 98 | form_user: |
98 | two_factor_description: "Включить двухфакторную аутентификацию, Вы получите сообщение на указанный email с кодом, при каждом новом непроверенном подключении." | 99 | # two_factor_description: "Enabling two factor authentication means you'll receive an email with a code OR need to use an OTP app (like Google Authenticator, Authy or FreeOTP) to get a one time code on every new untrusted connection. You can't choose both option." |
99 | name_label: 'Имя' | 100 | name_label: 'Имя' |
100 | email_label: 'Email' | 101 | email_label: 'Email' |
101 | twoFactorAuthentication_label: 'Двухфакторная аутентификация' | 102 | # emailTwoFactor_label: 'Using email (receive a code by email)' |
102 | help_twoFactorAuthentication: "Если Вы включите двухфакторную аутентификацию, то Вы будете получать код на указанный ранее email, каждый раз при входе в wallabag." | 103 | # googleTwoFactor_label: 'Using an OTP app (open the app, like Google Authenticator, Authy or FreeOTP, to get a one time code)' |
104 | # table_method: Method | ||
105 | # table_state: State | ||
106 | # table_action: Action | ||
107 | # state_enabled: Enabled | ||
108 | # state_disabled: Disabled | ||
109 | # action_email: Use email | ||
110 | # action_app: Use OTP App | ||
103 | delete: | 111 | delete: |
104 | title: "Удалить мой аккаунт (или опасная зона)" | 112 | title: "Удалить мой аккаунт (или опасная зона)" |
105 | description: "Если Вы удалите ваш аккаунт, ВСЕ ваши записи, теги и другие данные, будут БЕЗВОЗВРАТНО удалены (операция не может быть отменена после). Затем Вы выйдете из системы." | 113 | description: "Если Вы удалите ваш аккаунт, ВСЕ ваши записи, теги и другие данные, будут БЕЗВОЗВРАТНО удалены (операция не может быть отменена после). Затем Вы выйдете из системы." |
@@ -155,6 +163,15 @@ config: | |||
155 | or: 'Одно правило ИЛИ другое' | 163 | or: 'Одно правило ИЛИ другое' |
156 | and: 'Одно правило И другое' | 164 | and: 'Одно правило И другое' |
157 | matches: 'Тесты, в которых <i> тема </i> соответствует <i> поиску </i> (без учета регистра). Пример: <code> title matches "футбол" </code>' | 165 | matches: 'Тесты, в которых <i> тема </i> соответствует <i> поиску </i> (без учета регистра). Пример: <code> title matches "футбол" </code>' |
166 | otp: | ||
167 | # page_title: Two-factor authentication | ||
168 | # app: | ||
169 | # two_factor_code_description_1: You just enabled the OTP two factor authentication, open your OTP app and use that code to get a one time password. It'll disapear after a page reload. | ||
170 | # two_factor_code_description_2: 'You can scan that QR Code with your app:' | ||
171 | # two_factor_code_description_3: 'Also, save these backup codes in a safe place, you can use them in case you lose access to your OTP app:' | ||
172 | # two_factor_code_description_4: 'Test an OTP code from your configured app:' | ||
173 | # cancel: Cancel | ||
174 | # enable: Enable | ||
158 | 175 | ||
159 | entry: | 176 | entry: |
160 | default_title: 'Название записи' | 177 | default_title: 'Название записи' |
@@ -520,7 +537,8 @@ user: | |||
520 | email_label: 'Email' | 537 | email_label: 'Email' |
521 | enabled_label: 'Включить' | 538 | enabled_label: 'Включить' |
522 | last_login_label: 'Последний вход' | 539 | last_login_label: 'Последний вход' |
523 | twofactor_label: "Двухфакторная аутентификация" | 540 | # twofactor_email_label: Two factor authentication by email |
541 | # twofactor_google_label: Two factor authentication by OTP app | ||
524 | save: "Сохранить" | 542 | save: "Сохранить" |
525 | delete: "Удалить" | 543 | delete: "Удалить" |
526 | delete_confirm: "Вы уверены?" | 544 | delete_confirm: "Вы уверены?" |
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.th.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.th.yml index 148aa541..1fe4fa0e 100644 --- a/src/Wallabag/CoreBundle/Resources/translations/messages.th.yml +++ b/src/Wallabag/CoreBundle/Resources/translations/messages.th.yml | |||
@@ -59,6 +59,7 @@ config: | |||
59 | password: 'รหัสผ่าน' | 59 | password: 'รหัสผ่าน' |
60 | rules: 'การแท็กข้อบังคับ' | 60 | rules: 'การแท็กข้อบังคับ' |
61 | new_user: 'เพิ่มผู้ใช้' | 61 | new_user: 'เพิ่มผู้ใช้' |
62 | reset: 'รีเซ็ตพื้นที่ ' | ||
62 | form: | 63 | form: |
63 | save: 'บันทึก' | 64 | save: 'บันทึก' |
64 | form_settings: | 65 | form_settings: |
@@ -98,11 +99,18 @@ config: | |||
98 | all: 'ทั้งหมด' | 99 | all: 'ทั้งหมด' |
99 | rss_limit: 'จำนวนไอเทมที่เก็บ' | 100 | rss_limit: 'จำนวนไอเทมที่เก็บ' |
100 | form_user: | 101 | form_user: |
101 | two_factor_description: "การเปิดใช้งาน two factor authentication คือคุณจะต้องได้รับอีเมลกับ code ที่ยังไม่ตรวจสอบในการเชื่อมต่อ" | 102 | # two_factor_description: "Enabling two factor authentication means you'll receive an email with a code OR need to use an OTP app (like Google Authenticator, Authy or FreeOTP) to get a one time code on every new untrusted connection. You can't choose both option." |
102 | name_label: 'ชื่อ' | 103 | name_label: 'ชื่อ' |
103 | email_label: 'อีเมล' | 104 | email_label: 'อีเมล' |
104 | twoFactorAuthentication_label: 'Two factor authentication' | 105 | # emailTwoFactor_label: 'Using email (receive a code by email)' |
105 | help_twoFactorAuthentication: "ถ้าคุณเปิด 2FA, ในแต่ละช่วงเวลาที่คุณต้องการลงชื่อเข้าใช wallabag, คุณจะต้องได้รับ code จากอีเมล" | 106 | # googleTwoFactor_label: 'Using an OTP app (open the app, like Google Authenticator, Authy or FreeOTP, to get a one time code)' |
107 | # table_method: Method | ||
108 | # table_state: State | ||
109 | # table_action: Action | ||
110 | # state_enabled: Enabled | ||
111 | # state_disabled: Disabled | ||
112 | # action_email: Use email | ||
113 | # action_app: Use OTP App | ||
106 | delete: | 114 | delete: |
107 | title: ลบบัญชีของฉัน (โซนที่เป็นภัย!) | 115 | title: ลบบัญชีของฉัน (โซนที่เป็นภัย!) |
108 | description: ถ้าคุณลบบัญชีของคุณIf , รายการทั้งหมดของคุณ, แท็กทั้งหมดของคุณ, หมายเหตุทั้งหมดของคุณและบัญชีของคุณจะถูกลบอย่างถาวร (มันไม่สามารถยกเลิกได้) คุณจะต้องลงชื่อออก | 116 | description: ถ้าคุณลบบัญชีของคุณIf , รายการทั้งหมดของคุณ, แท็กทั้งหมดของคุณ, หมายเหตุทั้งหมดของคุณและบัญชีของคุณจะถูกลบอย่างถาวร (มันไม่สามารถยกเลิกได้) คุณจะต้องลงชื่อออก |
@@ -160,6 +168,15 @@ config: | |||
160 | and: 'หนึ่งข้อบังคับและอื่นๆ' | 168 | and: 'หนึ่งข้อบังคับและอื่นๆ' |
161 | matches: 'ทดสอบว่า <i>เรื่อง</i> นี้ตรงกับ <i>การต้นหา</i> (กรณีไม่ทราบ).<br />ตัวอย่าง: <code>หัวข้อที่ตรงกับ "football"</code>' | 169 | matches: 'ทดสอบว่า <i>เรื่อง</i> นี้ตรงกับ <i>การต้นหา</i> (กรณีไม่ทราบ).<br />ตัวอย่าง: <code>หัวข้อที่ตรงกับ "football"</code>' |
162 | notmatches: 'ทดสอบว่า <i>เรื่อง</i> นี้ไม่ตรงกับ <i>การต้นหา</i> (กรณีไม่ทราบ).<br />ตัวอย่าง: <code>หัวข้อทีไม่ตรงกับ "football"</code>' | 170 | notmatches: 'ทดสอบว่า <i>เรื่อง</i> นี้ไม่ตรงกับ <i>การต้นหา</i> (กรณีไม่ทราบ).<br />ตัวอย่าง: <code>หัวข้อทีไม่ตรงกับ "football"</code>' |
171 | otp: | ||
172 | # page_title: Two-factor authentication | ||
173 | # app: | ||
174 | # two_factor_code_description_1: You just enabled the OTP two factor authentication, open your OTP app and use that code to get a one time password. It'll disapear after a page reload. | ||
175 | # two_factor_code_description_2: 'You can scan that QR Code with your app:' | ||
176 | # two_factor_code_description_3: 'Also, save these backup codes in a safe place, you can use them in case you lose access to your OTP app:' | ||
177 | # two_factor_code_description_4: 'Test an OTP code from your configured app:' | ||
178 | # cancel: Cancel | ||
179 | # enable: Enable | ||
163 | 180 | ||
164 | entry: | 181 | entry: |
165 | default_title: 'หัวข้อรายการ' | 182 | default_title: 'หัวข้อรายการ' |
@@ -530,7 +547,8 @@ user: | |||
530 | email_label: 'อีเมล' | 547 | email_label: 'อีเมล' |
531 | enabled_label: 'เปิดใช้งาน' | 548 | enabled_label: 'เปิดใช้งาน' |
532 | last_login_label: 'ลงชื้อเข้าใช้ครั้งสุดท้าย' | 549 | last_login_label: 'ลงชื้อเข้าใช้ครั้งสุดท้าย' |
533 | twofactor_label: Two factor authentication | 550 | # twofactor_email_label: Two factor authentication by email |
551 | # twofactor_google_label: Two factor authentication by OTP app | ||
534 | save: บันทึก | 552 | save: บันทึก |
535 | delete: ลบ | 553 | delete: ลบ |
536 | delete_confirm: ตุณแน่ใจหรือไม่? | 554 | delete_confirm: ตุณแน่ใจหรือไม่? |
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.tr.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.tr.yml index 6fb9852a..3b8a0d59 100644 --- a/src/Wallabag/CoreBundle/Resources/translations/messages.tr.yml +++ b/src/Wallabag/CoreBundle/Resources/translations/messages.tr.yml | |||
@@ -59,6 +59,7 @@ config: | |||
59 | password: 'Şifre' | 59 | password: 'Şifre' |
60 | rules: 'Etiketleme kuralları' | 60 | rules: 'Etiketleme kuralları' |
61 | new_user: 'Bir kullanıcı ekle' | 61 | new_user: 'Bir kullanıcı ekle' |
62 | # reset: 'Reset area' | ||
62 | form: | 63 | form: |
63 | save: 'Kaydet' | 64 | save: 'Kaydet' |
64 | form_settings: | 65 | form_settings: |
@@ -98,11 +99,18 @@ config: | |||
98 | # all: 'All' | 99 | # all: 'All' |
99 | rss_limit: 'RSS içeriğinden talep edilecek makale limiti' | 100 | rss_limit: 'RSS içeriğinden talep edilecek makale limiti' |
100 | form_user: | 101 | form_user: |
101 | two_factor_description: "İki adımlı doğrulamayı aktifleştirdiğinizde, her yeni güvenilmeyen bağlantılarda size e-posta ile bir kod alacaksınız." | 102 | # two_factor_description: "Enabling two factor authentication means you'll receive an email with a code OR need to use an OTP app (like Google Authenticator, Authy or FreeOTP) to get a one time code on every new untrusted connection. You can't choose both option." |
102 | name_label: 'İsim' | 103 | name_label: 'İsim' |
103 | email_label: 'E-posta' | 104 | email_label: 'E-posta' |
104 | twoFactorAuthentication_label: 'İki adımlı doğrulama' | 105 | # emailTwoFactor_label: 'Using email (receive a code by email)' |
105 | # help_twoFactorAuthentication: "If you enable 2FA, each time you want to login to wallabag, you'll receive a code by email." | 106 | # googleTwoFactor_label: 'Using an OTP app (open the app, like Google Authenticator, Authy or FreeOTP, to get a one time code)' |
107 | # table_method: Method | ||
108 | # table_state: State | ||
109 | # table_action: Action | ||
110 | # state_enabled: Enabled | ||
111 | # state_disabled: Disabled | ||
112 | # action_email: Use email | ||
113 | # action_app: Use OTP App | ||
106 | delete: | 114 | delete: |
107 | # title: Delete my account (a.k.a danger zone) | 115 | # title: Delete my account (a.k.a danger zone) |
108 | # description: If you remove your account, ALL your articles, ALL your tags, ALL your annotations and your account will be PERMANENTLY removed (it can't be UNDONE). You'll then be logged out. | 116 | # description: If you remove your account, ALL your articles, ALL your tags, ALL your annotations and your account will be PERMANENTLY removed (it can't be UNDONE). You'll then be logged out. |
@@ -160,6 +168,15 @@ config: | |||
160 | and: 'Bir kural ve diğeri' | 168 | and: 'Bir kural ve diğeri' |
161 | # matches: 'Tests that a <i>subject</i> matches a <i>search</i> (case-insensitive).<br />Example: <code>title matches "football"</code>' | 169 | # matches: 'Tests that a <i>subject</i> matches a <i>search</i> (case-insensitive).<br />Example: <code>title matches "football"</code>' |
162 | # notmatches: 'Tests that a <i>subject</i> doesn''t match match a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>' | 170 | # notmatches: 'Tests that a <i>subject</i> doesn''t match match a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>' |
171 | otp: | ||
172 | # page_title: Two-factor authentication | ||
173 | # app: | ||
174 | # two_factor_code_description_1: You just enabled the OTP two factor authentication, open your OTP app and use that code to get a one time password. It'll disapear after a page reload. | ||
175 | # two_factor_code_description_2: 'You can scan that QR Code with your app:' | ||
176 | # two_factor_code_description_3: 'Also, save these backup codes in a safe place, you can use them in case you lose access to your OTP app:' | ||
177 | # two_factor_code_description_4: 'Test an OTP code from your configured app:' | ||
178 | # cancel: Cancel | ||
179 | # enable: Enable | ||
163 | 180 | ||
164 | entry: | 181 | entry: |
165 | default_title: 'Makalenin başlığı' | 182 | default_title: 'Makalenin başlığı' |
@@ -530,7 +547,8 @@ user: | |||
530 | email_label: 'E-posta' | 547 | email_label: 'E-posta' |
531 | # enabled_label: 'Enabled' | 548 | # enabled_label: 'Enabled' |
532 | # last_login_label: 'Last login' | 549 | # last_login_label: 'Last login' |
533 | # twofactor_label: Two factor authentication | 550 | # twofactor_email_label: Two factor authentication by email |
551 | # twofactor_google_label: Two factor authentication by OTP app | ||
534 | # save: Save | 552 | # save: Save |
535 | # delete: Delete | 553 | # delete: Delete |
536 | # delete_confirm: Are you sure? | 554 | # delete_confirm: Are you sure? |
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Config/index.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Config/index.html.twig index bcc57dac..93f8ddf8 100644 --- a/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Config/index.html.twig +++ b/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Config/index.html.twig | |||
@@ -86,8 +86,7 @@ | |||
86 | <br/> | 86 | <br/> |
87 | <img id="androidQrcode" /> | 87 | <img id="androidQrcode" /> |
88 | <script> | 88 | <script> |
89 | const imgBase64 = jrQrcode.getQrBase64('wallabag://{{ app.user.username }}@{{ wallabag_url }}'); | 89 | document.getElementById('androidQrcode').src = jrQrcode.getQrBase64('wallabag://{{ app.user.username }}@{{ wallabag_url }}'); |
90 | document.getElementById('androidQrcode').src = imgBase64; | ||
91 | </script> | 90 | </script> |
92 | </div> | 91 | </div> |
93 | </fieldset> | 92 | </fieldset> |
@@ -169,52 +168,41 @@ | |||
169 | </div> | 168 | </div> |
170 | </fieldset> | 169 | </fieldset> |
171 | 170 | ||
171 | {{ form_widget(form.user.save) }} | ||
172 | |||
172 | {% if twofactor_auth %} | 173 | {% if twofactor_auth %} |
174 | <h5>{{ 'config.otp.page_title'|trans }}</h5> | ||
175 | |||
173 | <div class="row"> | 176 | <div class="row"> |
174 | {{ 'config.form_user.two_factor_description'|trans }} | 177 | {{ 'config.form_user.two_factor_description'|trans }} |
175 | </div> | 178 | </div> |
176 | 179 | ||
177 | <fieldset class="w500p inline"> | 180 | <table> |
178 | <div class="row"> | 181 | <thead> |
179 | {{ form_label(form.user.twoFactorAuthentication) }} | 182 | <tr> |
180 | {{ form_errors(form.user.twoFactorAuthentication) }} | 183 | <th>{{ 'config.form_user.two_factor.table_method'|trans }}</th> |
181 | {{ form_widget(form.user.twoFactorAuthentication) }} | 184 | <th>{{ 'config.form_user.two_factor.table_state'|trans }}</th> |
182 | </div> | 185 | <th>{{ 'config.form_user.two_factor.table_action'|trans }}</th> |
183 | <a href="#" title="{{ 'config.form_user.help_twoFactorAuthentication'|trans }}"> | 186 | </tr> |
184 | <i class="material-icons">live_help</i> | 187 | </thead> |
185 | </a> | ||
186 | </fieldset> | ||
187 | {% endif %} | ||
188 | 188 | ||
189 | <h2>{{ 'config.reset.title'|trans }}</h2> | 189 | <tbody> |
190 | <fieldset class="w500p inline"> | 190 | <tr> |
191 | <p>{{ 'config.reset.description'|trans }}</p> | 191 | <td>{{ 'config.form_user.two_factor.emailTwoFactor_label'|trans }}</td> |
192 | <ul> | 192 | <td>{% if app.user.isEmailTwoFactor %}<b>{{ 'config.form_user.two_factor.state_enabled'|trans }}</b>{% else %}{{ 'config.form_user.two_factor.state_disabled'|trans }}{% endif %}</td> |
193 | <li> | 193 | <td><a href="{{ path('config_otp_email') }}" class="waves-effect waves-light btn{% if app.user.isEmailTwoFactor %} disabled{% endif %}">{{ 'config.form_user.two_factor.action_email'|trans }}</a></td> |
194 | <a href="{{ path('config_reset', { type: 'annotations'}) }}" onclick="return confirm('{{ 'config.reset.confirm'|trans|escape('js') }}')" class="waves-effect waves-light btn red"> | 194 | </tr> |
195 | {{ 'config.reset.annotations'|trans }} | 195 | <tr> |
196 | </a> | 196 | <td>{{ 'config.form_user.two_factor.googleTwoFactor_label'|trans }}</td> |
197 | </li> | 197 | <td>{% if app.user.isGoogleTwoFactor %}<b>{{ 'config.form_user.two_factor.state_enabled'|trans }}</b>{% else %}{{ 'config.form_user.two_factor.state_disabled'|trans }}{% endif %}</td> |
198 | <li> | 198 | <td><a href="{{ path('config_otp_app') }}" class="waves-effect waves-light btn{% if app.user.isGoogleTwoFactor %} disabled{% endif %}">{{ 'config.form_user.two_factor.action_app'|trans }}</a></td> |
199 | <a href="{{ path('config_reset', { type: 'tags'}) }}" onclick="return confirm('{{ 'config.reset.confirm'|trans|escape('js') }}')" class="waves-effect waves-light btn red"> | 199 | </tr> |
200 | {{ 'config.reset.tags'|trans }} | 200 | </tbody> |
201 | </a> | 201 | </table> |
202 | </li> | 202 | |
203 | <li> | 203 | {% endif %} |
204 | <a href="{{ path('config_reset', { type: 'archived'}) }}" onclick="return confirm('{{ 'config.reset.confirm'|trans|escape('js') }}')" class="waves-effect waves-light btn red"> | ||
205 | {{ 'config.reset.archived'|trans }} | ||
206 | </a> | ||
207 | </li> | ||
208 | <li> | ||
209 | <a href="{{ path('config_reset', { type: 'entries'}) }}" onclick="return confirm('{{ 'config.reset.confirm'|trans|escape('js') }}')" class="waves-effect waves-light btn red"> | ||
210 | {{ 'config.reset.entries'|trans }} | ||
211 | </a> | ||
212 | </li> | ||
213 | </ul> | ||
214 | </fieldset> | ||
215 | 204 | ||
216 | {{ form_widget(form.user._token) }} | 205 | {{ form_widget(form.user._token) }} |
217 | {{ form_widget(form.user.save) }} | ||
218 | </form> | 206 | </form> |
219 | 207 | ||
220 | {% if enabled_users > 1 %} | 208 | {% if enabled_users > 1 %} |
@@ -277,7 +265,7 @@ | |||
277 | {% endfor %} | 265 | {% endfor %} |
278 | </ul> | 266 | </ul> |
279 | 267 | ||
280 | {{ form_start(form.new_tagging_rule) }} | 268 | {{ form_start(form.new_tagging_rule) }} |
281 | {{ form_errors(form.new_tagging_rule) }} | 269 | {{ form_errors(form.new_tagging_rule) }} |
282 | 270 | ||
283 | <fieldset class="w500p inline"> | 271 | <fieldset class="w500p inline"> |
@@ -382,4 +370,31 @@ | |||
382 | </table> | 370 | </table> |
383 | </div> | 371 | </div> |
384 | </div> | 372 | </div> |
373 | |||
374 | <h2>{{ 'config.reset.title'|trans }}</h2> | ||
375 | <fieldset class="w500p inline"> | ||
376 | <p>{{ 'config.reset.description'|trans }}</p> | ||
377 | <ul> | ||
378 | <li> | ||
379 | <a href="{{ path('config_reset', { type: 'annotations'}) }}" onclick="return confirm('{{ 'config.reset.confirm'|trans|escape('js') }}')" class="waves-effect waves-light btn red"> | ||
380 | {{ 'config.reset.annotations'|trans }} | ||
381 | </a> | ||
382 | </li> | ||
383 | <li> | ||
384 | <a href="{{ path('config_reset', { type: 'tags'}) }}" onclick="return confirm('{{ 'config.reset.confirm'|trans|escape('js') }}')" class="waves-effect waves-light btn red"> | ||
385 | {{ 'config.reset.tags'|trans }} | ||
386 | </a> | ||
387 | </li> | ||
388 | <li> | ||
389 | <a href="{{ path('config_reset', { type: 'archived'}) }}" onclick="return confirm('{{ 'config.reset.confirm'|trans|escape('js') }}')" class="waves-effect waves-light btn red"> | ||
390 | {{ 'config.reset.archived'|trans }} | ||
391 | </a> | ||
392 | </li> | ||
393 | <li> | ||
394 | <a href="{{ path('config_reset', { type: 'entries'}) }}" onclick="return confirm('{{ 'config.reset.confirm'|trans|escape('js') }}')" class="waves-effect waves-light btn red"> | ||
395 | {{ 'config.reset.entries'|trans }} | ||
396 | </a> | ||
397 | </li> | ||
398 | </ul> | ||
399 | </fieldset> | ||
385 | {% endblock %} | 400 | {% endblock %} |
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Config/otp_app.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Config/otp_app.html.twig new file mode 100644 index 00000000..0919646e --- /dev/null +++ b/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Config/otp_app.html.twig | |||
@@ -0,0 +1,55 @@ | |||
1 | {% extends "WallabagCoreBundle::layout.html.twig" %} | ||
2 | |||
3 | {% block title %}{{ 'config.page_title'|trans }} > {{ 'config.otp.page_title'|trans }}{% endblock %} | ||
4 | |||
5 | {% block content %} | ||
6 | <h5>{{ 'config.otp.page_title'|trans }}</h5> | ||
7 | |||
8 | <ol> | ||
9 | <li> | ||
10 | <p>{{ 'config.otp.app.two_factor_code_description_1'|trans }}</p> | ||
11 | <p>{{ 'config.otp.app.two_factor_code_description_2'|trans }}</p> | ||
12 | |||
13 | <p> | ||
14 | <img id="2faQrcode" class="hide-on-med-and-down" /> | ||
15 | <script> | ||
16 | document.getElementById('2faQrcode').src = jrQrcode.getQrBase64('{{ qr_code }}'); | ||
17 | </script> | ||
18 | </p> | ||
19 | </li> | ||
20 | <li> | ||
21 | <p>{{ 'config.otp.app.two_factor_code_description_3'|trans }}</p> | ||
22 | |||
23 | <p><strong>{{ backupCodes|join("\n")|nl2br }}</strong></p> | ||
24 | </li> | ||
25 | <li> | ||
26 | <p>{{ 'config.otp.app.two_factor_code_description_4'|trans }}</p> | ||
27 | |||
28 | {% for flashMessage in app.session.flashbag.get("two_factor") %} | ||
29 | <div class="card-panel red darken-1 black-text"> | ||
30 | {{ flashMessage|trans }} | ||
31 | </div> | ||
32 | {% endfor %} | ||
33 | |||
34 | <form class="form" action="{{ path("config_otp_app_check") }}" method="post"> | ||
35 | <div class="card-content"> | ||
36 | <div class="row"> | ||
37 | <div class="input-field col s12"> | ||
38 | <label for="_auth_code">{{ "scheb_two_factor.auth_code"|trans }}</label> | ||
39 | <input id="_auth_code" type="text" autocomplete="off" name="_auth_code" /> | ||
40 | </div> | ||
41 | </div> | ||
42 | </div> | ||
43 | <div class="card-action"> | ||
44 | <a href="{{ path('config_otp_app_cancel') }}" class="waves-effect waves-light grey btn"> | ||
45 | {{ 'config.otp.app.cancel'|trans }} | ||
46 | </a> | ||
47 | <button class="btn waves-effect waves-light" type="submit" name="send"> | ||
48 | {{ 'config.otp.app.enable'|trans }} | ||
49 | <i class="material-icons right">send</i> | ||
50 | </button> | ||
51 | </div> | ||
52 | </form> | ||
53 | </li> | ||
54 | </ol> | ||
55 | {% endblock %} | ||
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/material/Config/index.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/material/Config/index.html.twig index f896fe2d..412c18f4 100644 --- a/src/Wallabag/CoreBundle/Resources/views/themes/material/Config/index.html.twig +++ b/src/Wallabag/CoreBundle/Resources/views/themes/material/Config/index.html.twig | |||
@@ -16,6 +16,7 @@ | |||
16 | <li class="tab col s12 m6 l3"><a href="#set3">{{ 'config.tab_menu.user_info'|trans }}</a></li> | 16 | <li class="tab col s12 m6 l3"><a href="#set3">{{ 'config.tab_menu.user_info'|trans }}</a></li> |
17 | <li class="tab col s12 m6 l3"><a href="#set4">{{ 'config.tab_menu.password'|trans }}</a></li> | 17 | <li class="tab col s12 m6 l3"><a href="#set4">{{ 'config.tab_menu.password'|trans }}</a></li> |
18 | <li class="tab col s12 m6 l3"><a href="#set5">{{ 'config.tab_menu.rules'|trans }}</a></li> | 18 | <li class="tab col s12 m6 l3"><a href="#set5">{{ 'config.tab_menu.rules'|trans }}</a></li> |
19 | <li class="tab col s12 m6 l3"><a href="#set6">{{ 'config.tab_menu.reset'|trans }}</a></li> | ||
19 | </ul> | 20 | </ul> |
20 | </div> | 21 | </div> |
21 | 22 | ||
@@ -111,8 +112,7 @@ | |||
111 | <img id="androidQrcode" class="hide-on-med-and-down" /> | 112 | <img id="androidQrcode" class="hide-on-med-and-down" /> |
112 | </div> | 113 | </div> |
113 | <script> | 114 | <script> |
114 | const imgBase64 = jrQrcode.getQrBase64('wallabag://{{ app.user.username }}@{{ wallabag_url }}'); | 115 | document.getElementById('androidQrcode').src = jrQrcode.getQrBase64('wallabag://{{ app.user.username }}@{{ wallabag_url }}'); |
115 | document.getElementById('androidQrcode').src = imgBase64; | ||
116 | </script> | 116 | </script> |
117 | </div> | 117 | </div> |
118 | 118 | ||
@@ -196,59 +196,42 @@ | |||
196 | </div> | 196 | </div> |
197 | </div> | 197 | </div> |
198 | 198 | ||
199 | {% if twofactor_auth %} | 199 | {{ form_widget(form.user.save, {'attr': {'class': 'btn waves-effect waves-light'}}) }} |
200 | <div class="row"> | ||
201 | <div class="input-field col s11"> | ||
202 | {{ 'config.form_user.two_factor_description'|trans }} | ||
203 | |||
204 | <br /> | ||
205 | 200 | ||
206 | {{ form_widget(form.user.twoFactorAuthentication) }} | 201 | {% if twofactor_auth %} |
207 | {{ form_label(form.user.twoFactorAuthentication) }} | 202 | <br/> |
208 | {{ form_errors(form.user.twoFactorAuthentication) }} | 203 | <br/> |
209 | </div> | 204 | <div class="row"> |
210 | <div class="input-field col s1"> | 205 | <h5>{{ 'config.otp.page_title'|trans }}</h5> |
211 | <a href="#" class="tooltipped" data-position="left" data-delay="50" data-tooltip="{{ 'config.form_user.help_twoFactorAuthentication'|trans }}"> | 206 | |
212 | <i class="material-icons">live_help</i> | 207 | <p>{{ 'config.form_user.two_factor_description'|trans }}</p> |
213 | </a> | 208 | |
209 | <table> | ||
210 | <thead> | ||
211 | <tr> | ||
212 | <th>{{ 'config.form_user.two_factor.table_method'|trans }}</th> | ||
213 | <th>{{ 'config.form_user.two_factor.table_state'|trans }}</th> | ||
214 | <th>{{ 'config.form_user.two_factor.table_action'|trans }}</th> | ||
215 | </tr> | ||
216 | </thead> | ||
217 | |||
218 | <tbody> | ||
219 | <tr> | ||
220 | <td>{{ 'config.form_user.two_factor.emailTwoFactor_label'|trans }}</td> | ||
221 | <td>{% if app.user.isEmailTwoFactor %}<b>{{ 'config.form_user.two_factor.state_enabled'|trans }}</b>{% else %}{{ 'config.form_user.two_factor.state_disabled'|trans }}{% endif %}</td> | ||
222 | <td><a href="{{ path('config_otp_email') }}" class="waves-effect waves-light btn{% if app.user.isEmailTwoFactor %} disabled{% endif %}">{{ 'config.form_user.two_factor.action_email'|trans }}</a></td> | ||
223 | </tr> | ||
224 | <tr> | ||
225 | <td>{{ 'config.form_user.two_factor.googleTwoFactor_label'|trans }}</td> | ||
226 | <td>{% if app.user.isGoogleTwoFactor %}<b>{{ 'config.form_user.two_factor.state_enabled'|trans }}</b>{% else %}{{ 'config.form_user.two_factor.state_disabled'|trans }}{% endif %}</td> | ||
227 | <td><a href="{{ path('config_otp_app') }}" class="waves-effect waves-light btn{% if app.user.isGoogleTwoFactor %} disabled{% endif %}">{{ 'config.form_user.two_factor.action_app'|trans }}</a></td> | ||
228 | </tr> | ||
229 | </tbody> | ||
230 | </table> | ||
214 | </div> | 231 | </div> |
215 | </div> | ||
216 | {% endif %} | 232 | {% endif %} |
217 | |||
218 | {{ form_widget(form.user.save, {'attr': {'class': 'btn waves-effect waves-light'}}) }} | ||
219 | {{ form_widget(form.user._token) }} | 233 | {{ form_widget(form.user._token) }} |
220 | </form> | 234 | </form> |
221 | |||
222 | <br /><hr /><br /> | ||
223 | |||
224 | <div class="row"> | ||
225 | <h5>{{ 'config.reset.title'|trans }}</h5> | ||
226 | <p>{{ 'config.reset.description'|trans }}</p> | ||
227 | <a href="{{ path('config_reset', { type: 'annotations'}) }}" onclick="return confirm('{{ 'config.reset.confirm'|trans|escape('js') }}')" class="waves-effect waves-light btn red"> | ||
228 | {{ 'config.reset.annotations'|trans }} | ||
229 | </a> | ||
230 | <a href="{{ path('config_reset', { type: 'tags'}) }}" onclick="return confirm('{{ 'config.reset.confirm'|trans|escape('js') }}')" class="waves-effect waves-light btn red"> | ||
231 | {{ 'config.reset.tags'|trans }} | ||
232 | </a> | ||
233 | <a href="{{ path('config_reset', { type: 'archived'}) }}" onclick="return confirm('{{ 'config.reset.confirm'|trans|escape('js') }}')" class="waves-effect waves-light btn red"> | ||
234 | {{ 'config.reset.archived'|trans }} | ||
235 | </a> | ||
236 | <a href="{{ path('config_reset', { type: 'entries'}) }}" onclick="return confirm('{{ 'config.reset.confirm'|trans|escape('js') }}')" class="waves-effect waves-light btn red"> | ||
237 | {{ 'config.reset.entries'|trans }} | ||
238 | </a> | ||
239 | </div> | ||
240 | |||
241 | {% if enabled_users > 1 %} | ||
242 | <br /><hr /><br /> | ||
243 | |||
244 | <div class="row"> | ||
245 | <h5>{{ 'config.form_user.delete.title'|trans }}</h5> | ||
246 | <p>{{ 'config.form_user.delete.description'|trans }}</p> | ||
247 | <a href="{{ path('delete_account') }}" onclick="return confirm('{{ 'config.form_user.delete.confirm'|trans|escape('js') }}')" class="waves-effect waves-light btn red delete-account"> | ||
248 | {{ 'config.form_user.delete.button'|trans }} | ||
249 | </a> | ||
250 | </div> | ||
251 | {% endif %} | ||
252 | </div> | 235 | </div> |
253 | 236 | ||
254 | <div id="set4" class="col s12"> | 237 | <div id="set4" class="col s12"> |
@@ -422,6 +405,37 @@ | |||
422 | </div> | 405 | </div> |
423 | </div> | 406 | </div> |
424 | </div> | 407 | </div> |
408 | |||
409 | <div id="set6" class="col s12"> | ||
410 | <div class="row"> | ||
411 | <h5>{{ 'config.reset.title'|trans }}</h5> | ||
412 | <p>{{ 'config.reset.description'|trans }}</p> | ||
413 | <a href="{{ path('config_reset', { type: 'annotations'}) }}" onclick="return confirm('{{ 'config.reset.confirm'|trans|escape('js') }}')" class="waves-effect waves-light btn red"> | ||
414 | {{ 'config.reset.annotations'|trans }} | ||
415 | </a> | ||
416 | <a href="{{ path('config_reset', { type: 'tags'}) }}" onclick="return confirm('{{ 'config.reset.confirm'|trans|escape('js') }}')" class="waves-effect waves-light btn red"> | ||
417 | {{ 'config.reset.tags'|trans }} | ||
418 | </a> | ||
419 | <a href="{{ path('config_reset', { type: 'archived'}) }}" onclick="return confirm('{{ 'config.reset.confirm'|trans|escape('js') }}')" class="waves-effect waves-light btn red"> | ||
420 | {{ 'config.reset.archived'|trans }} | ||
421 | </a> | ||
422 | <a href="{{ path('config_reset', { type: 'entries'}) }}" onclick="return confirm('{{ 'config.reset.confirm'|trans|escape('js') }}')" class="waves-effect waves-light btn red"> | ||
423 | {{ 'config.reset.entries'|trans }} | ||
424 | </a> | ||
425 | </div> | ||
426 | |||
427 | {% if enabled_users > 1 %} | ||
428 | <br /><hr /><br /> | ||
429 | |||
430 | <div class="row"> | ||
431 | <h5>{{ 'config.form_user.delete.title'|trans }}</h5> | ||
432 | <p>{{ 'config.form_user.delete.description'|trans }}</p> | ||
433 | <a href="{{ path('delete_account') }}" onclick="return confirm('{{ 'config.form_user.delete.confirm'|trans|escape('js') }}')" class="waves-effect waves-light btn red delete-account"> | ||
434 | {{ 'config.form_user.delete.button'|trans }} | ||
435 | </a> | ||
436 | </div> | ||
437 | {% endif %} | ||
438 | </div> | ||
425 | </div> | 439 | </div> |
426 | 440 | ||
427 | </div> | 441 | </div> |
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/material/Config/otp_app.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/material/Config/otp_app.html.twig new file mode 100644 index 00000000..7875d787 --- /dev/null +++ b/src/Wallabag/CoreBundle/Resources/views/themes/material/Config/otp_app.html.twig | |||
@@ -0,0 +1,63 @@ | |||
1 | {% extends "WallabagCoreBundle::layout.html.twig" %} | ||
2 | |||
3 | {% block title %}{{ 'config.page_title'|trans }} > {{ 'config.otp.page_title'|trans }}{% endblock %} | ||
4 | |||
5 | {% block content %} | ||
6 | <div class="row"> | ||
7 | <div class="col s12"> | ||
8 | <div class="card-panel settings"> | ||
9 | <div class="row"> | ||
10 | <h5>{{ 'config.otp.page_title'|trans }}</h5> | ||
11 | |||
12 | <ol> | ||
13 | <li> | ||
14 | <p>{{ 'config.otp.app.two_factor_code_description_1'|trans }}</p> | ||
15 | <p>{{ 'config.otp.app.two_factor_code_description_2'|trans }}</p> | ||
16 | |||
17 | <p> | ||
18 | <img id="2faQrcode" class="hide-on-med-and-down" /> | ||
19 | <script> | ||
20 | document.getElementById('2faQrcode').src = jrQrcode.getQrBase64('{{ qr_code }}'); | ||
21 | </script> | ||
22 | </p> | ||
23 | </li> | ||
24 | <li> | ||
25 | <p>{{ 'config.otp.app.two_factor_code_description_3'|trans }}</p> | ||
26 | |||
27 | <p><strong>{{ backupCodes|join("\n")|nl2br }}</strong></p> | ||
28 | </li> | ||
29 | <li> | ||
30 | <p>{{ 'config.otp.app.two_factor_code_description_4'|trans }}</p> | ||
31 | |||
32 | {% for flashMessage in app.session.flashbag.get("two_factor") %} | ||
33 | <div class="card-panel red darken-1 black-text"> | ||
34 | {{ flashMessage|trans }} | ||
35 | </div> | ||
36 | {% endfor %} | ||
37 | |||
38 | <form class="form" action="{{ path("config_otp_app_check") }}" method="post"> | ||
39 | <div class="card-content"> | ||
40 | <div class="row"> | ||
41 | <div class="input-field col s12"> | ||
42 | <label for="_auth_code">{{ "scheb_two_factor.auth_code"|trans }}</label> | ||
43 | <input id="_auth_code" type="text" autocomplete="off" name="_auth_code" /> | ||
44 | </div> | ||
45 | </div> | ||
46 | </div> | ||
47 | <div class="card-action"> | ||
48 | <a href="{{ path('config_otp_app_cancel') }}" class="waves-effect waves-light grey btn"> | ||
49 | {{ 'config.otp.app.cancel'|trans }} | ||
50 | </a> | ||
51 | <button class="btn waves-effect waves-light" type="submit" name="send"> | ||
52 | {{ 'config.otp.app.enable'|trans }} | ||
53 | <i class="material-icons right">send</i> | ||
54 | </button> | ||
55 | </div> | ||
56 | </form> | ||
57 | </li> | ||
58 | </ol> | ||
59 | </div> | ||
60 | </div> | ||
61 | </div> | ||
62 | </div> | ||
63 | {% endblock %} | ||
diff --git a/src/Wallabag/UserBundle/Controller/ManageController.php b/src/Wallabag/UserBundle/Controller/ManageController.php index a9746fb4..63a06206 100644 --- a/src/Wallabag/UserBundle/Controller/ManageController.php +++ b/src/Wallabag/UserBundle/Controller/ManageController.php | |||
@@ -62,14 +62,29 @@ class ManageController extends Controller | |||
62 | */ | 62 | */ |
63 | public function editAction(Request $request, User $user) | 63 | public function editAction(Request $request, User $user) |
64 | { | 64 | { |
65 | $userManager = $this->container->get('fos_user.user_manager'); | ||
66 | |||
65 | $deleteForm = $this->createDeleteForm($user); | 67 | $deleteForm = $this->createDeleteForm($user); |
66 | $editForm = $this->createForm('Wallabag\UserBundle\Form\UserType', $user); | 68 | $form = $this->createForm('Wallabag\UserBundle\Form\UserType', $user); |
67 | $editForm->handleRequest($request); | 69 | $form->handleRequest($request); |
68 | 70 | ||
69 | if ($editForm->isSubmitted() && $editForm->isValid()) { | 71 | // `googleTwoFactor` isn't a field within the User entity, we need to define it's value in a different way |
70 | $em = $this->getDoctrine()->getManager(); | 72 | if ($this->getParameter('twofactor_auth') && true === $user->isGoogleAuthenticatorEnabled() && false === $form->isSubmitted()) { |
71 | $em->persist($user); | 73 | $form->get('googleTwoFactor')->setData(true); |
72 | $em->flush(); | 74 | } |
75 | |||
76 | if ($form->isSubmitted() && $form->isValid()) { | ||
77 | // handle creation / reset of the OTP secret if checkbox changed from the previous state | ||
78 | if ($this->getParameter('twofactor_auth')) { | ||
79 | if (true === $form->get('googleTwoFactor')->getData() && false === $user->isGoogleAuthenticatorEnabled()) { | ||
80 | $user->setGoogleAuthenticatorSecret($this->get('scheb_two_factor.security.google_authenticator')->generateSecret()); | ||
81 | $user->setEmailTwoFactor(false); | ||
82 | } elseif (false === $form->get('googleTwoFactor')->getData() && true === $user->isGoogleAuthenticatorEnabled()) { | ||
83 | $user->setGoogleAuthenticatorSecret(null); | ||
84 | } | ||
85 | } | ||
86 | |||
87 | $userManager->updateUser($user); | ||
73 | 88 | ||
74 | $this->get('session')->getFlashBag()->add( | 89 | $this->get('session')->getFlashBag()->add( |
75 | 'notice', | 90 | 'notice', |
@@ -81,7 +96,7 @@ class ManageController extends Controller | |||
81 | 96 | ||
82 | return $this->render('WallabagUserBundle:Manage:edit.html.twig', [ | 97 | return $this->render('WallabagUserBundle:Manage:edit.html.twig', [ |
83 | 'user' => $user, | 98 | 'user' => $user, |
84 | 'edit_form' => $editForm->createView(), | 99 | 'edit_form' => $form->createView(), |
85 | 'delete_form' => $deleteForm->createView(), | 100 | 'delete_form' => $deleteForm->createView(), |
86 | 'twofactor_auth' => $this->getParameter('twofactor_auth'), | 101 | 'twofactor_auth' => $this->getParameter('twofactor_auth'), |
87 | ]); | 102 | ]); |
@@ -131,8 +146,6 @@ class ManageController extends Controller | |||
131 | $form->handleRequest($request); | 146 | $form->handleRequest($request); |
132 | 147 | ||
133 | if ($form->isSubmitted() && $form->isValid()) { | 148 | if ($form->isSubmitted() && $form->isValid()) { |
134 | $this->get('logger')->info('searching users'); | ||
135 | |||
136 | $searchTerm = (isset($request->get('search_user')['term']) ? $request->get('search_user')['term'] : ''); | 149 | $searchTerm = (isset($request->get('search_user')['term']) ? $request->get('search_user')['term'] : ''); |
137 | 150 | ||
138 | $qb = $em->getRepository('WallabagUserBundle:User')->getQueryBuilderForSearch($searchTerm); | 151 | $qb = $em->getRepository('WallabagUserBundle:User')->getQueryBuilderForSearch($searchTerm); |
@@ -157,7 +170,7 @@ class ManageController extends Controller | |||
157 | } | 170 | } |
158 | 171 | ||
159 | /** | 172 | /** |
160 | * Creates a form to delete a User entity. | 173 | * Create a form to delete a User entity. |
161 | * | 174 | * |
162 | * @param User $user The User entity | 175 | * @param User $user The User entity |
163 | * | 176 | * |
diff --git a/src/Wallabag/UserBundle/Entity/User.php b/src/Wallabag/UserBundle/Entity/User.php index 48446e3c..43fa6a80 100644 --- a/src/Wallabag/UserBundle/Entity/User.php +++ b/src/Wallabag/UserBundle/Entity/User.php | |||
@@ -8,8 +8,9 @@ use FOS\UserBundle\Model\User as BaseUser; | |||
8 | use JMS\Serializer\Annotation\Accessor; | 8 | use JMS\Serializer\Annotation\Accessor; |
9 | use JMS\Serializer\Annotation\Groups; | 9 | use JMS\Serializer\Annotation\Groups; |
10 | use JMS\Serializer\Annotation\XmlRoot; | 10 | use JMS\Serializer\Annotation\XmlRoot; |
11 | use Scheb\TwoFactorBundle\Model\Email\TwoFactorInterface; | 11 | use Scheb\TwoFactorBundle\Model\BackupCodeInterface; |
12 | use Scheb\TwoFactorBundle\Model\TrustedComputerInterface; | 12 | use Scheb\TwoFactorBundle\Model\Email\TwoFactorInterface as EmailTwoFactorInterface; |
13 | use Scheb\TwoFactorBundle\Model\Google\TwoFactorInterface as GoogleTwoFactorInterface; | ||
13 | use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; | 14 | use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; |
14 | use Symfony\Component\Security\Core\User\UserInterface; | 15 | use Symfony\Component\Security\Core\User\UserInterface; |
15 | use Wallabag\ApiBundle\Entity\Client; | 16 | use Wallabag\ApiBundle\Entity\Client; |
@@ -28,7 +29,7 @@ use Wallabag\CoreBundle\Helper\EntityTimestampsTrait; | |||
28 | * @UniqueEntity("email") | 29 | * @UniqueEntity("email") |
29 | * @UniqueEntity("username") | 30 | * @UniqueEntity("username") |
30 | */ | 31 | */ |
31 | class User extends BaseUser implements TwoFactorInterface, TrustedComputerInterface | 32 | class User extends BaseUser implements EmailTwoFactorInterface, GoogleTwoFactorInterface, BackupCodeInterface |
32 | { | 33 | { |
33 | use EntityTimestampsTrait; | 34 | use EntityTimestampsTrait; |
34 | 35 | ||
@@ -123,16 +124,21 @@ class User extends BaseUser implements TwoFactorInterface, TrustedComputerInterf | |||
123 | private $authCode; | 124 | private $authCode; |
124 | 125 | ||
125 | /** | 126 | /** |
126 | * @var bool | 127 | * @ORM\Column(name="googleAuthenticatorSecret", type="string", nullable=true) |
127 | * | ||
128 | * @ORM\Column(type="boolean") | ||
129 | */ | 128 | */ |
130 | private $twoFactorAuthentication = false; | 129 | private $googleAuthenticatorSecret; |
131 | 130 | ||
132 | /** | 131 | /** |
133 | * @ORM\Column(type="json_array", nullable=true) | 132 | * @ORM\Column(type="json_array", nullable=true) |
134 | */ | 133 | */ |
135 | private $trusted; | 134 | private $backupCodes; |
135 | |||
136 | /** | ||
137 | * @var bool | ||
138 | * | ||
139 | * @ORM\Column(type="boolean") | ||
140 | */ | ||
141 | private $emailTwoFactor = false; | ||
136 | 142 | ||
137 | public function __construct() | 143 | public function __construct() |
138 | { | 144 | { |
@@ -233,49 +239,119 @@ class User extends BaseUser implements TwoFactorInterface, TrustedComputerInterf | |||
233 | /** | 239 | /** |
234 | * @return bool | 240 | * @return bool |
235 | */ | 241 | */ |
236 | public function isTwoFactorAuthentication() | 242 | public function isEmailTwoFactor() |
237 | { | 243 | { |
238 | return $this->twoFactorAuthentication; | 244 | return $this->emailTwoFactor; |
239 | } | 245 | } |
240 | 246 | ||
241 | /** | 247 | /** |
242 | * @param bool $twoFactorAuthentication | 248 | * @param bool $emailTwoFactor |
243 | */ | 249 | */ |
244 | public function setTwoFactorAuthentication($twoFactorAuthentication) | 250 | public function setEmailTwoFactor($emailTwoFactor) |
245 | { | 251 | { |
246 | $this->twoFactorAuthentication = $twoFactorAuthentication; | 252 | $this->emailTwoFactor = $emailTwoFactor; |
247 | } | 253 | } |
248 | 254 | ||
249 | public function isEmailAuthEnabled() | 255 | /** |
256 | * Used in the user config form to be "like" the email option. | ||
257 | */ | ||
258 | public function isGoogleTwoFactor() | ||
259 | { | ||
260 | return $this->isGoogleAuthenticatorEnabled(); | ||
261 | } | ||
262 | |||
263 | /** | ||
264 | * {@inheritdoc} | ||
265 | */ | ||
266 | public function isEmailAuthEnabled(): bool | ||
250 | { | 267 | { |
251 | return $this->twoFactorAuthentication; | 268 | return $this->emailTwoFactor; |
252 | } | 269 | } |
253 | 270 | ||
254 | public function getEmailAuthCode() | 271 | /** |
272 | * {@inheritdoc} | ||
273 | */ | ||
274 | public function getEmailAuthCode(): string | ||
255 | { | 275 | { |
256 | return $this->authCode; | 276 | return $this->authCode; |
257 | } | 277 | } |
258 | 278 | ||
259 | public function setEmailAuthCode($authCode) | 279 | /** |
280 | * {@inheritdoc} | ||
281 | */ | ||
282 | public function setEmailAuthCode(string $authCode): void | ||
260 | { | 283 | { |
261 | $this->authCode = $authCode; | 284 | $this->authCode = $authCode; |
262 | } | 285 | } |
263 | 286 | ||
264 | public function addTrustedComputer($token, \DateTime $validUntil) | 287 | /** |
288 | * {@inheritdoc} | ||
289 | */ | ||
290 | public function getEmailAuthRecipient(): string | ||
265 | { | 291 | { |
266 | $this->trusted[$token] = $validUntil->format('r'); | 292 | return $this->email; |
267 | } | 293 | } |
268 | 294 | ||
269 | public function isTrustedComputer($token) | 295 | /** |
296 | * {@inheritdoc} | ||
297 | */ | ||
298 | public function isGoogleAuthenticatorEnabled(): bool | ||
270 | { | 299 | { |
271 | if (isset($this->trusted[$token])) { | 300 | return $this->googleAuthenticatorSecret ? true : false; |
272 | $now = new \DateTime(); | 301 | } |
273 | $validUntil = new \DateTime($this->trusted[$token]); | ||
274 | 302 | ||
275 | return $now < $validUntil; | 303 | /** |
276 | } | 304 | * {@inheritdoc} |
305 | */ | ||
306 | public function getGoogleAuthenticatorUsername(): string | ||
307 | { | ||
308 | return $this->username; | ||
309 | } | ||
277 | 310 | ||
278 | return false; | 311 | /** |
312 | * {@inheritdoc} | ||
313 | */ | ||
314 | public function getGoogleAuthenticatorSecret(): string | ||
315 | { | ||
316 | return $this->googleAuthenticatorSecret; | ||
317 | } | ||
318 | |||
319 | /** | ||
320 | * {@inheritdoc} | ||
321 | */ | ||
322 | public function setGoogleAuthenticatorSecret(?string $googleAuthenticatorSecret): void | ||
323 | { | ||
324 | $this->googleAuthenticatorSecret = $googleAuthenticatorSecret; | ||
325 | } | ||
326 | |||
327 | public function setBackupCodes(array $codes = null) | ||
328 | { | ||
329 | $this->backupCodes = $codes; | ||
330 | } | ||
331 | |||
332 | public function getBackupCodes() | ||
333 | { | ||
334 | return $this->backupCodes; | ||
335 | } | ||
336 | |||
337 | /** | ||
338 | * {@inheritdoc} | ||
339 | */ | ||
340 | public function isBackupCode(string $code): bool | ||
341 | { | ||
342 | return false === $this->findBackupCode($code) ? false : true; | ||
343 | } | ||
344 | |||
345 | /** | ||
346 | * {@inheritdoc} | ||
347 | */ | ||
348 | public function invalidateBackupCode(string $code): void | ||
349 | { | ||
350 | $key = $this->findBackupCode($code); | ||
351 | |||
352 | if (false !== $key) { | ||
353 | unset($this->backupCodes[$key]); | ||
354 | } | ||
279 | } | 355 | } |
280 | 356 | ||
281 | /** | 357 | /** |
@@ -309,4 +385,24 @@ class User extends BaseUser implements TwoFactorInterface, TrustedComputerInterf | |||
309 | return $this->clients->first(); | 385 | return $this->clients->first(); |
310 | } | 386 | } |
311 | } | 387 | } |
388 | |||
389 | /** | ||
390 | * Try to find a backup code from the list of backup codes of the current user. | ||
391 | * | ||
392 | * @param string $code Given code from the user | ||
393 | * | ||
394 | * @return string|false | ||
395 | */ | ||
396 | private function findBackupCode(string $code) | ||
397 | { | ||
398 | foreach ($this->backupCodes as $key => $backupCode) { | ||
399 | // backup code are hashed using `password_hash` | ||
400 | // see ConfigController->otpAppAction | ||
401 | if (password_verify($code, $backupCode)) { | ||
402 | return $key; | ||
403 | } | ||
404 | } | ||
405 | |||
406 | return false; | ||
407 | } | ||
312 | } | 408 | } |
diff --git a/src/Wallabag/UserBundle/Form/UserType.php b/src/Wallabag/UserBundle/Form/UserType.php index 56fea640..026db9a2 100644 --- a/src/Wallabag/UserBundle/Form/UserType.php +++ b/src/Wallabag/UserBundle/Form/UserType.php | |||
@@ -35,9 +35,14 @@ class UserType extends AbstractType | |||
35 | 'required' => false, | 35 | 'required' => false, |
36 | 'label' => 'user.form.enabled_label', | 36 | 'label' => 'user.form.enabled_label', |
37 | ]) | 37 | ]) |
38 | ->add('twoFactorAuthentication', CheckboxType::class, [ | 38 | ->add('emailTwoFactor', CheckboxType::class, [ |
39 | 'required' => false, | 39 | 'required' => false, |
40 | 'label' => 'user.form.twofactor_label', | 40 | 'label' => 'user.form.twofactor_email_label', |
41 | ]) | ||
42 | ->add('googleTwoFactor', CheckboxType::class, [ | ||
43 | 'required' => false, | ||
44 | 'label' => 'user.form.twofactor_google_label', | ||
45 | 'mapped' => false, | ||
41 | ]) | 46 | ]) |
42 | ->add('save', SubmitType::class, [ | 47 | ->add('save', SubmitType::class, [ |
43 | 'label' => 'user.form.save', | 48 | 'label' => 'user.form.save', |
diff --git a/src/Wallabag/UserBundle/Mailer/AuthCodeMailer.php b/src/Wallabag/UserBundle/Mailer/AuthCodeMailer.php index aed805c9..2797efde 100644 --- a/src/Wallabag/UserBundle/Mailer/AuthCodeMailer.php +++ b/src/Wallabag/UserBundle/Mailer/AuthCodeMailer.php | |||
@@ -78,7 +78,7 @@ class AuthCodeMailer implements AuthCodeMailerInterface | |||
78 | * | 78 | * |
79 | * @param TwoFactorInterface $user | 79 | * @param TwoFactorInterface $user |
80 | */ | 80 | */ |
81 | public function sendAuthCode(TwoFactorInterface $user) | 81 | public function sendAuthCode(TwoFactorInterface $user): void |
82 | { | 82 | { |
83 | $template = $this->twig->loadTemplate('WallabagUserBundle:TwoFactor:email_auth_code.html.twig'); | 83 | $template = $this->twig->loadTemplate('WallabagUserBundle:TwoFactor:email_auth_code.html.twig'); |
84 | 84 | ||
@@ -97,7 +97,7 @@ class AuthCodeMailer implements AuthCodeMailerInterface | |||
97 | 97 | ||
98 | $message = new \Swift_Message(); | 98 | $message = new \Swift_Message(); |
99 | $message | 99 | $message |
100 | ->setTo($user->getEmail()) | 100 | ->setTo($user->getEmailAuthRecipient()) |
101 | ->setFrom($this->senderEmail, $this->senderName) | 101 | ->setFrom($this->senderEmail, $this->senderName) |
102 | ->setSubject($subject) | 102 | ->setSubject($subject) |
103 | ->setBody($bodyText, 'text/plain') | 103 | ->setBody($bodyText, 'text/plain') |
diff --git a/src/Wallabag/UserBundle/Resources/views/Authentication/form.html.twig b/src/Wallabag/UserBundle/Resources/views/Authentication/form.html.twig index c8471bdd..47a5cb78 100644 --- a/src/Wallabag/UserBundle/Resources/views/Authentication/form.html.twig +++ b/src/Wallabag/UserBundle/Resources/views/Authentication/form.html.twig | |||
@@ -1,7 +1,8 @@ | |||
1 | {# Override `vendor/scheb/two-factor-bundle/Resources/views/Authentication/form.html.twig` #} | ||
1 | {% extends "WallabagUserBundle::layout.html.twig" %} | 2 | {% extends "WallabagUserBundle::layout.html.twig" %} |
2 | 3 | ||
3 | {% block fos_user_content %} | 4 | {% block fos_user_content %} |
4 | <form class="form" action="" method="post"> | 5 | <form class="form" action="{{ path("2fa_login_check") }}" method="post"> |
5 | <div class="card-content"> | 6 | <div class="card-content"> |
6 | <div class="row"> | 7 | <div class="row"> |
7 | 8 | ||
@@ -9,14 +10,19 @@ | |||
9 | <p class="error">{{ flashMessage|trans }}</p> | 10 | <p class="error">{{ flashMessage|trans }}</p> |
10 | {% endfor %} | 11 | {% endfor %} |
11 | 12 | ||
13 | {# Authentication errors #} | ||
14 | {% if authenticationError %} | ||
15 | <p class="error">{{ authenticationError|trans(authenticationErrorData) }}</p> | ||
16 | {% endif %} | ||
17 | |||
12 | <div class="input-field col s12"> | 18 | <div class="input-field col s12"> |
13 | <label for="_auth_code">{{ "scheb_two_factor.auth_code"|trans }}</label> | 19 | <label for="_auth_code">{{ "scheb_two_factor.auth_code"|trans }}</label> |
14 | <input id="_auth_code" type="text" autocomplete="off" name="_auth_code" /> | 20 | <input id="_auth_code" type="text" autocomplete="off" name="{{ authCodeParameterName }}" /> |
15 | </div> | 21 | </div> |
16 | 22 | ||
17 | {% if useTrustedOption %} | 23 | {% if displayTrustedOption %} |
18 | <div class="input-field col s12"> | 24 | <div class="input-field col s12"> |
19 | <input id="_trusted" type="checkbox" name="_trusted" /> | 25 | <input id="_trusted" type="checkbox" name="{{ trustedParameterName }}" /> |
20 | <label for="_trusted">{{ "scheb_two_factor.trusted"|trans }}</label> | 26 | <label for="_trusted">{{ "scheb_two_factor.trusted"|trans }}</label> |
21 | </div> | 27 | </div> |
22 | {% endif %} | 28 | {% endif %} |
diff --git a/src/Wallabag/UserBundle/Resources/views/Manage/edit.html.twig b/src/Wallabag/UserBundle/Resources/views/Manage/edit.html.twig index 3ffd15f5..2de8f3a5 100644 --- a/src/Wallabag/UserBundle/Resources/views/Manage/edit.html.twig +++ b/src/Wallabag/UserBundle/Resources/views/Manage/edit.html.twig | |||
@@ -50,9 +50,14 @@ | |||
50 | {% if twofactor_auth %} | 50 | {% if twofactor_auth %} |
51 | <div class="row"> | 51 | <div class="row"> |
52 | <div class="input-field col s12"> | 52 | <div class="input-field col s12"> |
53 | {{ form_widget(edit_form.twoFactorAuthentication) }} | 53 | {{ form_widget(edit_form.emailTwoFactor) }} |
54 | {{ form_label(edit_form.twoFactorAuthentication) }} | 54 | {{ form_label(edit_form.emailTwoFactor) }} |
55 | {{ form_errors(edit_form.twoFactorAuthentication) }} | 55 | {{ form_errors(edit_form.emailTwoFactor) }} |
56 | </div> | ||
57 | <div class="input-field col s12"> | ||
58 | {{ form_widget(edit_form.googleTwoFactor) }} | ||
59 | {{ form_label(edit_form.googleTwoFactor) }} | ||
60 | {{ form_errors(edit_form.googleTwoFactor) }} | ||
56 | </div> | 61 | </div> |
57 | </div> | 62 | </div> |
58 | {% endif %} | 63 | {% endif %} |
diff --git a/tests/Wallabag/CoreBundle/Command/ShowUserCommandTest.php b/tests/Wallabag/CoreBundle/Command/ShowUserCommandTest.php index 9b34f2a0..ed383a2c 100644 --- a/tests/Wallabag/CoreBundle/Command/ShowUserCommandTest.php +++ b/tests/Wallabag/CoreBundle/Command/ShowUserCommandTest.php | |||
@@ -59,7 +59,8 @@ class ShowUserCommandTest extends WallabagCoreTestCase | |||
59 | $this->assertContains('Username: admin', $tester->getDisplay()); | 59 | $this->assertContains('Username: admin', $tester->getDisplay()); |
60 | $this->assertContains('Email: bigboss@wallabag.org', $tester->getDisplay()); | 60 | $this->assertContains('Email: bigboss@wallabag.org', $tester->getDisplay()); |
61 | $this->assertContains('Display name: Big boss', $tester->getDisplay()); | 61 | $this->assertContains('Display name: Big boss', $tester->getDisplay()); |
62 | $this->assertContains('2FA activated: no', $tester->getDisplay()); | 62 | $this->assertContains('2FA (email) activated', $tester->getDisplay()); |
63 | $this->assertContains('2FA (OTP) activated', $tester->getDisplay()); | ||
63 | } | 64 | } |
64 | 65 | ||
65 | public function testShowUser() | 66 | public function testShowUser() |
diff --git a/tests/Wallabag/CoreBundle/Controller/ConfigControllerTest.php b/tests/Wallabag/CoreBundle/Controller/ConfigControllerTest.php index c9dbbaa3..1090a686 100644 --- a/tests/Wallabag/CoreBundle/Controller/ConfigControllerTest.php +++ b/tests/Wallabag/CoreBundle/Controller/ConfigControllerTest.php | |||
@@ -1000,4 +1000,85 @@ class ConfigControllerTest extends WallabagCoreTestCase | |||
1000 | $this->assertNotSame('yuyuyuyu', $client->getRequest()->getLocale()); | 1000 | $this->assertNotSame('yuyuyuyu', $client->getRequest()->getLocale()); |
1001 | $this->assertNotSame('yuyuyuyu', $client->getContainer()->get('session')->get('_locale')); | 1001 | $this->assertNotSame('yuyuyuyu', $client->getContainer()->get('session')->get('_locale')); |
1002 | } | 1002 | } |
1003 | |||
1004 | public function testUserEnable2faEmail() | ||
1005 | { | ||
1006 | $this->logInAs('admin'); | ||
1007 | $client = $this->getClient(); | ||
1008 | |||
1009 | $crawler = $client->request('GET', '/config/otp/email'); | ||
1010 | |||
1011 | $this->assertSame(302, $client->getResponse()->getStatusCode()); | ||
1012 | |||
1013 | $crawler = $client->followRedirect(); | ||
1014 | |||
1015 | $this->assertGreaterThan(1, $alert = $crawler->filter('body')->extract(['_text'])); | ||
1016 | $this->assertContains('flashes.config.notice.otp_enabled', $alert[0]); | ||
1017 | |||
1018 | // restore user | ||
1019 | $em = $this->getEntityManager(); | ||
1020 | $user = $em | ||
1021 | ->getRepository('WallabagUserBundle:User') | ||
1022 | ->findOneByUsername('admin'); | ||
1023 | |||
1024 | $this->assertTrue($user->isEmailTwoFactor()); | ||
1025 | |||
1026 | $user->setEmailTwoFactor(false); | ||
1027 | $em->persist($user); | ||
1028 | $em->flush(); | ||
1029 | } | ||
1030 | |||
1031 | public function testUserEnable2faGoogle() | ||
1032 | { | ||
1033 | $this->logInAs('admin'); | ||
1034 | $client = $this->getClient(); | ||
1035 | |||
1036 | $crawler = $client->request('GET', '/config/otp/app'); | ||
1037 | |||
1038 | $this->assertSame(200, $client->getResponse()->getStatusCode()); | ||
1039 | |||
1040 | // restore user | ||
1041 | $em = $this->getEntityManager(); | ||
1042 | $user = $em | ||
1043 | ->getRepository('WallabagUserBundle:User') | ||
1044 | ->findOneByUsername('admin'); | ||
1045 | |||
1046 | $this->assertTrue($user->isGoogleTwoFactor()); | ||
1047 | $this->assertGreaterThan(0, $user->getBackupCodes()); | ||
1048 | |||
1049 | $user->setGoogleAuthenticatorSecret(false); | ||
1050 | $user->setBackupCodes(null); | ||
1051 | $em->persist($user); | ||
1052 | $em->flush(); | ||
1053 | } | ||
1054 | |||
1055 | public function testUserEnable2faGoogleCancel() | ||
1056 | { | ||
1057 | $this->logInAs('admin'); | ||
1058 | $client = $this->getClient(); | ||
1059 | |||
1060 | $crawler = $client->request('GET', '/config/otp/app'); | ||
1061 | |||
1062 | $this->assertSame(200, $client->getResponse()->getStatusCode()); | ||
1063 | |||
1064 | // restore user | ||
1065 | $em = $this->getEntityManager(); | ||
1066 | $user = $em | ||
1067 | ->getRepository('WallabagUserBundle:User') | ||
1068 | ->findOneByUsername('admin'); | ||
1069 | |||
1070 | $this->assertTrue($user->isGoogleTwoFactor()); | ||
1071 | $this->assertGreaterThan(0, $user->getBackupCodes()); | ||
1072 | |||
1073 | $crawler = $client->request('GET', '/config/otp/app/cancel'); | ||
1074 | |||
1075 | $this->assertSame(302, $client->getResponse()->getStatusCode()); | ||
1076 | |||
1077 | $user = $em | ||
1078 | ->getRepository('WallabagUserBundle:User') | ||
1079 | ->findOneByUsername('admin'); | ||
1080 | |||
1081 | $this->assertFalse($user->isGoogleTwoFactor()); | ||
1082 | $this->assertEmpty($user->getBackupCodes()); | ||
1083 | } | ||
1003 | } | 1084 | } |
diff --git a/tests/Wallabag/CoreBundle/Controller/SecurityControllerTest.php b/tests/Wallabag/CoreBundle/Controller/SecurityControllerTest.php index 395208a2..b03c7550 100644 --- a/tests/Wallabag/CoreBundle/Controller/SecurityControllerTest.php +++ b/tests/Wallabag/CoreBundle/Controller/SecurityControllerTest.php | |||
@@ -26,7 +26,7 @@ class SecurityControllerTest extends WallabagCoreTestCase | |||
26 | $this->assertContains('config.form_rss.description', $crawler->filter('body')->extract(['_text'])[0]); | 26 | $this->assertContains('config.form_rss.description', $crawler->filter('body')->extract(['_text'])[0]); |
27 | } | 27 | } |
28 | 28 | ||
29 | public function testLoginWith2Factor() | 29 | public function testLoginWith2FactorEmail() |
30 | { | 30 | { |
31 | $client = $this->getClient(); | 31 | $client = $this->getClient(); |
32 | 32 | ||
@@ -42,7 +42,7 @@ class SecurityControllerTest extends WallabagCoreTestCase | |||
42 | $user = $em | 42 | $user = $em |
43 | ->getRepository('WallabagUserBundle:User') | 43 | ->getRepository('WallabagUserBundle:User') |
44 | ->findOneByUsername('admin'); | 44 | ->findOneByUsername('admin'); |
45 | $user->setTwoFactorAuthentication(true); | 45 | $user->setEmailTwoFactor(true); |
46 | $em->persist($user); | 46 | $em->persist($user); |
47 | $em->flush(); | 47 | $em->flush(); |
48 | 48 | ||
@@ -54,12 +54,12 @@ class SecurityControllerTest extends WallabagCoreTestCase | |||
54 | $user = $em | 54 | $user = $em |
55 | ->getRepository('WallabagUserBundle:User') | 55 | ->getRepository('WallabagUserBundle:User') |
56 | ->findOneByUsername('admin'); | 56 | ->findOneByUsername('admin'); |
57 | $user->setTwoFactorAuthentication(false); | 57 | $user->setEmailTwoFactor(false); |
58 | $em->persist($user); | 58 | $em->persist($user); |
59 | $em->flush(); | 59 | $em->flush(); |
60 | } | 60 | } |
61 | 61 | ||
62 | public function testTrustedComputer() | 62 | public function testLoginWith2FactorGoogle() |
63 | { | 63 | { |
64 | $client = $this->getClient(); | 64 | $client = $this->getClient(); |
65 | 65 | ||
@@ -69,15 +69,27 @@ class SecurityControllerTest extends WallabagCoreTestCase | |||
69 | return; | 69 | return; |
70 | } | 70 | } |
71 | 71 | ||
72 | $client->followRedirects(); | ||
73 | |||
72 | $em = $client->getContainer()->get('doctrine.orm.entity_manager'); | 74 | $em = $client->getContainer()->get('doctrine.orm.entity_manager'); |
73 | $user = $em | 75 | $user = $em |
74 | ->getRepository('WallabagUserBundle:User') | 76 | ->getRepository('WallabagUserBundle:User') |
75 | ->findOneByUsername('admin'); | 77 | ->findOneByUsername('admin'); |
78 | $user->setGoogleAuthenticatorSecret('26LDIHYGHNELOQEM'); | ||
79 | $em->persist($user); | ||
80 | $em->flush(); | ||
81 | |||
82 | $this->logInAsUsingHttp('admin'); | ||
83 | $crawler = $client->request('GET', '/config'); | ||
84 | $this->assertContains('scheb_two_factor.trusted', $crawler->filter('body')->extract(['_text'])[0]); | ||
76 | 85 | ||
77 | $date = new \DateTime(); | 86 | // restore user |
78 | $user->addTrustedComputer('ABCDEF', $date->add(new \DateInterval('P1M'))); | 87 | $user = $em |
79 | $this->assertTrue($user->isTrustedComputer('ABCDEF')); | 88 | ->getRepository('WallabagUserBundle:User') |
80 | $this->assertFalse($user->isTrustedComputer('FEDCBA')); | 89 | ->findOneByUsername('admin'); |
90 | $user->setGoogleAuthenticatorSecret(null); | ||
91 | $em->persist($user); | ||
92 | $em->flush(); | ||
81 | } | 93 | } |
82 | 94 | ||
83 | public function testEnabledRegistration() | 95 | public function testEnabledRegistration() |
diff --git a/tests/Wallabag/CoreBundle/Helper/ContentProxyTest.php b/tests/Wallabag/CoreBundle/Helper/ContentProxyTest.php index 3dd9273c..508adb1b 100644 --- a/tests/Wallabag/CoreBundle/Helper/ContentProxyTest.php +++ b/tests/Wallabag/CoreBundle/Helper/ContentProxyTest.php | |||
@@ -163,7 +163,7 @@ class ContentProxyTest extends TestCase | |||
163 | 163 | ||
164 | $this->assertSame('http://1.1.1.1', $entry->getUrl()); | 164 | $this->assertSame('http://1.1.1.1', $entry->getUrl()); |
165 | $this->assertSame('this is my title', $entry->getTitle()); | 165 | $this->assertSame('this is my title', $entry->getTitle()); |
166 | $this->assertContains('this is my content', $entry->getContent()); | 166 | $this->assertContains('content', $entry->getContent()); |
167 | $this->assertSame('http://3.3.3.3/cover.jpg', $entry->getPreviewPicture()); | 167 | $this->assertSame('http://3.3.3.3/cover.jpg', $entry->getPreviewPicture()); |
168 | $this->assertSame('text/html', $entry->getMimetype()); | 168 | $this->assertSame('text/html', $entry->getMimetype()); |
169 | $this->assertSame('fr', $entry->getLanguage()); | 169 | $this->assertSame('fr', $entry->getLanguage()); |
@@ -205,7 +205,7 @@ class ContentProxyTest extends TestCase | |||
205 | 205 | ||
206 | $this->assertSame('http://1.1.1.1', $entry->getUrl()); | 206 | $this->assertSame('http://1.1.1.1', $entry->getUrl()); |
207 | $this->assertSame('this is my title', $entry->getTitle()); | 207 | $this->assertSame('this is my title', $entry->getTitle()); |
208 | $this->assertContains('this is my content', $entry->getContent()); | 208 | $this->assertContains('content', $entry->getContent()); |
209 | $this->assertNull($entry->getPreviewPicture()); | 209 | $this->assertNull($entry->getPreviewPicture()); |
210 | $this->assertSame('text/html', $entry->getMimetype()); | 210 | $this->assertSame('text/html', $entry->getMimetype()); |
211 | $this->assertSame('fr', $entry->getLanguage()); | 211 | $this->assertSame('fr', $entry->getLanguage()); |
@@ -247,7 +247,7 @@ class ContentProxyTest extends TestCase | |||
247 | 247 | ||
248 | $this->assertSame('http://1.1.1.1', $entry->getUrl()); | 248 | $this->assertSame('http://1.1.1.1', $entry->getUrl()); |
249 | $this->assertSame('this is my title', $entry->getTitle()); | 249 | $this->assertSame('this is my title', $entry->getTitle()); |
250 | $this->assertContains('this is my content', $entry->getContent()); | 250 | $this->assertContains('content', $entry->getContent()); |
251 | $this->assertSame('text/html', $entry->getMimetype()); | 251 | $this->assertSame('text/html', $entry->getMimetype()); |
252 | $this->assertNull($entry->getLanguage()); | 252 | $this->assertNull($entry->getLanguage()); |
253 | $this->assertSame('200', $entry->getHttpStatus()); | 253 | $this->assertSame('200', $entry->getHttpStatus()); |
@@ -296,7 +296,7 @@ class ContentProxyTest extends TestCase | |||
296 | 296 | ||
297 | $this->assertSame('http://1.1.1.1', $entry->getUrl()); | 297 | $this->assertSame('http://1.1.1.1', $entry->getUrl()); |
298 | $this->assertSame('this is my title', $entry->getTitle()); | 298 | $this->assertSame('this is my title', $entry->getTitle()); |
299 | $this->assertContains('this is my content', $entry->getContent()); | 299 | $this->assertContains('content', $entry->getContent()); |
300 | $this->assertNull($entry->getPreviewPicture()); | 300 | $this->assertNull($entry->getPreviewPicture()); |
301 | $this->assertSame('text/html', $entry->getMimetype()); | 301 | $this->assertSame('text/html', $entry->getMimetype()); |
302 | $this->assertSame('fr', $entry->getLanguage()); | 302 | $this->assertSame('fr', $entry->getLanguage()); |
@@ -332,7 +332,7 @@ class ContentProxyTest extends TestCase | |||
332 | 332 | ||
333 | $this->assertSame('http://1.1.1.1', $entry->getUrl()); | 333 | $this->assertSame('http://1.1.1.1', $entry->getUrl()); |
334 | $this->assertSame('this is my title', $entry->getTitle()); | 334 | $this->assertSame('this is my title', $entry->getTitle()); |
335 | $this->assertContains('this is my content', $entry->getContent()); | 335 | $this->assertContains('content', $entry->getContent()); |
336 | $this->assertSame('text/html', $entry->getMimetype()); | 336 | $this->assertSame('text/html', $entry->getMimetype()); |
337 | $this->assertSame('fr', $entry->getLanguage()); | 337 | $this->assertSame('fr', $entry->getLanguage()); |
338 | $this->assertSame(4.0, $entry->getReadingTime()); | 338 | $this->assertSame(4.0, $entry->getReadingTime()); |
@@ -371,7 +371,7 @@ class ContentProxyTest extends TestCase | |||
371 | 371 | ||
372 | $this->assertSame('http://1.1.1.1', $entry->getUrl()); | 372 | $this->assertSame('http://1.1.1.1', $entry->getUrl()); |
373 | $this->assertSame('this is my title', $entry->getTitle()); | 373 | $this->assertSame('this is my title', $entry->getTitle()); |
374 | $this->assertContains('this is my content', $entry->getContent()); | 374 | $this->assertContains('content', $entry->getContent()); |
375 | $this->assertSame('text/html', $entry->getMimetype()); | 375 | $this->assertSame('text/html', $entry->getMimetype()); |
376 | $this->assertSame('fr', $entry->getLanguage()); | 376 | $this->assertSame('fr', $entry->getLanguage()); |
377 | $this->assertSame(4.0, $entry->getReadingTime()); | 377 | $this->assertSame(4.0, $entry->getReadingTime()); |
@@ -406,7 +406,7 @@ class ContentProxyTest extends TestCase | |||
406 | 406 | ||
407 | $this->assertSame('http://1.1.1.1', $entry->getUrl()); | 407 | $this->assertSame('http://1.1.1.1', $entry->getUrl()); |
408 | $this->assertSame('this is my title', $entry->getTitle()); | 408 | $this->assertSame('this is my title', $entry->getTitle()); |
409 | $this->assertContains('this is my content', $entry->getContent()); | 409 | $this->assertContains('content', $entry->getContent()); |
410 | $this->assertSame('text/html', $entry->getMimetype()); | 410 | $this->assertSame('text/html', $entry->getMimetype()); |
411 | $this->assertSame('fr', $entry->getLanguage()); | 411 | $this->assertSame('fr', $entry->getLanguage()); |
412 | $this->assertSame(4.0, $entry->getReadingTime()); | 412 | $this->assertSame(4.0, $entry->getReadingTime()); |
diff --git a/tests/Wallabag/UserBundle/Mailer/AuthCodeMailerTest.php b/tests/Wallabag/UserBundle/Mailer/AuthCodeMailerTest.php index e34e13a8..1713c10c 100644 --- a/tests/Wallabag/UserBundle/Mailer/AuthCodeMailerTest.php +++ b/tests/Wallabag/UserBundle/Mailer/AuthCodeMailerTest.php | |||
@@ -33,7 +33,7 @@ TWIG; | |||
33 | public function testSendEmail() | 33 | public function testSendEmail() |
34 | { | 34 | { |
35 | $user = new User(); | 35 | $user = new User(); |
36 | $user->setTwoFactorAuthentication(true); | 36 | $user->setEmailTwoFactor(true); |
37 | $user->setEmailAuthCode(666666); | 37 | $user->setEmailAuthCode(666666); |
38 | $user->setEmail('test@wallabag.io'); | 38 | $user->setEmail('test@wallabag.io'); |
39 | $user->setName('Bob'); | 39 | $user->setName('Bob'); |