diff options
Diffstat (limited to 'app')
-rw-r--r-- | app/DoctrineMigrations/Version20181202073750.php | 76 | ||||
-rw-r--r-- | app/Resources/static/themes/_global/index.js | 18 | ||||
-rwxr-xr-x | app/Resources/static/themes/material/index.js | 5 | ||||
-rw-r--r-- | app/config/config.yml | 11 | ||||
-rw-r--r-- | app/config/routing.yml | 8 | ||||
-rw-r--r-- | app/config/security.yml | 9 |
6 files changed, 125 insertions, 2 deletions
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 } |