Two-Factor - Version 0.7.0

Version Description

Download this release

Release Info

Developer kasparsd
Plugin Icon 128x128 Two-Factor
Version 0.7.0
Comparing to
See all releases

Code changes from version 0.7.1 to 0.7.0

class-two-factor-core.php CHANGED
@@ -679,35 +679,50 @@ class Two_Factor_Core {
679
  </ul>
680
  </div>
681
  <?php endif; ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
682
  <style>
683
- /* @todo: migrate to an external stylesheet. */
684
- .backup-methods-wrap {
685
  margin-top: 16px;
686
  padding: 0 24px;
687
- }
688
- .backup-methods-wrap a {
689
  color: #999;
690
  text-decoration: none;
691
- }
692
- ul.backup-methods {
693
  display: none;
694
  padding-left: 1.5em;
695
- }
696
- /* Prevent Jetpack from hiding our controls, see https://github.com/Automattic/jetpack/issues/3747 */
697
- .jetpack-sso-form-display #loginform > p,
698
- .jetpack-sso-form-display #loginform > div {
699
  display: block;
700
- }
701
  </style>
702
 
703
  <?php
704
- if ( ! function_exists( 'login_footer' ) ) {
705
- include_once TWO_FACTOR_DIR . 'includes/function.login-footer.php';
706
- }
707
-
708
- login_footer();
709
  ?>
710
- <?php
 
 
 
711
  }
712
 
713
  /**
679
  </ul>
680
  </div>
681
  <?php endif; ?>
682
+
683
+ <p id="backtoblog">
684
+ <a href="<?php echo esc_url( home_url( '/' ) ); ?>" title="<?php esc_attr_e( 'Are you lost?', 'two-factor' ); ?>">
685
+ <?php
686
+ echo esc_html(
687
+ sprintf(
688
+ // translators: %s: site name.
689
+ __( '&larr; Back to %s', 'two-factor' ),
690
+ get_bloginfo( 'title', 'display' )
691
+ )
692
+ );
693
+ ?>
694
+ </a>
695
+ </p>
696
+ </div>
697
  <style>
698
+ /* @todo: migrate to an external stylesheet. */
699
+ .backup-methods-wrap {
700
  margin-top: 16px;
701
  padding: 0 24px;
702
+ }
703
+ .backup-methods-wrap a {
704
  color: #999;
705
  text-decoration: none;
706
+ }
707
+ ul.backup-methods {
708
  display: none;
709
  padding-left: 1.5em;
710
+ }
711
+ /* Prevent Jetpack from hiding our controls, see https://github.com/Automattic/jetpack/issues/3747 */
712
+ .jetpack-sso-form-display #loginform > p,
713
+ .jetpack-sso-form-display #loginform > div {
714
  display: block;
715
+ }
716
  </style>
717
 
718
  <?php
719
+ /** This action is documented in wp-login.php */
720
+ do_action( 'login_footer' );
 
 
 
721
  ?>
722
+ <div class="clear"></div>
723
+ </body>
724
+ </html>
725
+ <?php
726
  }
727
 
