From a5a4ad7b6bd99e57b31d9ec64712af1dea072de1 Mon Sep 17 00:00:00 2001 From: Kuba Mikita Date: Thu, 6 Feb 2020 10:55:03 +0100 Subject: [PATCH 01/17] Call an action when user is authenticated (#324) --- class-two-factor-core.php | 2 ++ readme.txt | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/class-two-factor-core.php b/class-two-factor-core.php index a5e0c8db..7cbcb21d 100644 --- a/class-two-factor-core.php +++ b/class-two-factor-core.php @@ -702,6 +702,8 @@ public static function login_form_validate_2fa() { wp_set_auth_cookie( $user->ID, $rememberme ); + do_action( 'two_factor_user_authenticated', $user ); + // Must be global because that's how login_header() uses it. global $interim_login; $interim_login = isset( $_REQUEST['interim-login'] ); // WPCS: override ok. diff --git a/readme.txt b/readme.txt index 1acf72b2..9c4b85f4 100644 --- a/readme.txt +++ b/readme.txt @@ -20,6 +20,11 @@ Use the "Two-Factor Options" section under "Users" → "Your Profile" to enable For more history, see [this post](https://stephanis.info/2013/08/14/two-cents-on-two-factor/). += Actions & Filters = + +Here is a list of action and filter hooks provided by the plugin: + +- `two_factor_user_authenticated` action which receives the logged in `WP_User` object as the first argument for determining the logged in user right after the authentication workflow. == Screenshots == From f9394ddf3b45b64c065c9e1065d1affbce5aeba5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Toni=20Viemer=C3=B6?= Date: Wed, 12 Feb 2020 21:07:42 +0200 Subject: [PATCH 02/17] Update blog post URL (#332) --- readme.md | 2 +- readme.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/readme.md b/readme.md index 069b8914..fa711b55 100644 --- a/readme.md +++ b/readme.md @@ -23,7 +23,7 @@ Use the "Two-Factor Options" section under "Users" → "Your Profile" to enable - Backup Codes - Dummy Method (only for testing purposes) -For more history, see [this post](https://stephanis.info/2013/08/14/two-cents-on-two-factor/). +For more history, see [this post](https://georgestephanis.wordpress.com/2013/08/14/two-cents-on-two-factor/). ## Screenshots ## diff --git a/readme.txt b/readme.txt index 9c4b85f4..7d8e1c9a 100644 --- a/readme.txt +++ b/readme.txt @@ -18,7 +18,7 @@ Use the "Two-Factor Options" section under "Users" → "Your Profile" to enable - Backup Codes - Dummy Method (only for testing purposes) -For more history, see [this post](https://stephanis.info/2013/08/14/two-cents-on-two-factor/). +For more history, see [this post](https://georgestephanis.wordpress.com/2013/08/14/two-cents-on-two-factor/). = Actions & Filters = From f79433e771120d40e475c38c7cb866f906a85439 Mon Sep 17 00:00:00 2001 From: Paul Schreiber Date: Mon, 23 Mar 2020 18:20:45 -0400 Subject: [PATCH 03/17] remove spaces from TOTP codes --- providers/class.two-factor-totp.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/providers/class.two-factor-totp.php b/providers/class.two-factor-totp.php index d9a56781..8d109086 100644 --- a/providers/class.two-factor-totp.php +++ b/providers/class.two-factor-totp.php @@ -137,7 +137,8 @@ public function user_two_factor_options_update( $user_id ) { // Validate and store a new secret key. if ( ! empty( $_POST['two-factor-totp-authcode'] ) && ! empty( $_POST['two-factor-totp-key'] ) ) { if ( $this->is_valid_key( $_POST['two-factor-totp-key'] ) ) { - if ( $this->is_valid_authcode( $_POST['two-factor-totp-key'], $_POST['two-factor-totp-authcode'] ) ) { + $authcode = filter_input( INPUT_POST, 'two-factor-totp-authcode', FILTER_SANITIZE_NUMBER_INT ); + if ( $this->is_valid_authcode( $_POST['two-factor-totp-key'], $authcode ) ) { if ( ! $this->set_user_totp_key( $user_id, $_POST['two-factor-totp-key'] ) ) { $errors[] = __( 'Unable to save Two Factor Authentication code. Please re-scan the QR code and enter the code provided by your application.', 'two-factor' ); } From 47ee4d525fc6a56ac151721255d8a6d86bb9afae Mon Sep 17 00:00:00 2001 From: Christian Chung Date: Tue, 28 Apr 2020 20:18:03 -0400 Subject: [PATCH 04/17] Filter the available provider for a user --- class-two-factor-core.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/class-two-factor-core.php b/class-two-factor-core.php index 7cbcb21d..6ccadd37 100644 --- a/class-two-factor-core.php +++ b/class-two-factor-core.php @@ -190,6 +190,14 @@ public static function get_available_providers_for_user( $user = null ) { $enabled_providers = self::get_enabled_providers_for_user( $user ); $configured_providers = array(); + /** + * Filter the available two-factor authentication providers for this user. + * + * @param string $providers The available providers. + * @param int $user_id The user ID. + */ + $enabled_providers = apply_filters( 'two_factor_available_providers_for_user', $enabled_providers, $user_id ); + foreach ( $providers as $classname => $provider ) { if ( in_array( $classname, $enabled_providers ) && $provider->is_available_for_user( $user ) ) { $configured_providers[ $classname ] = $provider; @@ -882,4 +890,3 @@ public static function rememberme() { return (bool) apply_filters( 'two_factor_rememberme', $rememberme ); } } - From cc4fdaf84d12fa5a8c261c84b8bb04dd5206e91f Mon Sep 17 00:00:00 2001 From: Christian Chung Date: Tue, 28 Apr 2020 20:20:36 -0400 Subject: [PATCH 05/17] Update availble provider hook docblock --- class-two-factor-core.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/class-two-factor-core.php b/class-two-factor-core.php index 6ccadd37..b0128289 100644 --- a/class-two-factor-core.php +++ b/class-two-factor-core.php @@ -193,7 +193,7 @@ public static function get_available_providers_for_user( $user = null ) { /** * Filter the available two-factor authentication providers for this user. * - * @param string $providers The available providers. + * @param array $providers The available providers. * @param int $user_id The user ID. */ $enabled_providers = apply_filters( 'two_factor_available_providers_for_user', $enabled_providers, $user_id ); From 7a8cb659ff5e92c00e6f05ecae1939eac1104dd1 Mon Sep 17 00:00:00 2001 From: Christian Chung Date: Tue, 28 Apr 2020 20:23:58 -0400 Subject: [PATCH 06/17] Update available provider hook signature and docs --- class-two-factor-core.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/class-two-factor-core.php b/class-two-factor-core.php index b0128289..c02b0d4c 100644 --- a/class-two-factor-core.php +++ b/class-two-factor-core.php @@ -193,10 +193,10 @@ public static function get_available_providers_for_user( $user = null ) { /** * Filter the available two-factor authentication providers for this user. * - * @param array $providers The available providers. - * @param int $user_id The user ID. + * @param array $enabled_providers The available providers. + * @param int $user_id The user ID. */ - $enabled_providers = apply_filters( 'two_factor_available_providers_for_user', $enabled_providers, $user_id ); + $enabled_providers = apply_filters( 'two_factor_available_providers_for_user', $enabled_providers, $user->ID ); foreach ( $providers as $classname => $provider ) { if ( in_array( $classname, $enabled_providers ) && $provider->is_available_for_user( $user ) ) { From 6e24d516c9528935812d56c40cecc0f3d441fec1 Mon Sep 17 00:00:00 2001 From: Christian Chung Date: Tue, 28 Apr 2020 20:30:14 -0400 Subject: [PATCH 07/17] Rename filter to two_factor_enabled_providers_for_user --- class-two-factor-core.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/class-two-factor-core.php b/class-two-factor-core.php index c02b0d4c..a90fcf06 100644 --- a/class-two-factor-core.php +++ b/class-two-factor-core.php @@ -191,12 +191,12 @@ public static function get_available_providers_for_user( $user = null ) { $configured_providers = array(); /** - * Filter the available two-factor authentication providers for this user. + * Filter the enabled two-factor authentication providers for this user. * - * @param array $enabled_providers The available providers. + * @param array $enabled_providers The enabled providers. * @param int $user_id The user ID. */ - $enabled_providers = apply_filters( 'two_factor_available_providers_for_user', $enabled_providers, $user->ID ); + $enabled_providers = apply_filters( 'two_factor_enabled_providers_for_user', $enabled_providers, $user->ID ); foreach ( $providers as $classname => $provider ) { if ( in_array( $classname, $enabled_providers ) && $provider->is_available_for_user( $user ) ) { From 59ac115905d3c95fe1f524403d10066a262ddc0f Mon Sep 17 00:00:00 2001 From: Christian Chung Date: Tue, 28 Apr 2020 20:34:41 -0400 Subject: [PATCH 08/17] Move enabled provider filter lower in call stack --- class-two-factor-core.php | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/class-two-factor-core.php b/class-two-factor-core.php index a90fcf06..359e8c57 100644 --- a/class-two-factor-core.php +++ b/class-two-factor-core.php @@ -172,7 +172,13 @@ public static function get_enabled_providers_for_user( $user = null ) { } $enabled_providers = array_intersect( $enabled_providers, array_keys( $providers ) ); - return $enabled_providers; + /** + * Filter the enabled two-factor authentication providers for this user. + * + * @param array $enabled_providers The enabled providers. + * @param int $user_id The user ID. + */ + return apply_filters( 'two_factor_enabled_providers_for_user', $enabled_providers, $user->ID ); } /** @@ -190,14 +196,6 @@ public static function get_available_providers_for_user( $user = null ) { $enabled_providers = self::get_enabled_providers_for_user( $user ); $configured_providers = array(); - /** - * Filter the enabled two-factor authentication providers for this user. - * - * @param array $enabled_providers The enabled providers. - * @param int $user_id The user ID. - */ - $enabled_providers = apply_filters( 'two_factor_enabled_providers_for_user', $enabled_providers, $user->ID ); - foreach ( $providers as $classname => $provider ) { if ( in_array( $classname, $enabled_providers ) && $provider->is_available_for_user( $user ) ) { $configured_providers[ $classname ] = $provider; From ab712781879048cb85f76c506f048f023fab34e2 Mon Sep 17 00:00:00 2001 From: Christian Chung Date: Thu, 30 Apr 2020 02:13:31 -0400 Subject: [PATCH 09/17] Add filter to customize email token mail subject and message (#345) Props @christianc1 --- providers/class.two-factor-email.php | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/providers/class.two-factor-email.php b/providers/class.two-factor-email.php index 17788571..818e1f15 100644 --- a/providers/class.two-factor-email.php +++ b/providers/class.two-factor-email.php @@ -152,6 +152,23 @@ public function generate_and_email_token( $user ) { /* translators: %s: token */ $message = wp_strip_all_tags( sprintf( __( 'Enter %s to log in.', 'two-factor' ), $token ) ); + /** + * Filter the token email subject. + * + * @param string $subject The email subject line. + * @param int $user_id The ID of the user. + */ + $subject = apply_filters( 'two_factor_token_email_subject', $subject, $user->ID ); + + /** + * Filter the token email message. + * + * @param string $message The email message. + * @param string $token The token. + * @param int $user_id The ID of the user. + */ + $message = apply_filters( 'two_factor_token_email_message', $message, $token, $user->ID ); + return wp_mail( $user->user_email, $subject, $message ); } From 9e7fa13b7faa55ed1a0c6391e72505d804d294e1 Mon Sep 17 00:00:00 2001 From: Kaspars Dambis Date: Thu, 30 Apr 2020 10:00:37 +0300 Subject: [PATCH 10/17] Fix the GitHub repo URL and track Composer deps (#346) --- .gitignore | 1 - composer.json | 7 +- composer.lock | 1000 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 1006 insertions(+), 2 deletions(-) create mode 100644 composer.lock diff --git a/.gitignore b/.gitignore index 08e044a1..bf93ebc1 100644 --- a/.gitignore +++ b/.gitignore @@ -2,5 +2,4 @@ /node_modules /npm-debug.log /vendor -/composer.lock /dist diff --git a/composer.json b/composer.json index b654e59d..6022f3e8 100644 --- a/composer.json +++ b/composer.json @@ -5,10 +5,15 @@ "license": "GPL-2.0-or-later", "homepage": "https://wordpress.org/plugins/two-factor/", "support": { - "source": "https://github.com/WordPress/application-passwords", + "source": "https://github.com/WordPress/two-factor", "forum": "https://wordpress.org/support/plugin/two-factor/", "issues": "https://github.com/WordPress/two-factor/issues" }, + "config": { + "platform": { + "php": "5.6.20" + } + }, "require": { "php": ">=5.6" }, diff --git a/composer.lock b/composer.lock new file mode 100644 index 00000000..2279698a --- /dev/null +++ b/composer.lock @@ -0,0 +1,1000 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "a83c62e6890021658de2662f901d53a4", + "packages": [], + "packages-dev": [ + { + "name": "guzzle/guzzle", + "version": "v3.9.3", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle3.git", + "reference": "0645b70d953bc1c067bbc8d5bc53194706b628d9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle3/zipball/0645b70d953bc1c067bbc8d5bc53194706b628d9", + "reference": "0645b70d953bc1c067bbc8d5bc53194706b628d9", + "shasum": "" + }, + "require": { + "ext-curl": "*", + "php": ">=5.3.3", + "symfony/event-dispatcher": "~2.1" + }, + "replace": { + "guzzle/batch": "self.version", + "guzzle/cache": "self.version", + "guzzle/common": "self.version", + "guzzle/http": "self.version", + "guzzle/inflection": "self.version", + "guzzle/iterator": "self.version", + "guzzle/log": "self.version", + "guzzle/parser": "self.version", + "guzzle/plugin": "self.version", + "guzzle/plugin-async": "self.version", + "guzzle/plugin-backoff": "self.version", + "guzzle/plugin-cache": "self.version", + "guzzle/plugin-cookie": "self.version", + "guzzle/plugin-curlauth": "self.version", + "guzzle/plugin-error-response": "self.version", + "guzzle/plugin-history": "self.version", + "guzzle/plugin-log": "self.version", + "guzzle/plugin-md5": "self.version", + "guzzle/plugin-mock": "self.version", + "guzzle/plugin-oauth": "self.version", + "guzzle/service": "self.version", + "guzzle/stream": "self.version" + }, + "require-dev": { + "doctrine/cache": "~1.3", + "monolog/monolog": "~1.0", + "phpunit/phpunit": "3.7.*", + "psr/log": "~1.0", + "symfony/class-loader": "~2.1", + "zendframework/zend-cache": "2.*,<2.3", + "zendframework/zend-log": "2.*,<2.3" + }, + "suggest": { + "guzzlehttp/guzzle": "Guzzle 5 has moved to a new package name. The package you have installed, Guzzle 3, is deprecated." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.9-dev" + } + }, + "autoload": { + "psr-0": { + "Guzzle": "src/", + "Guzzle\\Tests": "tests/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Guzzle Community", + "homepage": "https://github.com/guzzle/guzzle/contributors" + } + ], + "description": "PHP HTTP client. This library is deprecated in favor of https://packagist.org/packages/guzzlehttp/guzzle", + "homepage": "http://guzzlephp.org/", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "rest", + "web service" + ], + "abandoned": "guzzlehttp/guzzle", + "time": "2015-03-18T18:23:50+00:00" + }, + { + "name": "php-coveralls/php-coveralls", + "version": "v1.1.0", + "source": { + "type": "git", + "url": "https://github.com/php-coveralls/php-coveralls.git", + "reference": "37f8f83fe22224eb9d9c6d593cdeb33eedd2a9ad" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-coveralls/php-coveralls/zipball/37f8f83fe22224eb9d9c6d593cdeb33eedd2a9ad", + "reference": "37f8f83fe22224eb9d9c6d593cdeb33eedd2a9ad", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-simplexml": "*", + "guzzle/guzzle": "^2.8 || ^3.0", + "php": "^5.3.3 || ^7.0", + "psr/log": "^1.0", + "symfony/config": "^2.1 || ^3.0 || ^4.0", + "symfony/console": "^2.1 || ^3.0 || ^4.0", + "symfony/stopwatch": "^2.0 || ^3.0 || ^4.0", + "symfony/yaml": "^2.0 || ^3.0 || ^4.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35 || ^5.4.3 || ^6.0" + }, + "suggest": { + "symfony/http-kernel": "Allows Symfony integration" + }, + "bin": [ + "bin/coveralls" + ], + "type": "library", + "autoload": { + "psr-4": { + "Satooshi\\": "src/Satooshi/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Kitamura Satoshi", + "email": "with.no.parachute@gmail.com", + "homepage": "https://www.facebook.com/satooshi.jp" + } + ], + "description": "PHP client library for Coveralls API", + "homepage": "https://github.com/php-coveralls/php-coveralls", + "keywords": [ + "ci", + "coverage", + "github", + "test" + ], + "time": "2017-12-06T23:17:56+00:00" + }, + { + "name": "psr/log", + "version": "1.1.3", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "0f73288fd15629204f9d42b7055f72dacbe811fc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/0f73288fd15629204f9d42b7055f72dacbe811fc", + "reference": "0f73288fd15629204f9d42b7055f72dacbe811fc", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "Psr/Log/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "time": "2020-03-23T09:12:05+00:00" + }, + { + "name": "squizlabs/php_codesniffer", + "version": "3.5.5", + "source": { + "type": "git", + "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", + "reference": "73e2e7f57d958e7228fce50dc0c61f58f017f9f6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/73e2e7f57d958e7228fce50dc0c61f58f017f9f6", + "reference": "73e2e7f57d958e7228fce50dc0c61f58f017f9f6", + "shasum": "" + }, + "require": { + "ext-simplexml": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0" + }, + "bin": [ + "bin/phpcs", + "bin/phpcbf" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Greg Sherwood", + "role": "lead" + } + ], + "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", + "homepage": "https://github.com/squizlabs/PHP_CodeSniffer", + "keywords": [ + "phpcs", + "standards" + ], + "time": "2020-04-17T01:09:41+00:00" + }, + { + "name": "symfony/config", + "version": "v3.4.40", + "source": { + "type": "git", + "url": "https://github.com/symfony/config.git", + "reference": "3634991bea549e73c45a964c38f30ceeae6ed877" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/config/zipball/3634991bea549e73c45a964c38f30ceeae6ed877", + "reference": "3634991bea549e73c45a964c38f30ceeae6ed877", + "shasum": "" + }, + "require": { + "php": "^5.5.9|>=7.0.8", + "symfony/filesystem": "~2.8|~3.0|~4.0", + "symfony/polyfill-ctype": "~1.8" + }, + "conflict": { + "symfony/dependency-injection": "<3.3", + "symfony/finder": "<3.3" + }, + "require-dev": { + "symfony/dependency-injection": "~3.3|~4.0", + "symfony/event-dispatcher": "~3.3|~4.0", + "symfony/finder": "~3.3|~4.0", + "symfony/yaml": "~3.0|~4.0" + }, + "suggest": { + "symfony/yaml": "To use the yaml reference dumper" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.4-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Config\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Config Component", + "homepage": "https://symfony.com", + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-04-12T14:33:46+00:00" + }, + { + "name": "symfony/console", + "version": "v3.4.40", + "source": { + "type": "git", + "url": "https://github.com/symfony/console.git", + "reference": "bf60d5e606cd595391c5f82bf6b570d9573fa120" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/console/zipball/bf60d5e606cd595391c5f82bf6b570d9573fa120", + "reference": "bf60d5e606cd595391c5f82bf6b570d9573fa120", + "shasum": "" + }, + "require": { + "php": "^5.5.9|>=7.0.8", + "symfony/debug": "~2.8|~3.0|~4.0", + "symfony/polyfill-mbstring": "~1.0" + }, + "conflict": { + "symfony/dependency-injection": "<3.4", + "symfony/process": "<3.3" + }, + "provide": { + "psr/log-implementation": "1.0" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/config": "~3.3|~4.0", + "symfony/dependency-injection": "~3.4|~4.0", + "symfony/event-dispatcher": "~2.8|~3.0|~4.0", + "symfony/lock": "~3.4|~4.0", + "symfony/process": "~3.3|~4.0" + }, + "suggest": { + "psr/log": "For using the console logger", + "symfony/event-dispatcher": "", + "symfony/lock": "", + "symfony/process": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.4-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Console\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Console Component", + "homepage": "https://symfony.com", + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-03-27T17:07:22+00:00" + }, + { + "name": "symfony/debug", + "version": "v3.4.40", + "source": { + "type": "git", + "url": "https://github.com/symfony/debug.git", + "reference": "ce9f3b5e8e1c50f849fded59b3a1b6bc3562ec29" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/debug/zipball/ce9f3b5e8e1c50f849fded59b3a1b6bc3562ec29", + "reference": "ce9f3b5e8e1c50f849fded59b3a1b6bc3562ec29", + "shasum": "" + }, + "require": { + "php": "^5.5.9|>=7.0.8", + "psr/log": "~1.0" + }, + "conflict": { + "symfony/http-kernel": ">=2.3,<2.3.24|~2.4.0|>=2.5,<2.5.9|>=2.6,<2.6.2" + }, + "require-dev": { + "symfony/http-kernel": "~2.8|~3.0|~4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.4-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Debug\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Debug Component", + "homepage": "https://symfony.com", + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-03-23T10:22:40+00:00" + }, + { + "name": "symfony/event-dispatcher", + "version": "v2.8.52", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "a77e974a5fecb4398833b0709210e3d5e334ffb0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/a77e974a5fecb4398833b0709210e3d5e334ffb0", + "reference": "a77e974a5fecb4398833b0709210e3d5e334ffb0", + "shasum": "" + }, + "require": { + "php": ">=5.3.9" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/config": "^2.0.5|~3.0.0", + "symfony/dependency-injection": "~2.6|~3.0.0", + "symfony/expression-language": "~2.6|~3.0.0", + "symfony/stopwatch": "~2.3|~3.0.0" + }, + "suggest": { + "symfony/dependency-injection": "", + "symfony/http-kernel": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.8-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\EventDispatcher\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony EventDispatcher Component", + "homepage": "https://symfony.com", + "time": "2018-11-21T14:20:20+00:00" + }, + { + "name": "symfony/filesystem", + "version": "v3.4.40", + "source": { + "type": "git", + "url": "https://github.com/symfony/filesystem.git", + "reference": "78a93e5606a19d0fb490afc3c4a9b7ecd86e1515" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/78a93e5606a19d0fb490afc3c4a9b7ecd86e1515", + "reference": "78a93e5606a19d0fb490afc3c4a9b7ecd86e1515", + "shasum": "" + }, + "require": { + "php": "^5.5.9|>=7.0.8", + "symfony/polyfill-ctype": "~1.8" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.4-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Filesystem\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Filesystem Component", + "homepage": "https://symfony.com", + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-04-12T16:54:01+00:00" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.15.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "4719fa9c18b0464d399f1a63bf624b42b6fa8d14" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/4719fa9c18b0464d399f1a63bf624b42b6fa8d14", + "reference": "4719fa9c18b0464d399f1a63bf624b42b6fa8d14", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.15-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-02-27T09:26:54+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.15.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "81ffd3a9c6d707be22e3012b827de1c9775fc5ac" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/81ffd3a9c6d707be22e3012b827de1c9775fc5ac", + "reference": "81ffd3a9c6d707be22e3012b827de1c9775fc5ac", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.15-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-03-09T19:04:49+00:00" + }, + { + "name": "symfony/stopwatch", + "version": "v3.4.40", + "source": { + "type": "git", + "url": "https://github.com/symfony/stopwatch.git", + "reference": "a7a98f40dcc382a332c3729a6d04b298ffbb8f1f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/a7a98f40dcc382a332c3729a6d04b298ffbb8f1f", + "reference": "a7a98f40dcc382a332c3729a6d04b298ffbb8f1f", + "shasum": "" + }, + "require": { + "php": "^5.5.9|>=7.0.8" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.4-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Stopwatch\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Stopwatch Component", + "homepage": "https://symfony.com", + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-03-15T09:38:08+00:00" + }, + { + "name": "symfony/yaml", + "version": "v3.4.40", + "source": { + "type": "git", + "url": "https://github.com/symfony/yaml.git", + "reference": "8fef49ac1357f4e05c997a1f139467ccb186bffa" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/yaml/zipball/8fef49ac1357f4e05c997a1f139467ccb186bffa", + "reference": "8fef49ac1357f4e05c997a1f139467ccb186bffa", + "shasum": "" + }, + "require": { + "php": "^5.5.9|>=7.0.8", + "symfony/polyfill-ctype": "~1.8" + }, + "conflict": { + "symfony/console": "<3.4" + }, + "require-dev": { + "symfony/console": "~3.4|~4.0" + }, + "suggest": { + "symfony/console": "For validating YAML files using the lint command" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.4-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Yaml\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Yaml Component", + "homepage": "https://symfony.com", + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-04-24T10:16:04+00:00" + }, + { + "name": "wp-coding-standards/wpcs", + "version": "2.2.1", + "source": { + "type": "git", + "url": "https://github.com/WordPress/WordPress-Coding-Standards.git", + "reference": "b5a453203114cc2284b1a614c4953456fbe4f546" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/WordPress/WordPress-Coding-Standards/zipball/b5a453203114cc2284b1a614c4953456fbe4f546", + "reference": "b5a453203114cc2284b1a614c4953456fbe4f546", + "shasum": "" + }, + "require": { + "php": ">=5.4", + "squizlabs/php_codesniffer": "^3.3.1" + }, + "require-dev": { + "dealerdirect/phpcodesniffer-composer-installer": "^0.5 || ^0.6", + "phpcompatibility/php-compatibility": "^9.0", + "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0" + }, + "suggest": { + "dealerdirect/phpcodesniffer-composer-installer": "^0.6 || This Composer plugin will sort out the PHPCS 'installed_paths' automatically." + }, + "type": "phpcodesniffer-standard", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Contributors", + "homepage": "https://github.com/WordPress/WordPress-Coding-Standards/graphs/contributors" + } + ], + "description": "PHP_CodeSniffer rules (sniffs) to enforce WordPress coding conventions", + "keywords": [ + "phpcs", + "standards", + "wordpress" + ], + "time": "2020-02-04T02:52:06+00:00" + }, + { + "name": "xwp/wp-dev-lib", + "version": "1.6.3", + "source": { + "type": "git", + "url": "https://github.com/xwp/wp-dev-lib.git", + "reference": "a0e93ff45b3ff1a5488195d935edaf31af49eaf5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/xwp/wp-dev-lib/zipball/a0e93ff45b3ff1a5488195d935edaf31af49eaf5", + "reference": "a0e93ff45b3ff1a5488195d935edaf31af49eaf5", + "shasum": "" + }, + "type": "library", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "XWP", + "email": "technology@xwp.co", + "homepage": "https://xwp.co" + } + ], + "description": "Common code used during development of WordPress plugins and themes", + "homepage": "https://github.com/xwp/wp-dev-lib", + "keywords": [ + "development", + "plugins", + "themes", + "tools", + "wordpress" + ], + "time": "2020-04-28T02:24:13+00:00" + } + ], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "php": ">=5.6" + }, + "platform-dev": [], + "platform-overrides": { + "php": "5.6.20" + }, + "plugin-api-version": "1.1.0" +} From d3359a87fb0c087cc0c57764f5fa6bb2a2937744 Mon Sep 17 00:00:00 2001 From: Kaspars Dambis Date: Thu, 30 Apr 2020 10:11:51 +0300 Subject: [PATCH 11/17] Enable the dummy method only during debug (#347) --- class-two-factor-core.php | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/class-two-factor-core.php b/class-two-factor-core.php index 359e8c57..50da86fd 100644 --- a/class-two-factor-core.php +++ b/class-two-factor-core.php @@ -68,6 +68,8 @@ public static function add_hooks( $compat ) { // Run only after the core wp_authenticate_username_password() check. add_filter( 'authenticate', array( __CLASS__, 'filter_authenticate' ), 50 ); + add_filter( 'two_factor_providers', array( __CLASS__, 'enable_dummy_method_for_debug' ) ); + $compat->init(); } @@ -138,6 +140,30 @@ public static function get_providers() { return $providers; } + /** + * Enable the dummy method only during debugging. + * + * @param array $methods List of enabled methods. + * + * @return array + */ + public static function enable_dummy_method_for_debug( $methods ) { + if ( ! self::is_wp_debug() ) { + unset( $methods['Two_Factor_Dummy'] ); + } + + return $methods; + } + + /** + * Check if the debug mode is enabled. + * + * @return boolean + */ + protected static function is_wp_debug() { + return ( defined( 'WP_DEBUG' ) && WP_DEBUG ); + } + /** * Keep track of all the authentication cookies that need to be * invalidated before the second factor authentication. From 121993cbe3e773b192b1776bcad6046c69d19f5d Mon Sep 17 00:00:00 2001 From: Kaspars Dambis Date: Thu, 30 Apr 2020 14:07:36 +0300 Subject: [PATCH 12/17] Fix the OTP secret delete button (#348) --- class-two-factor-core.php | 106 +++++++++++++++++++++- providers/class.two-factor-totp.php | 60 +++++++++--- tests/providers/class.two-factor-totp.php | 11 +-- 3 files changed, 152 insertions(+), 25 deletions(-) diff --git a/class-two-factor-core.php b/class-two-factor-core.php index 50da86fd..827f882b 100644 --- a/class-two-factor-core.php +++ b/class-two-factor-core.php @@ -27,7 +27,21 @@ class Two_Factor_Core { * * @type string */ - const USER_META_NONCE_KEY = '_two_factor_nonce'; + const USER_META_NONCE_KEY = '_two_factor_nonce'; + + /** + * URL query paramater used for our custom actions. + * + * @var string + */ + const USER_SETTINGS_ACTION_QUERY_VAR = 'two_factor_action'; + + /** + * Nonce key for user settings. + * + * @var string + */ + const USER_SETTINGS_ACTION_NONCE_QUERY_ARG = '_two_factor_action_nonce'; /** * Keep track of all the password-based authentication sessions that @@ -68,6 +82,7 @@ public static function add_hooks( $compat ) { // Run only after the core wp_authenticate_username_password() check. add_filter( 'authenticate', array( __CLASS__, 'filter_authenticate' ), 50 ); + add_action( 'admin_init', array( __CLASS__, 'trigger_user_settings_action' ) ); add_filter( 'two_factor_providers', array( __CLASS__, 'enable_dummy_method_for_debug' ) ); $compat->init(); @@ -164,6 +179,95 @@ protected static function is_wp_debug() { return ( defined( 'WP_DEBUG' ) && WP_DEBUG ); } + /** + * Get the user settings page URL. + * + * Fetch this from the plugin core after we introduce proper dependency injection + * and get away from the singletons at the provider level (should be handled by core). + * + * @param integer $user_id User ID. + * + * @return string + */ + protected static function get_user_settings_page_url( $user_id ) { + $page = 'user-edit.php'; + + if ( defined( 'IS_PROFILE_PAGE' ) && IS_PROFILE_PAGE ) { + $page = 'profile.php'; + } + + return add_query_arg( + array( + 'user_id' => intval( $user_id ), + ), + self_admin_url( $page ) + ); + } + + /** + * Get the URL for resetting the secret token. + * + * @param integer $user_id User ID. + * @param string $action Custom two factor action key. + * + * @return string + */ + public static function get_user_update_action_url( $user_id, $action ) { + return wp_nonce_url( + add_query_arg( + array( + self::USER_SETTINGS_ACTION_QUERY_VAR => $action, + ), + self::get_user_settings_page_url( $user_id ) + ), + sprintf( '%d-%s', $user_id, $action ), + self::USER_SETTINGS_ACTION_NONCE_QUERY_ARG + ); + } + + /** + * Check if a user action is valid. + * + * @param integer $user_id User ID. + * @param string $action User action ID. + * + * @return boolean + */ + public static function is_valid_user_action( $user_id, $action ) { + $request_nonce = filter_input( INPUT_GET, self::USER_SETTINGS_ACTION_NONCE_QUERY_ARG, FILTER_SANITIZE_STRING ); + + return wp_verify_nonce( + $request_nonce, + sprintf( '%d-%s', $user_id, $action ) + ); + } + + /** + * Trigger our custom update action if a valid + * action request is detected and passes the nonce check. + * + * @return void + */ + public static function trigger_user_settings_action() { + $action = filter_input( INPUT_GET, self::USER_SETTINGS_ACTION_QUERY_VAR, FILTER_SANITIZE_STRING ); + $user_id = filter_input( INPUT_GET, 'user_id', FILTER_SANITIZE_NUMBER_INT ); + + if ( empty( $user_id ) && is_user_logged_in() ) { + $user_id = get_current_user_id(); + } + + if ( ! empty( $action ) && self::is_valid_user_action( $user_id, $action ) ) { + /** + * This action is triggered when a valid Two Factor settings + * action is detected and it passes the nonce validation. + * + * @param integer $user_id User ID. + * @param string $action Settings action. + */ + do_action( 'two_factor_user_settings_action', $user_id, $action ); + } + } + /** * Keep track of all the authentication cookies that need to be * invalidated before the second factor authentication. diff --git a/providers/class.two-factor-totp.php b/providers/class.two-factor-totp.php index 8d109086..e764e1c9 100644 --- a/providers/class.two-factor-totp.php +++ b/providers/class.two-factor-totp.php @@ -24,6 +24,13 @@ class Two_Factor_Totp extends Two_Factor_Provider { */ const NOTICES_META_KEY = '_two_factor_totp_notices'; + /** + * Action name for resetting the secret token. + * + * @var string + */ + const ACTION_SECRET_DELETE = 'totp-delete'; + const DEFAULT_KEY_BIT_SIZE = 160; const DEFAULT_CRYPTO = 'sha1'; const DEFAULT_DIGIT_COUNT = 6; @@ -36,8 +43,10 @@ class Two_Factor_Totp extends Two_Factor_Provider { */ protected function __construct() { add_action( 'two-factor-user-options-' . __CLASS__, array( $this, 'user_two_factor_options' ) ); - add_action( 'personal_options_update', array( $this, 'user_two_factor_options_update' ) ); - add_action( 'edit_user_profile_update', array( $this, 'user_two_factor_options_update' ) ); + add_action( 'personal_options_update', array( $this, 'user_two_factor_options_update' ) ); + add_action( 'edit_user_profile_update', array( $this, 'user_two_factor_options_update' ) ); + add_action( 'two_factor_user_settings_action', array( $this, 'user_settings_action' ), 10, 2 ); + return parent::__construct(); } @@ -59,6 +68,31 @@ public function get_label() { return _x( 'Time Based One-Time Password (Google Authenticator)', 'Provider Label', 'two-factor' ); } + /** + * Trigger our custom user settings actions. + * + * @param integer $user_id User ID. + * @param string $action Action ID. + * + * @return void + */ + public function user_settings_action( $user_id, $action ) { + if ( self::ACTION_SECRET_DELETE === $action ) { + $this->delete_user_totp_key( $user_id ); + } + } + + /** + * Get the URL for deleting the secret token. + * + * @param integer $user_id User ID. + * + * @return string + */ + protected function get_token_delete_url_for_user( $user_id ) { + return Two_Factor_Core::get_user_update_action_url( $user_id, self::ACTION_SECRET_DELETE ); + } + /** * Display TOTP options on the user settings page. * @@ -73,7 +107,7 @@ public function user_two_factor_options( $user ) { wp_nonce_field( 'user_two_factor_totp_options', '_nonce_user_two_factor_totp_options', false ); $key = $this->get_user_totp_key( $user->ID ); - $this->admin_notices(); + $this->admin_notices( $user->ID ); ?>
@@ -104,7 +138,7 @@ public function user_two_factor_options( $user ) {

- + @@ -124,16 +158,9 @@ public function user_two_factor_options_update( $user_id ) { $notices = array(); $errors = array(); - $current_key = $this->get_user_totp_key( $user_id ); - if ( isset( $_POST['_nonce_user_two_factor_totp_options'] ) ) { check_admin_referer( 'user_two_factor_totp_options', '_nonce_user_two_factor_totp_options' ); - // Delete the secret key. - if ( ! empty( $current_key ) && isset( $_POST['two-factor-totp-delete'] ) ) { - $this->delete_user_totp_key( $user_id ); - } - // Validate and store a new secret key. if ( ! empty( $_POST['two-factor-totp-authcode'] ) && ! empty( $_POST['two-factor-totp-key'] ) ) { if ( $this->is_valid_key( $_POST['two-factor-totp-key'] ) ) { @@ -213,12 +240,17 @@ public function is_valid_key( $key ) { /** * Display any available admin notices. + * + * @param integer $user_id User ID. + * + * @return void */ - public function admin_notices() { - $notices = get_user_meta( get_current_user_id(), self::NOTICES_META_KEY, true ); + public function admin_notices( $user_id ) { + $notices = get_user_meta( $user_id, self::NOTICES_META_KEY, true ); if ( ! empty( $notices ) ) { - delete_user_meta( get_current_user_id(), self::NOTICES_META_KEY ); + delete_user_meta( $user_id, self::NOTICES_META_KEY ); + foreach ( $notices as $class => $messages ) { ?>

diff --git a/tests/providers/class.two-factor-totp.php b/tests/providers/class.two-factor-totp.php index a9ec0bb3..3b45101b 100644 --- a/tests/providers/class.two-factor-totp.php +++ b/tests/providers/class.two-factor-totp.php @@ -246,16 +246,7 @@ public function test_user_can_delete_secret() { 'Secret was stored and can be fetched' ); - // Configure the request and the nonce. - $nonce = wp_create_nonce( 'user_two_factor_totp_options' ); - $_POST['_nonce_user_two_factor_totp_options'] = $nonce; - $_REQUEST['_nonce_user_two_factor_totp_options'] = $nonce; // Required for check_admin_referer(). - - // Set the request to delete things. - $_POST['two-factor-totp-delete'] = 1; - - // Process the request. - $this->provider->user_two_factor_options_update( $user->ID ); + $this->provider->delete_user_totp_key( $user->ID ); $this->assertEquals( '', From dffa869c7a9bed5a1f3fbb209d3e773bf3812186 Mon Sep 17 00:00:00 2001 From: Kaspars Dambis Date: Thu, 30 Apr 2020 15:42:47 +0300 Subject: [PATCH 13/17] Bump the tested with WP --- readme.md | 41 +++++++++++++++++++++++------------------ readme.txt | 2 +- 2 files changed, 24 insertions(+), 19 deletions(-) diff --git a/readme.md b/readme.md index fa711b55..61128d00 100644 --- a/readme.md +++ b/readme.md @@ -4,26 +4,31 @@ ![Banner](assets/banner-1544x500.png) Enable Two-Factor Authentication using time-based one-time passwords (OTP, Google Authenticator), Universal 2nd Factor (FIDO U2F, YubiKey), email and backup verification codes. -**Contributors:** [georgestephanis](https://profiles.wordpress.org/georgestephanis), [valendesigns](https://profiles.wordpress.org/valendesigns), [stevenkword](https://profiles.wordpress.org/stevenkword), [extendwings](https://profiles.wordpress.org/extendwings), [sgrant](https://profiles.wordpress.org/sgrant), [aaroncampbell](https://profiles.wordpress.org/aaroncampbell), [johnbillion](https://profiles.wordpress.org/johnbillion), [stevegrunwell](https://profiles.wordpress.org/stevegrunwell), [netweb](https://profiles.wordpress.org/netweb), [kasparsd](https://profiles.wordpress.org/kasparsd), [alihusnainarshad](https://profiles.wordpress.org/alihusnainarshad), [passoniate](https://profiles.wordpress.org/passoniate) +**Contributors:** [georgestephanis](https://profiles.wordpress.org/georgestephanis), [valendesigns](https://profiles.wordpress.org/valendesigns), [stevenkword](https://profiles.wordpress.org/stevenkword), [extendwings](https://profiles.wordpress.org/extendwings), [sgrant](https://profiles.wordpress.org/sgrant), [aaroncampbell](https://profiles.wordpress.org/aaroncampbell), [johnbillion](https://profiles.wordpress.org/johnbillion), [stevegrunwell](https://profiles.wordpress.org/stevegrunwell), [netweb](https://profiles.wordpress.org/netweb), [kasparsd](https://profiles.wordpress.org/kasparsd), [alihusnainarshad](https://profiles.wordpress.org/alihusnainarshad), [passoniate](https://profiles.wordpress.org/passoniate) **Tags:** [two factor](https://wordpress.org/plugins/tags/two-factor), [two step](https://wordpress.org/plugins/tags/two-step), [authentication](https://wordpress.org/plugins/tags/authentication), [login](https://wordpress.org/plugins/tags/login), [totp](https://wordpress.org/plugins/tags/totp), [fido u2f](https://wordpress.org/plugins/tags/fido-u2f), [u2f](https://wordpress.org/plugins/tags/u2f), [email](https://wordpress.org/plugins/tags/email), [backup codes](https://wordpress.org/plugins/tags/backup-codes), [2fa](https://wordpress.org/plugins/tags/2fa), [yubikey](https://wordpress.org/plugins/tags/yubikey) **Requires at least:** 4.3 -**Tested up to:** 5.3 +**Tested up to:** 5.4 **Stable tag:** trunk (master) **Requires PHP:** 5.6 -[![Build Status](https://travis-ci.org/WordPress/two-factor.svg?branch=master)](https://travis-ci.org/WordPress/two-factor) [![Coverage Status](https://coveralls.io/repos/WordPress/two-factor/badge.svg?branch=master)](https://coveralls.io/github/WordPress/two-factor) [![Built with Grunt](https://gruntjs.com/cdn/builtwith.svg)](http://gruntjs.com) +[![Build Status](https://travis-ci.org/wordpress/two-factor.svg?branch=master)](https://travis-ci.org/wordpress/two-factor) [![Coverage Status](https://coveralls.io/repos/wordpress/two-factor/badge.svg?branch=master)](https://coveralls.io/github/wordpress/two-factor) [![Built with Grunt](https://gruntjs.com/cdn/builtwith.svg)](http://gruntjs.com) ## Description ## -Use the "Two-Factor Options" section under "Users" → "Your Profile" to enable and configure one or multiple two-factor authentication providers for your account: +Use the "Two-Factor Options" section under "Users" → "Your Profile" to enable and configure one or multiple two-factor authentication providers for your account: + +- Email codes +- Time Based One-Time Passwords (TOTP) +- FIDO Universal 2nd Factor (U2F) +- Backup Codes +- Dummy Method (only for testing purposes) + +For more history, see [this post](https://georgestephanis.wordpress.com/2013/08/14/two-cents-on-two-factor/). +### Actions & Filters ### +Here is a list of action and filter hooks provided by the plugin: + +- `two_factor_user_authenticated` action which receives the logged in `WP_User` object as the first argument for determining the logged in user right after the authentication workflow. -- Email codes -- Time Based One-Time Passwords (TOTP) -- FIDO Universal 2nd Factor (U2F) -- Backup Codes -- Dummy Method (only for testing purposes) - -For more history, see [this post](https://georgestephanis.wordpress.com/2013/08/14/two-cents-on-two-factor/). ## Screenshots ## @@ -41,13 +46,13 @@ For more history, see [this post](https://georgestephanis.wordpress.com/2013/08/ ## Get Involved ## -Development happens [on GitHub](https://github.com/wordpress/two-factor/). Join the `#core-passwords` channel [on WordPress Slack](http://wordpress.slack.com) ([sign up here](http://chat.wordpress.org)). - -Here is how to get started: - - $ git clone https://github.com/wordpress/two-factor.git - $ npm install - +Development happens [on GitHub](https://github.com/wordpress/two-factor/). Join the `#core-passwords` channel [on WordPress Slack](http://wordpress.slack.com) ([sign up here](http://chat.wordpress.org)). + +Here is how to get started: + + $ git clone https://github.com/wordpress/two-factor.git + $ npm install + Then open [a pull request](https://help.github.com/articles/creating-a-pull-request-from-a-fork/) with the suggested changes. ## Changelog ## diff --git a/readme.txt b/readme.txt index 7d8e1c9a..8866a206 100644 --- a/readme.txt +++ b/readme.txt @@ -2,7 +2,7 @@ Contributors: georgestephanis, valendesigns, stevenkword, extendwings, sgrant, aaroncampbell, johnbillion, stevegrunwell, netweb, kasparsd, alihusnainarshad, passoniate Tags: two factor, two step, authentication, login, totp, fido u2f, u2f, email, backup codes, 2fa, yubikey Requires at least: 4.3 -Tested up to: 5.3 +Tested up to: 5.4 Requires PHP: 5.6 Stable tag: trunk From a1b6c807163a9159001bca9d7e14cba6662fe75f Mon Sep 17 00:00:00 2001 From: Kaspars Dambis Date: Thu, 30 Apr 2020 15:43:00 +0300 Subject: [PATCH 14/17] Version bump --- two-factor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/two-factor.php b/two-factor.php index 3db47577..09725281 100644 --- a/two-factor.php +++ b/two-factor.php @@ -4,7 +4,7 @@ * Plugin URI: https://wordpress.org/plugins/two-factor/ * Description: Two-Factor Authentication using time-based one-time passwords, Universal 2nd Factor (FIDO U2F), email and backup verification codes. * Author: Plugin Contributors - * Version: 0.5.1 + * Version: 0.5.2 * Author URI: https://github.com/wordpress/two-factor/graphs/contributors * Network: True * Text Domain: two-factor From 2b4ce5cd41a8859f5524f651493151baa61b7683 Mon Sep 17 00:00:00 2001 From: Kaspars Dambis Date: Thu, 30 Apr 2020 15:51:16 +0300 Subject: [PATCH 15/17] Allow admins to configure U2F keys for other users (#349) --- class-two-factor-core.php | 24 +++++++++++++++---- ...s.two-factor-fido-u2f-admin-list-table.php | 2 -- providers/class.two-factor-fido-u2f-admin.php | 16 +++++++++---- providers/class.two-factor-fido-u2f.php | 2 +- providers/js/fido-u2f-admin-inline-edit.js | 3 ++- 5 files changed, 33 insertions(+), 14 deletions(-) diff --git a/class-two-factor-core.php b/class-two-factor-core.php index 827f882b..923cdfc8 100644 --- a/class-two-factor-core.php +++ b/class-two-factor-core.php @@ -242,6 +242,24 @@ public static function is_valid_user_action( $user_id, $action ) { ); } + /** + * Get the ID of the user being edited. + * + * @return integer + */ + public static function current_user_being_edited() { + // Try to resolve the user ID from the request first. + if ( ! empty( $_REQUEST['user_id'] ) ) { + $user_id = intval( $_REQUEST['user_id'] ); + + if ( current_user_can( 'edit_user', $user_id ) ) { + return $user_id; + } + } + + return get_current_user_id(); + } + /** * Trigger our custom update action if a valid * action request is detected and passes the nonce check. @@ -250,11 +268,7 @@ public static function is_valid_user_action( $user_id, $action ) { */ public static function trigger_user_settings_action() { $action = filter_input( INPUT_GET, self::USER_SETTINGS_ACTION_QUERY_VAR, FILTER_SANITIZE_STRING ); - $user_id = filter_input( INPUT_GET, 'user_id', FILTER_SANITIZE_NUMBER_INT ); - - if ( empty( $user_id ) && is_user_logged_in() ) { - $user_id = get_current_user_id(); - } + $user_id = self::current_user_being_edited(); if ( ! empty( $action ) && self::is_valid_user_action( $user_id, $action ) ) { /** diff --git a/providers/class.two-factor-fido-u2f-admin-list-table.php b/providers/class.two-factor-fido-u2f-admin-list-table.php index 95109e7d..61adf0f7 100644 --- a/providers/class.two-factor-fido-u2f-admin-list-table.php +++ b/providers/class.two-factor-fido-u2f-admin-list-table.php @@ -115,8 +115,6 @@ public function inline_edit() {
-

-