728
  /**
docker-compose.yml ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ version: '3.6'
2
+
3
+ services:
4
+
5
+ wpdevlib:
6
+ build: ./tests/docker/wp-dev-lib
7
+ working_dir: /var/www/html
8
+ volumes:
9
+ - .:/var/www/html
10
+ environment:
11
+ CHECK_SCOPE: all
includes/function.login-footer.php DELETED
@@ -1,87 +0,0 @@
1
- <?php
2
- /**
3
- * Extracted from wp-login.php since that file also loads WP core which we already have.
4
- */
5
-
6
- /**
7
- * Outputs the footer for the login page.
8
- *
9
- * @since 3.1.0
10
- *
11
- * @global bool|string $interim_login Whether interim login modal is being displayed. String 'success'
12
- * upon successful login.
13
- *
14
- * @param string $input_id Which input to auto-focus.
15
- */
16
- function login_footer( $input_id = '' ) {
17
- global $interim_login;
18
-
19
- // Don't allow interim logins to navigate away from the page.
20
- if ( ! $interim_login ) {
21
- ?>
22
- <p id="backtoblog">
23
- <?php
24
- $html_link = sprintf(
25
- '<a href="%s">%s</a>',
26
- esc_url( home_url( '/' ) ),
27
- sprintf(
28
- /* translators: %s: Site title. */
29
- _x( '&larr; Go to %s', 'site' ),
30
- get_bloginfo( 'title', 'display' )
31
- )
32
- );
33
- /**
34
- * Filter the "Go to site" link displayed in the login page footer.
35
- *
36
- * @since 5.7.0
37
- *
38
- * @param string $link HTML link to the home URL of the current site.
39
- */
40
- echo apply_filters( 'login_site_html_link', $html_link );
41
- ?>
42
- </p>
43
- <?php
44
-
45
- the_privacy_policy_link( '<div class="privacy-policy-page-link">', '</div>' );
46
- }
47
-
48
- ?>
49
- </div><?php // End of <div id="login">. ?>
50
-
51
- <?php
52
-
53
- if ( ! empty( $input_id ) ) {
54
- ?>
55
- <script type="text/javascript">
56
- try{document.getElementById('<?php echo $input_id; ?>').focus();}catch(e){}
57
- if(typeof wpOnload==='function')wpOnload();
58
- </script>
59
- <?php
60
- }
61
-
62
- /**
63
- * Fires in the login page footer.
64
- *
65
- * @since 3.1.0
66
- */
67
- do_action( 'login_footer' );
68
-
69
- ?>
70
- <div class="clear"></div>
71
- </body>
72
- </html>
73
- <?php
74
- }
75
-
76
- /**
77
- * Outputs the JavaScript to handle the form shaking on the login page.
78
- *
79
- * @since 3.0.0
80
- */
81
- function wp_shake_js() {
82
- ?>
83
- <script type="text/javascript">
84
- document.querySelector('form').classList.add('shake');
85
- </script>
86
- <?php
87
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/function.login-header.php CHANGED
@@ -6,14 +6,6 @@
6
  /**
7
  * Output the login page header.
8
  *
9
- * @since 2.1.0
10
- *
11
- * @global string $error Login error message set by deprecated pluggable wp_login() function
12
- * or plugins replacing it.
13
- * @global bool|string $interim_login Whether interim login modal is being displayed. String 'success'
14
- * upon successful login.
15
- * @global string $action The action that brought the visitor to the login page.
16
- *
17
  * @param string $title Optional. WordPress login Page title to display in the `<title>` element.
18
  * Default 'Log In'.
19
  * @param string $message Optional. Message to display in header. Default empty.
@@ -23,8 +15,7 @@ function login_header( $title = 'Log In', $message = '', $wp_error = null ) {
23
  global $error, $interim_login, $action;
24
 
25
  // Don't index any of these forms.
26
- add_filter( 'wp_robots', 'wp_robots_sensitive_page' );
27
- add_action( 'login_head', 'wp_strict_cross_origin_referrer' );
28
 
29
  add_action( 'login_head', 'wp_login_viewport_meta' );
30
 
@@ -33,7 +24,7 @@ function login_header( $title = 'Log In', $message = '', $wp_error = null ) {
33
  }
34
 
35
  // Shake it!
36
- $shake_error_codes = array( 'empty_password', 'empty_email', 'invalid_email', 'invalidcombo', 'empty_username', 'invalid_username', 'incorrect_password', 'retrieve_password_email_failure' );
37
  /**
38
  * Filters the error codes array for shaking the login form.
39
  *
@@ -43,20 +34,14 @@ function login_header( $title = 'Log In', $message = '', $wp_error = null ) {
43
  */
44
  $shake_error_codes = apply_filters( 'shake_error_codes', $shake_error_codes );
45
 
46
- if ( $shake_error_codes && $wp_error->has_errors() && in_array( $wp_error->get_error_code(), $shake_error_codes, true ) ) {
47
- add_action( 'login_footer', 'wp_shake_js', 12 );
48
- }
49
 
50
  $login_title = get_bloginfo( 'name', 'display' );
51
 
52
- /* translators: Login screen title. 1: Login screen name, 2: Network or site name. */
53
  $login_title = sprintf( __( '%1$s &lsaquo; %2$s &#8212; WordPress' ), $title, $login_title );
54
 
55
- if ( wp_is_recovery_mode() ) {
56
- /* translators: %s: Login screen title. */
57
- $login_title = sprintf( __( 'Recovery Mode &#8212; %s' ), $login_title );
58
- }
59
-
60
  /**
61
  * Filters the title tag content for login page.
62
  *
@@ -68,9 +53,14 @@ function login_header( $title = 'Log In', $message = '', $wp_error = null ) {
68
  $login_title = apply_filters( 'login_title', $login_title, $title );
69
 
70
  ?><!DOCTYPE html>
71
- <html <?php language_attributes(); ?>>
 
 
 
 
 
72
  <head>
73
- <meta http-equiv="Content-Type" content="<?php bloginfo( 'html_type' ); ?>; charset=<?php bloginfo( 'charset' ); ?>" />
74
  <title><?php echo $login_title; ?></title>
75
  <?php
76
 
@@ -79,9 +69,9 @@ function login_header( $title = 'Log In', $message = '', $wp_error = null ) {
79
  /*
80
  * Remove all stored post data on logging out.
81
  * This could be added by add_action('login_head'...) like wp_shake_js(),
82
- * but maybe better if it's not removable by plugins.
83
  */
84
- if ( 'loggedout' === $wp_error->get_error_code() ) {
85
  ?>
86
  <script>if("sessionStorage" in window){try{for(var key in sessionStorage){if(key.indexOf("wp-autosave-")!=-1){sessionStorage.removeItem(key)}}}catch(e){}};</script>
87
  <?php
@@ -101,7 +91,13 @@ function login_header( $title = 'Log In', $message = '', $wp_error = null ) {
101
  */
102
  do_action( 'login_head' );
103
 
104
- $login_header_url = __( 'https://wordpress.org/' );
 
 
 
 
 
 
105
 
106
  /**
107
  * Filters link URL of the header logo above login form.
@@ -112,54 +108,38 @@ function login_header( $title = 'Log In', $message = '', $wp_error = null ) {
112
  */
113
  $login_header_url = apply_filters( 'login_headerurl', $login_header_url );
114
 
115
- $login_header_title = '';
116
-
117
  /**
118
  * Filters the title attribute of the header logo above login form.
119
  *
120
  * @since 2.1.0
121
- * @deprecated 5.2.0 Use {@see 'login_headertext'} instead.
122
  *
123
  * @param string $login_header_title Login header logo title attribute.
124
  */
125
- $login_header_title = apply_filters_deprecated(
126
- 'login_headertitle',
127
- array( $login_header_title ),
128
- '5.2.0',
129
- 'login_headertext',
130
- __( 'Usage of the title attribute on the login logo is not recommended for accessibility reasons. Use the link text instead.' )
131
- );
132
-
133
- $login_header_text = empty( $login_header_title ) ? __( 'Powered by WordPress' ) : $login_header_title;
134
 
135
- /**
136
- * Filters the link text of the header logo above the login form.
137
- *
138
- * @since 5.2.0
139
- *
140
- * @param string $login_header_text The login header logo link text.
141
  */
142
- $login_header_text = apply_filters( 'login_headertext', $login_header_text );
 
 
 
 
143
 
144
  $classes = array( 'login-action-' . $action, 'wp-core-ui' );
145
-
146
- if ( is_rtl() ) {
147
  $classes[] = 'rtl';
148
- }
149
-
150
  if ( $interim_login ) {
151
  $classes[] = 'interim-login';
152
-
153
  ?>
154
  <style type="text/css">html{background-color: transparent;}</style>
155
  <?php
156
 
157
- if ( 'success' === $interim_login ) {
158
  $classes[] = 'interim-login-success';
159
- }
160
  }
161
-
162
- $classes[] = ' locale-' . sanitize_html_class( strtolower( str_replace( '_', '-', get_locale() ) ) );
163
 
164
  /**
165
  * Filters the login page body classes.
@@ -173,10 +153,7 @@ function login_header( $title = 'Log In', $message = '', $wp_error = null ) {
173
 
174
  ?>
175
  </head>
176
- <body class="login no-js <?php echo esc_attr( implode( ' ', $classes ) ); ?>">
177
- <script type="text/javascript">
178
- document.body.className = document.body.className.replace('no-js','js');
179
- </script>
180
  <?php
181
  /**
182
  * Fires in the login page header after the body tag is opened.
@@ -184,11 +161,13 @@ function login_header( $title = 'Log In', $message = '', $wp_error = null ) {
184
  * @since 4.6.0
185
  */
186
  do_action( 'login_header' );
187
-
188
  ?>
189
  <div id="login">
190
- <h1><a href="<?php echo esc_url( $login_header_url ); ?>"><?php echo $login_header_text; ?></a></h1>
191
  <?php
 
 
 
192
  /**
193
  * Filters the message to display above the login form.
194
  *
@@ -197,32 +176,27 @@ function login_header( $title = 'Log In', $message = '', $wp_error = null ) {
197
  * @param string $message Login message text.
198
  */
199
  $message = apply_filters( 'login_message', $message );
200
-
201
- if ( ! empty( $message ) ) {
202
  echo $message . "\n";
203
- }
204
 
205
  // In case a plugin uses $error rather than the $wp_errors object.
206
- if ( ! empty( $error ) ) {
207
- $wp_error->add( 'error', $error );
208
- unset( $error );
209
  }
210
 
211
- if ( $wp_error->has_errors() ) {
212
- $errors = '';
213
  $messages = '';
214
-
215
  foreach ( $wp_error->get_error_codes() as $code ) {
216
  $severity = $wp_error->get_error_data( $code );
217
  foreach ( $wp_error->get_error_messages( $code ) as $error_message ) {
218
- if ( 'message' === $severity ) {
219
  $messages .= ' ' . $error_message . "<br />\n";
220
- } else {
221
  $errors .= ' ' . $error_message . "<br />\n";
222
- }
223
  }
224
  }
225
-
226
  if ( ! empty( $errors ) ) {
227
  /**
228
  * Filters the error messages displayed above the login form.
@@ -233,7 +207,6 @@ function login_header( $title = 'Log In', $message = '', $wp_error = null ) {
233
  */
234
  echo '<div id="login_error">' . apply_filters( 'login_errors', $errors ) . "</div>\n";
235
  }
236
-
237
  if ( ! empty( $messages ) ) {
238
  /**
239
  * Filters instructional messages displayed above the login form.
@@ -247,11 +220,6 @@ function login_header( $title = 'Log In', $message = '', $wp_error = null ) {
247
  }
248
  } // End of login_header().
249
 
250
- /**
251
- * Outputs the viewport meta tag for the login page.
252
- *
253
- * @since 3.7.0
254
- */
255
  function wp_login_viewport_meta() {
256
  ?>
257
  <meta name="viewport" content="width=device-width" />
6
  /**
7
  * Output the login page header.
8
  *
 
 
 
 
 
 
 
 
9
  * @param string $title Optional. WordPress login Page title to display in the `<title>` element.
10
  * Default 'Log In'.
11
  * @param string $message Optional. Message to display in header. Default empty.
15
  global $error, $interim_login, $action;
16
 
17
  // Don't index any of these forms.
18
+ add_action( 'login_head', 'wp_no_robots' );
 
19
 
20
  add_action( 'login_head', 'wp_login_viewport_meta' );
21
 
24
  }
25
 
26
  // Shake it!
27
+ $shake_error_codes = array( 'empty_password', 'empty_email', 'invalid_email', 'invalidcombo', 'empty_username', 'invalid_username', 'incorrect_password' );
28
  /**
29
  * Filters the error codes array for shaking the login form.
30
  *
34
  */
35
  $shake_error_codes = apply_filters( 'shake_error_codes', $shake_error_codes );
36
 
37
+ if ( $shake_error_codes && $wp_error->get_error_code() && in_array( $wp_error->get_error_code(), $shake_error_codes ) )
38
+ add_action( 'login_head', 'wp_shake_js', 12 );
 
39
 
40
  $login_title = get_bloginfo( 'name', 'display' );
41
 
42
+ /* translators: Login screen title. 1: Login screen name, 2: Network or site name */
43
  $login_title = sprintf( __( '%1$s &lsaquo; %2$s &#8212; WordPress' ), $title, $login_title );
44
 
 
 
 
 
 
45
  /**
46
  * Filters the title tag content for login page.
47
  *
53
  $login_title = apply_filters( 'login_title', $login_title, $title );
54
 
55
  ?><!DOCTYPE html>
56
+ <!--[if IE 8]>
57
+ <html xmlns="http://www.w3.org/1999/xhtml" class="ie8" <?php language_attributes(); ?>>
58
+ <![endif]-->
59
+ <!--[if !(IE 8) ]><!-->
60
+ <html xmlns="http://www.w3.org/1999/xhtml" <?php language_attributes(); ?>>
61
+ <!--<![endif]-->
62
  <head>
63
+ <meta http-equiv="Content-Type" content="<?php bloginfo('html_type'); ?>; charset=<?php bloginfo('charset'); ?>" />
64
  <title><?php echo $login_title; ?></title>
65
  <?php
66
 
69
  /*
70
  * Remove all stored post data on logging out.
71
  * This could be added by add_action('login_head'...) like wp_shake_js(),
72
+ * but maybe better if it's not removable by plugins
73
  */
74
+ if ( 'loggedout' == $wp_error->get_error_code() ) {
75
  ?>
76
  <script>if("sessionStorage" in window){try{for(var key in sessionStorage){if(key.indexOf("wp-autosave-")!=-1){sessionStorage.removeItem(key)}}}catch(e){}};</script>
77
  <?php
91
  */
92
  do_action( 'login_head' );
93
 
94
+ if ( is_multisite() ) {
95
+ $login_header_url = network_home_url();
96
+ $login_header_title = get_network()->site_name;
97
+ } else {
98
+ $login_header_url = __( 'https://wordpress.org/' );
99
+ $login_header_title = __( 'Powered by WordPress' );
100
+ }
101
 
102
  /**
103
  * Filters link URL of the header logo above login form.
108
  */
109
  $login_header_url = apply_filters( 'login_headerurl', $login_header_url );
110
 
 
 
111
  /**
112
  * Filters the title attribute of the header logo above login form.
113
  *
114
  * @since 2.1.0
 
115
  *
116
  * @param string $login_header_title Login header logo title attribute.
117
  */
118
+ $login_header_title = apply_filters( 'login_headertitle', $login_header_title );
 
 
 
 
 
 
 
 
119
 
120
+ /*
121
+ * To match the URL/title set above, Multisite sites have the blog name,
122
+ * while single sites get the header title.
 
 
 
123
  */
124
+ if ( is_multisite() ) {
125
+ $login_header_text = get_bloginfo( 'name', 'display' );
126
+ } else {
127
+ $login_header_text = $login_header_title;
128
+ }
129
 
130
  $classes = array( 'login-action-' . $action, 'wp-core-ui' );
131
+ if ( is_rtl() )
 
132
  $classes[] = 'rtl';
 
 
133
  if ( $interim_login ) {
134
  $classes[] = 'interim-login';
 
135
  ?>
136
  <style type="text/css">html{background-color: transparent;}</style>
137
  <?php
138
 
139
+ if ( 'success' === $interim_login )
140
  $classes[] = 'interim-login-success';
 
141
  }
142
+ $classes[] =' locale-' . sanitize_html_class( strtolower( str_replace( '_', '-', get_locale() ) ) );
 
143
 
144
  /**
145
  * Filters the login page body classes.
153
 
154
  ?>
155
  </head>
156
+ <body class="login <?php echo esc_attr( implode( ' ', $classes ) ); ?>">
 
 
 
157
  <?php
158
  /**
159
  * Fires in the login page header after the body tag is opened.
161
  * @since 4.6.0
162
  */
163
  do_action( 'login_header' );
 
164
  ?>
165
  <div id="login">
166
+ <h1><a href="<?php echo esc_url( $login_header_url ); ?>" title="<?php echo esc_attr( $login_header_title ); ?>" tabindex="-1"><?php echo $login_header_text; ?></a></h1>
167
  <?php
168
+
169
+ unset( $login_header_url, $login_header_title );
170
+
171
  /**
172
  * Filters the message to display above the login form.
173
  *
176
  * @param string $message Login message text.
177
  */
178
  $message = apply_filters( 'login_message', $message );
179
+ if ( !empty( $message ) )
 
180
  echo $message . "\n";
 
181
 
182
  // In case a plugin uses $error rather than the $wp_errors object.
183
+ if ( !empty( $error ) ) {
184
+ $wp_error->add('error', $error);
185
+ unset($error);
186
  }
187
 
188
+ if ( $wp_error->get_error_code() ) {
189
+ $errors = '';
190
  $messages = '';
 
191
  foreach ( $wp_error->get_error_codes() as $code ) {
192
  $severity = $wp_error->get_error_data( $code );
193
  foreach ( $wp_error->get_error_messages( $code ) as $error_message ) {
194
+ if ( 'message' == $severity )
195
  $messages .= ' ' . $error_message . "<br />\n";
196
+ else
197
  $errors .= ' ' . $error_message . "<br />\n";
 
198
  }
199
  }
 
200
  if ( ! empty( $errors ) ) {
201
  /**
202
  * Filters the error messages displayed above the login form.
207
  */
208
  echo '<div id="login_error">' . apply_filters( 'login_errors', $errors ) . "</div>\n";
209
  }
 
210
  if ( ! empty( $messages ) ) {
211
  /**
212
  * Filters instructional messages displayed above the login form.
220
  }
221
  } // End of login_header().
222
 
 
 
 
 
 
223
  function wp_login_viewport_meta() {
224
  ?>
225
  <meta name="viewport" content="width=device-width" />
providers/class-two-factor-backup-codes.php CHANGED
@@ -77,7 +77,7 @@ class Two_Factor_Backup_Codes extends Two_Factor_Provider {
77
  <p>
78
  <span>
79
  <?php
80
- echo wp_kses(
81
  sprintf(
82
  /* translators: %s: URL for code regeneration */
83
  __( 'Two-Factor: You are out of backup codes and need to <a href="%s">regenerate!</a>', 'two-factor' ),
77
  <p>
78
  <span>
79
  <?php
80
+ wp_kses(
81
  sprintf(
82
  /* translators: %s: URL for code regeneration */
83
  __( 'Two-Factor: You are out of backup codes and need to <a href="%s">regenerate!</a>', 'two-factor' ),
readme.md ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!-- DO NOT EDIT THIS FILE; it is auto-generated from readme.txt -->
2
+ # Two-Factor
3
+
4
+ ![Banner](assets/banner-1544x500.png)
5
+ Enable Two-Factor Authentication using time-based one-time passwords (OTP, Google Authenticator), Universal 2nd Factor (FIDO U2F, YubiKey), email and backup verification codes.
6
+
7
+ **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)
8
+ **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)
9
+ **Requires at least:** 4.3
10
+ **Tested up to:** 5.5
11
+ **Stable tag:** trunk (master)
12
+ **Requires PHP:** 5.6
13
+
14
+ [![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)
15
+
16
+ ## Description ##
17
+
18
+ Use the "Two-Factor Options" section under "Users" → "Your Profile" to enable and configure one or multiple two-factor authentication providers for your account:
19
+
20
+ - Email codes
21
+ - Time Based One-Time Passwords (TOTP)
22
+ - FIDO Universal 2nd Factor (U2F)
23
+ - Backup Codes
24
+ - Dummy Method (only for testing purposes)
25
+
26
+ For more history, see [this post](https://georgestephanis.wordpress.com/2013/08/14/two-cents-on-two-factor/).
27
+ ### Actions & Filters ###
28
+ Here is a list of action and filter hooks provided by the plugin:
29
+
30
+ - `two_factor_providers` filter overrides the available two-factor providers such as email and time-based one-time passwords. Array values are PHP classnames of the two-factor providers.
31
+ - `two_factor_enabled_providers_for_user` filter overrides the list of two-factor providers enabled for a user. First argument is an array of enabled provider classnames as values, the second argument is the user ID.
32
+ - `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.
33
+ - `two_factor_token_ttl` filter overrides the time interval in seconds that an email token is considered after generation. Accepts the time in seconds as the first argument and the ID of the `WP_User` object being authenticated.
34
+
35
+
36
+ ## Screenshots ##
37
+
38
+ ### Two-factor options under User Profile.
39
+
40
+ ![Two-factor options under User Profile.](assets/screenshot-1.png)
41
+
42
+ ### U2F Security Keys section under User Profile.
43
+
44
+ ![U2F Security Keys section under User Profile.](assets/screenshot-2.png)
45
+
46
+ ### Email Code Authentication during WordPress Login.
47
+
48
+ ![Email Code Authentication during WordPress Login.](assets/screenshot-3.png)
49
+
50
+ ## Get Involved ##
51
+
52
+ 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)).
53
+
54
+ Here is how to get started:
55
+
56
+ $ git clone https://github.com/wordpress/two-factor.git
57
+ $ npm install
58
+
59
+ Then open [a pull request](https://help.github.com/articles/creating-a-pull-request-from-a-fork/) with the suggested changes.
60
+
61
+ ## Changelog ##
62
+
63
+ See the [release history](https://github.com/wordpress/two-factor/releases).
64
+
readme.txt CHANGED
@@ -2,7 +2,7 @@
2
  Contributors: georgestephanis, valendesigns, stevenkword, extendwings, sgrant, aaroncampbell, johnbillion, stevegrunwell, netweb, kasparsd, alihusnainarshad, passoniate
3
  Tags: two factor, two step, authentication, login, totp, fido u2f, u2f, email, backup codes, 2fa, yubikey
4
  Requires at least: 4.3
5
- Tested up to: 5.8
6
  Requires PHP: 5.6
7
  Stable tag: trunk
8
 
2
  Contributors: georgestephanis, valendesigns, stevenkword, extendwings, sgrant, aaroncampbell, johnbillion, stevegrunwell, netweb, kasparsd, alihusnainarshad, passoniate
3
  Tags: two factor, two step, authentication, login, totp, fido u2f, u2f, email, backup codes, 2fa, yubikey
4
  Requires at least: 4.3
5
+ Tested up to: 5.5
6
  Requires PHP: 5.6
7
  Stable tag: trunk
8
 
two-factor.php CHANGED
@@ -12,7 +12,7 @@
12
  * Plugin URI: https://wordpress.org/plugins/two-factor/
13
  * Description: Two-Factor Authentication using time-based one-time passwords, Universal 2nd Factor (FIDO U2F), email and backup verification codes.
14
  * Author: Plugin Contributors
15
- * Version: 0.7.1
16
  * Author URI: https://github.com/wordpress/two-factor/graphs/contributors
17
  * Network: True
18
  * Text Domain: two-factor
@@ -26,7 +26,7 @@ define( 'TWO_FACTOR_DIR', plugin_dir_path( __FILE__ ) );
26
  /**
27
  * Version of the plugin.
28
  */
29
- define( 'TWO_FACTOR_VERSION', '0.7.1' );
30
 
31
  /**
32
  * Include the base class here, so that other plugins can also extend it.
12
  * Plugin URI: https://wordpress.org/plugins/two-factor/
13
  * Description: Two-Factor Authentication using time-based one-time passwords, Universal 2nd Factor (FIDO U2F), email and backup verification codes.
14
  * Author: Plugin Contributors
15
+ * Version: 0.7.0
16
  * Author URI: https://github.com/wordpress/two-factor/graphs/contributors
17
  * Network: True
18
  * Text Domain: two-factor
26
  /**
27
  * Version of the plugin.
28
  */
29
+ define( 'TWO_FACTOR_VERSION', '0.7.0' );
30
 
31
  /**
32
  * Include the base class here, so that other plugins can also extend it.