diff --git a/wp-content/plugins/two-factor/assets/banner-1544x500.png b/wp-content/plugins/two-factor/assets/banner-1544x500.png
new file mode 100644
index 0000000000000000000000000000000000000000..5b6e2081cf6d604d3b27df7f2bf1bd3554056698
Binary files /dev/null and b/wp-content/plugins/two-factor/assets/banner-1544x500.png differ
diff --git a/wp-content/plugins/two-factor/assets/banner-772x250.png b/wp-content/plugins/two-factor/assets/banner-772x250.png
new file mode 100644
index 0000000000000000000000000000000000000000..b955eeeb3cd3c5cdcdfaafe866ec76b9acc8041c
Binary files /dev/null and b/wp-content/plugins/two-factor/assets/banner-772x250.png differ
diff --git a/wp-content/plugins/two-factor/assets/icon-128x128.png b/wp-content/plugins/two-factor/assets/icon-128x128.png
new file mode 100644
index 0000000000000000000000000000000000000000..1f3a3c314d553dec31fb6b3b788d855aa62bab6f
Binary files /dev/null and b/wp-content/plugins/two-factor/assets/icon-128x128.png differ
diff --git a/wp-content/plugins/two-factor/assets/icon-256x256.png b/wp-content/plugins/two-factor/assets/icon-256x256.png
new file mode 100644
index 0000000000000000000000000000000000000000..3240b832c92997756aaf75e7045372ceaef18272
Binary files /dev/null and b/wp-content/plugins/two-factor/assets/icon-256x256.png differ
diff --git a/wp-content/plugins/two-factor/assets/icon.svg b/wp-content/plugins/two-factor/assets/icon.svg
new file mode 100644
index 0000000000000000000000000000000000000000..cc15690b795c8af5bcf5b715a681aaaf999c85e3
--- /dev/null
+++ b/wp-content/plugins/two-factor/assets/icon.svg
@@ -0,0 +1,6 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="256" height="256">
+  <g fill="none" fill-rule="evenodd">
+    <path fill="#CCC" d="M98 150a60 60 0 1 1 60 0v60a8 8 0 0 1-8 8h-44a8 8 0 0 1-8-8v-60z"/>
+    <path fill="#0073AA" d="M116 132a36 36 0 1 1 24 0v64.7a4 4 0 0 1-4 4h-16a4 4 0 0 1-4-4v-64-.7z"/>
+  </g>
+</svg>
diff --git a/wp-content/plugins/two-factor/assets/screenshot-1.png b/wp-content/plugins/two-factor/assets/screenshot-1.png
new file mode 100644
index 0000000000000000000000000000000000000000..545b45ee70dea58f9fd70c7fee3e85ba67fdb683
Binary files /dev/null and b/wp-content/plugins/two-factor/assets/screenshot-1.png differ
diff --git a/wp-content/plugins/two-factor/assets/screenshot-2.png b/wp-content/plugins/two-factor/assets/screenshot-2.png
new file mode 100644
index 0000000000000000000000000000000000000000..b98358007515bf6fb0640a487737a1e5b3619e4a
Binary files /dev/null and b/wp-content/plugins/two-factor/assets/screenshot-2.png differ
diff --git a/wp-content/plugins/two-factor/class.two-factor-core.php b/wp-content/plugins/two-factor/class.two-factor-core.php
new file mode 100644
index 0000000000000000000000000000000000000000..58d179b6561460aded06f8701ea34a3aceb54cf1
--- /dev/null
+++ b/wp-content/plugins/two-factor/class.two-factor-core.php
@@ -0,0 +1,812 @@
+<?php
+/**
+ * Class for creating two factor authorization.
+ *
+ * @since 0.1-dev
+ *
+ * @package Two_Factor
+ */
+class Two_Factor_Core {
+
+	/**
+	 * The user meta provider key.
+	 *
+	 * @type string
+	 */
+	const PROVIDER_USER_META_KEY = '_two_factor_provider';
+
+	/**
+	 * The user meta enabled providers key.
+	 *
+	 * @type string
+	 */
+	const ENABLED_PROVIDERS_USER_META_KEY = '_two_factor_enabled_providers';
+
+	/**
+	 * The user meta nonce key.
+	 *
+	 * @type string
+	 */
+	const USER_META_NONCE_KEY    = '_two_factor_nonce';
+
+	/**
+	 * Set up filters and actions.
+	 *
+	 * @since 0.1-dev
+	 */
+	public static function add_hooks() {
+		add_action( 'plugins_loaded', array( __CLASS__, 'load_textdomain' ) );
+		add_action( 'init', array( __CLASS__, 'get_providers' ) );
+		add_action( 'wp_login', array( __CLASS__, 'wp_login' ), 10, 2 );
+		add_action( 'login_form_validate_2fa', array( __CLASS__, 'login_form_validate_2fa' ) );
+		add_action( 'login_form_backup_2fa', array( __CLASS__, 'backup_2fa' ) );
+		add_action( 'show_user_profile', array( __CLASS__, 'user_two_factor_options' ) );
+		add_action( 'edit_user_profile', array( __CLASS__, 'user_two_factor_options' ) );
+		add_action( 'personal_options_update', array( __CLASS__, 'user_two_factor_options_update' ) );
+		add_action( 'edit_user_profile_update', array( __CLASS__, 'user_two_factor_options_update' ) );
+		add_filter( 'manage_users_columns', array( __CLASS__, 'filter_manage_users_columns' ) );
+		add_filter( 'wpmu_users_columns', array( __CLASS__, 'filter_manage_users_columns' ) );
+		add_filter( 'manage_users_custom_column', array( __CLASS__, 'manage_users_custom_column' ), 10, 3 );
+
+		// Run only after the core wp_authenticate_username_password() check.
+		add_filter( 'authenticate', array( __CLASS__, 'filter_authenticate' ), 50 );
+	}
+
+	/**
+	 * Loads the plugin's text domain.
+	 *
+	 * Sites on WordPress 4.6+ benefit from just-in-time loading of translations.
+	 */
+	public static function load_textdomain() {
+		load_plugin_textdomain( 'two-factor' );
+	}
+
+	/**
+	 * For each provider, include it and then instantiate it.
+	 *
+	 * @since 0.1-dev
+	 *
+	 * @return array
+	 */
+	public static function get_providers() {
+		$providers = array(
+			'Two_Factor_Email'        => TWO_FACTOR_DIR . 'providers/class.two-factor-email.php',
+			'Two_Factor_Totp'         => TWO_FACTOR_DIR . 'providers/class.two-factor-totp.php',
+			'Two_Factor_FIDO_U2F'     => TWO_FACTOR_DIR . 'providers/class.two-factor-fido-u2f.php',
+			'Two_Factor_Backup_Codes' => TWO_FACTOR_DIR . 'providers/class.two-factor-backup-codes.php',
+			'Two_Factor_Dummy'        => TWO_FACTOR_DIR . 'providers/class.two-factor-dummy.php',
+		);
+
+		/**
+		 * Filter the supplied providers.
+		 *
+		 * This lets third-parties either remove providers (such as Email), or
+		 * add their own providers (such as text message or Clef).
+		 *
+		 * @param array $providers A key-value array where the key is the class name, and
+		 *                         the value is the path to the file containing the class.
+		 */
+		$providers = apply_filters( 'two_factor_providers', $providers );
+
+		// FIDO U2F is PHP 5.3+ only.
+		if ( isset( $providers['Two_Factor_FIDO_U2F'] ) && version_compare( PHP_VERSION, '5.3.0', '<' ) ) {
+			unset( $providers['Two_Factor_FIDO_U2F'] );
+			trigger_error( sprintf( // WPCS: XSS OK.
+				/* translators: %s: version number */
+				__( 'FIDO U2F is not available because you are using PHP %s. (Requires 5.3 or greater)', 'two-factor' ),
+				PHP_VERSION
+			) );
+		}
+
+		/**
+		 * For each filtered provider,
+		 */
+		foreach ( $providers as $class => $path ) {
+			include_once( $path );
+
+			/**
+			 * Confirm that it's been successfully included before instantiating.
+			 */
+			if ( class_exists( $class ) ) {
+				try {
+					$providers[ $class ] = call_user_func( array( $class, 'get_instance' ) );
+				} catch ( Exception $e ) {
+					unset( $providers[ $class ] );
+				}
+			}
+		}
+
+		return $providers;
+	}
+
+	/**
+	 * Get all Two-Factor Auth providers that are enabled for the specified|current user.
+	 *
+	 * @param WP_User $user WP_User object of the logged-in user.
+	 * @return array
+	 */
+	public static function get_enabled_providers_for_user( $user = null ) {
+		if ( empty( $user ) || ! is_a( $user, 'WP_User' ) ) {
+			$user = wp_get_current_user();
+		}
+
+		$providers         = self::get_providers();
+		$enabled_providers = get_user_meta( $user->ID, self::ENABLED_PROVIDERS_USER_META_KEY, true );
+		if ( empty( $enabled_providers ) ) {
+			$enabled_providers = array();
+		}
+		$enabled_providers = array_intersect( $enabled_providers, array_keys( $providers ) );
+
+		return $enabled_providers;
+	}
+
+	/**
+	 * Get all Two-Factor Auth providers that are both enabled and configured for the specified|current user.
+	 *
+	 * @param WP_User $user WP_User object of the logged-in user.
+	 * @return array
+	 */
+	public static function get_available_providers_for_user( $user = null ) {
+		if ( empty( $user ) || ! is_a( $user, 'WP_User' ) ) {
+			$user = wp_get_current_user();
+		}
+
+		$providers            = self::get_providers();
+		$enabled_providers    = self::get_enabled_providers_for_user( $user );
+		$configured_providers = array();
+
+		foreach ( $providers as $classname => $provider ) {
+			if ( in_array( $classname, $enabled_providers ) && $provider->is_available_for_user( $user ) ) {
+				$configured_providers[ $classname ] = $provider;
+			}
+		}
+
+		return $configured_providers;
+	}
+
+	/**
+	 * Gets the Two-Factor Auth provider for the specified|current user.
+	 *
+	 * @since 0.1-dev
+	 *
+	 * @param int $user_id Optional. User ID. Default is 'null'.
+	 * @return object|null
+	 */
+	public static function get_primary_provider_for_user( $user_id = null ) {
+		if ( empty( $user_id ) || ! is_numeric( $user_id ) ) {
+			$user_id = get_current_user_id();
+		}
+
+		$providers           = self::get_providers();
+		$available_providers = self::get_available_providers_for_user( get_userdata( $user_id ) );
+
+		// If there's only one available provider, force that to be the primary.
+		if ( empty( $available_providers ) ) {
+			return null;
+		} elseif ( 1 === count( $available_providers ) ) {
+			$provider = key( $available_providers );
+		} else {
+			$provider = get_user_meta( $user_id, self::PROVIDER_USER_META_KEY, true );
+
+			// If the provider specified isn't enabled, just grab the first one that is.
+			if ( ! isset( $available_providers[ $provider ] ) ) {
+				$provider = key( $available_providers );
+			}
+		}
+
+		/**
+		 * Filter the two-factor authentication provider used for this user.
+		 *
+		 * @param string $provider The provider currently being used.
+		 * @param int    $user_id  The user ID.
+		 */
+		$provider = apply_filters( 'two_factor_primary_provider_for_user', $provider, $user_id );
+
+		if ( isset( $providers[ $provider ] ) ) {
+			return $providers[ $provider ];
+		}
+
+		return null;
+	}
+
+	/**
+	 * Quick boolean check for whether a given user is using two-step.
+	 *
+	 * @since 0.1-dev
+	 *
+	 * @param int $user_id Optional. User ID. Default is 'null'.
+	 * @return bool
+	 */
+	public static function is_user_using_two_factor( $user_id = null ) {
+		$provider = self::get_primary_provider_for_user( $user_id );
+		return ! empty( $provider );
+	}
+
+	/**
+	 * Handle the browser-based login.
+	 *
+	 * @since 0.1-dev
+	 *
+	 * @param string  $user_login Username.
+	 * @param WP_User $user WP_User object of the logged-in user.
+	 */
+	public static function wp_login( $user_login, $user ) {
+		if ( ! self::is_user_using_two_factor( $user->ID ) ) {
+			return;
+		}
+
+		wp_clear_auth_cookie();
+
+		self::show_two_factor_login( $user );
+		exit;
+	}
+
+	/**
+	 * Prevent login through XML-RPC and REST API for users with at least one
+	 * two-factor method enabled.
+	 *
+	 * @param  WP_User|WP_Error $user Valid WP_User only if the previous filters
+	 *                                have verified and confirmed the
+	 *                                authentication credentials.
+	 *
+	 * @return WP_User|WP_Error
+	 */
+	public static function filter_authenticate( $user ) {
+		if ( $user instanceof WP_User && self::is_api_request() && self::is_user_using_two_factor( $user->ID ) && ! self::is_user_api_login_enabled( $user->ID ) ) {
+			return new WP_Error(
+				'invalid_application_credentials',
+				__( 'Error: API login for user disabled.', 'two-factor' )
+			);
+		}
+
+		return $user;
+	}
+
+	/**
+	 * If the current user can login via API requests such as XML-RPC and REST.
+	 *
+	 * @param  integer $user_id User ID.
+	 *
+	 * @return boolean
+	 */
+	public static function is_user_api_login_enabled( $user_id ) {
+		return (bool) apply_filters( 'two_factor_user_api_login_enable', false, $user_id );
+	}
+
+	/**
+	 * Is the current request an XML-RPC or REST request.
+	 *
+	 * @return boolean
+	 */
+	public static function is_api_request() {
+		if ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST ) {
+			return true;
+		}
+
+		if ( defined( 'REST_REQUEST' ) && REST_REQUEST ) {
+			return true;
+		}
+
+		return false;
+	}
+
+	/**
+	 * Display the login form.
+	 *
+	 * @since 0.1-dev
+	 *
+	 * @param WP_User $user WP_User object of the logged-in user.
+	 */
+	public static function show_two_factor_login( $user ) {
+		if ( ! $user ) {
+			$user = wp_get_current_user();
+		}
+
+		$login_nonce = self::create_login_nonce( $user->ID );
+		if ( ! $login_nonce ) {
+			wp_die( esc_html__( 'Failed to create a login nonce.', 'two-factor' ) );
+		}
+
+		$redirect_to = isset( $_REQUEST['redirect_to'] ) ? $_REQUEST['redirect_to'] : admin_url();
+
+		self::login_html( $user, $login_nonce['key'], $redirect_to );
+	}
+
+	/**
+	 * Display the Backup code 2fa screen.
+	 *
+	 * @since 0.1-dev
+	 */
+	public static function backup_2fa() {
+		if ( ! isset( $_GET['wp-auth-id'], $_GET['wp-auth-nonce'], $_GET['provider'] ) ) {
+			return;
+		}
+
+		$user = get_userdata( $_GET['wp-auth-id'] );
+		if ( ! $user ) {
+			return;
+		}
+
+		$nonce = $_GET['wp-auth-nonce'];
+		if ( true !== self::verify_login_nonce( $user->ID, $nonce ) ) {
+			wp_safe_redirect( get_bloginfo( 'url' ) );
+			exit;
+		}
+
+		$providers = self::get_available_providers_for_user( $user );
+		if ( isset( $providers[ $_GET['provider'] ] ) ) {
+			$provider = $providers[ $_GET['provider'] ];
+		} else {
+			wp_die( esc_html__( 'Cheatin&#8217; uh?', 'two-factor' ), 403 );
+		}
+
+		self::login_html( $user, $_GET['wp-auth-nonce'], $_GET['redirect_to'], '', $provider );
+
+		exit;
+	}
+
+	/**
+	 * Generates the html form for the second step of the authentication process.
+	 *
+	 * @since 0.1-dev
+	 *
+	 * @param WP_User       $user WP_User object of the logged-in user.
+	 * @param string        $login_nonce A string nonce stored in usermeta.
+	 * @param string        $redirect_to The URL to which the user would like to be redirected.
+	 * @param string        $error_msg Optional. Login error message.
+	 * @param string|object $provider An override to the provider.
+	 */
+	public static function login_html( $user, $login_nonce, $redirect_to, $error_msg = '', $provider = null ) {
+		if ( empty( $provider ) ) {
+			$provider = self::get_primary_provider_for_user( $user->ID );
+		} elseif ( is_string( $provider ) && method_exists( $provider, 'get_instance' ) ) {
+			$provider = call_user_func( array( $provider, 'get_instance' ) );
+		}
+
+		$provider_class = get_class( $provider );
+
+		$available_providers = self::get_available_providers_for_user( $user );
+		$backup_providers = array_diff_key( $available_providers, array( $provider_class => null ) );
+		$interim_login = isset( $_REQUEST['interim-login'] ); // WPCS: CSRF ok.
+
+		$rememberme = 0;
+		if ( isset( $_REQUEST['rememberme'] ) && $_REQUEST['rememberme'] ) {
+			$rememberme = 1;
+		}
+
+		if ( ! function_exists( 'login_header' ) ) {
+			// We really should migrate login_header() out of `wp-login.php` so it can be called from an includes file.
+			include_once( TWO_FACTOR_DIR . 'includes/function.login-header.php' );
+		}
+
+		login_header();
+
+		if ( ! empty( $error_msg ) ) {
+			echo '<div id="login_error"><strong>' . esc_html( $error_msg ) . '</strong><br /></div>';
+		}
+		?>
+
+		<form name="validate_2fa_form" id="loginform" action="<?php echo esc_url( self::login_url( array( 'action' => 'validate_2fa' ), 'login_post' ) ); ?>" method="post" autocomplete="off">
+				<input type="hidden" name="provider"      id="provider"      value="<?php echo esc_attr( $provider_class ); ?>" />
+				<input type="hidden" name="wp-auth-id"    id="wp-auth-id"    value="<?php echo esc_attr( $user->ID ); ?>" />
+				<input type="hidden" name="wp-auth-nonce" id="wp-auth-nonce" value="<?php echo esc_attr( $login_nonce ); ?>" />
+				<?php   if ( $interim_login ) { ?>
+					<input type="hidden" name="interim-login" value="1" />
+				<?php   } else { ?>
+					<input type="hidden" name="redirect_to" value="<?php echo esc_attr( $redirect_to ); ?>" />
+				<?php   } ?>
+				<input type="hidden" name="rememberme"    id="rememberme"    value="<?php echo esc_attr( $rememberme ); ?>" />
+
+				<?php $provider->authentication_page( $user ); ?>
+		</form>
+
+		<?php
+		if ( 1 === count( $backup_providers ) ) :
+			$backup_classname = key( $backup_providers );
+			$backup_provider = $backup_providers[ $backup_classname ];
+			$login_url = self::login_url(
+				array(
+					'action'        => 'backup_2fa',
+					'provider'      => $backup_classname,
+					'wp-auth-id'    => $user->ID,
+					'wp-auth-nonce' => $login_nonce,
+					'redirect_to'   => $redirect_to,
+					'rememberme'    => $rememberme,
+				)
+			);
+			?>
+			<div class="backup-methods-wrap">
+				<p class="backup-methods">
+					<a href="<?php echo esc_url( $login_url ); ?>">
+						<?php
+						echo esc_html(
+							sprintf(
+								// translators: %s: Two-factor method name.
+								__( 'Or, use your backup method: %s &rarr;', 'two-factor' ),
+								$backup_provider->get_label()
+							)
+						);
+						?>
+					</a>
+				</p>
+			</div>
+			<?php elseif ( 1 < count( $backup_providers ) ) : ?>
+			<div class="backup-methods-wrap">
+				<p class="backup-methods">
+					<a href="javascript:;" onclick="document.querySelector('ul.backup-methods').style.display = 'block';">
+						<?php esc_html_e( 'Or, use a backup method…', 'two-factor' ); ?>
+					</a>
+				</p>
+				<ul class="backup-methods">
+					<?php
+					foreach ( $backup_providers as $backup_classname => $backup_provider ) :
+						$login_url = self::login_url(
+							array(
+								'action'        => 'backup_2fa',
+								'provider'      => $backup_classname,
+								'wp-auth-id'    => $user->ID,
+								'wp-auth-nonce' => $login_nonce,
+								'redirect_to'   => $redirect_to,
+								'rememberme'    => $rememberme,
+							)
+						);
+						?>
+						<li>
+							<a href="<?php echo esc_url( $login_url ); ?>">
+								<?php $backup_provider->print_label(); ?>
+							</a>
+						</li>
+					<?php endforeach; ?>
+				</ul>
+			</div>
+		<?php endif; ?>
+
+		<p id="backtoblog">
+			<a href="<?php echo esc_url( home_url( '/' ) ); ?>" title="<?php esc_attr_e( 'Are you lost?', 'two-factor' ); ?>">
+				<?php
+				echo esc_html(
+					sprintf(
+						// translators: %s: site name.
+						__( '&larr; Back to %s', 'two-factor' ),
+						get_bloginfo( 'title', 'display' )
+					)
+				);
+				?>
+			</a>
+		</p>
+		</div>
+		<style>
+		/* @todo: migrate to an external stylesheet. */
+		.backup-methods-wrap {
+			margin-top: 16px;
+			padding: 0 24px;
+		}
+		.backup-methods-wrap a {
+			color: #999;
+			text-decoration: none;
+		}
+		ul.backup-methods {
+			display: none;
+			padding-left: 1.5em;
+		}
+		/* Prevent Jetpack from hiding our controls, see https://github.com/Automattic/jetpack/issues/3747 */
+		.jetpack-sso-form-display #loginform > p,
+		.jetpack-sso-form-display #loginform > div {
+			display: block;
+		}
+		</style>
+
+		<?php
+		/** This action is documented in wp-login.php */
+		do_action( 'login_footer' ); ?>
+		<div class="clear"></div>
+		</body>
+		</html>
+		<?php
+	}
+
+	/**
+	 * Generate the two-factor login form URL.
+	 *
+	 * @param  array  $params List of query argument pairs to add to the URL.
+	 * @param  string $scheme URL scheme context.
+	 *
+	 * @return string
+	 */
+	public static function login_url( $params = array(), $scheme = 'login' ) {
+		if ( ! is_array( $params ) ) {
+			$params = array();
+		}
+
+		$params = urlencode_deep( $params );
+
+		return add_query_arg( $params, site_url( 'wp-login.php', $scheme ) );
+	}
+
+	/**
+	 * Create the login nonce.
+	 *
+	 * @since 0.1-dev
+	 *
+	 * @param int $user_id User ID.
+	 * @return array
+	 */
+	public static function create_login_nonce( $user_id ) {
+		$login_nonce               = array();
+		try {
+			$login_nonce['key'] = bin2hex( random_bytes( 32 ) );
+		} catch (Exception $ex) {
+			$login_nonce['key'] = wp_hash( $user_id . mt_rand() . microtime(), 'nonce' );
+		}
+		$login_nonce['expiration'] = time() + HOUR_IN_SECONDS;
+
+		if ( ! update_user_meta( $user_id, self::USER_META_NONCE_KEY, $login_nonce ) ) {
+			return false;
+		}
+
+		return $login_nonce;
+	}
+
+	/**
+	 * Delete the login nonce.
+	 *
+	 * @since 0.1-dev
+	 *
+	 * @param int $user_id User ID.
+	 * @return bool
+	 */
+	public static function delete_login_nonce( $user_id ) {
+		return delete_user_meta( $user_id, self::USER_META_NONCE_KEY );
+	}
+
+	/**
+	 * Verify the login nonce.
+	 *
+	 * @since 0.1-dev
+	 *
+	 * @param int    $user_id User ID.
+	 * @param string $nonce Login nonce.
+	 * @return bool
+	 */
+	public static function verify_login_nonce( $user_id, $nonce ) {
+		$login_nonce = get_user_meta( $user_id, self::USER_META_NONCE_KEY, true );
+		if ( ! $login_nonce ) {
+			return false;
+		}
+
+		if ( $nonce !== $login_nonce['key'] || time() > $login_nonce['expiration'] ) {
+			self::delete_login_nonce( $user_id );
+			return false;
+		}
+
+		return true;
+	}
+
+	/**
+	 * Login form validation.
+	 *
+	 * @since 0.1-dev
+	 */
+	public static function login_form_validate_2fa() {
+		if ( ! isset( $_POST['wp-auth-id'], $_POST['wp-auth-nonce'] ) ) {
+			return;
+		}
+
+		$user = get_userdata( $_POST['wp-auth-id'] );
+		if ( ! $user ) {
+			return;
+		}
+
+		$nonce = $_POST['wp-auth-nonce'];
+		if ( true !== self::verify_login_nonce( $user->ID, $nonce ) ) {
+			wp_safe_redirect( get_bloginfo( 'url' ) );
+			exit;
+		}
+
+		if ( isset( $_POST['provider'] ) ) {
+			$providers = self::get_available_providers_for_user( $user );
+			if ( isset( $providers[ $_POST['provider'] ] ) ) {
+				$provider = $providers[ $_POST['provider'] ];
+			} else {
+				wp_die( esc_html__( 'Cheatin&#8217; uh?', 'two-factor' ), 403 );
+			}
+		} else {
+			$provider = self::get_primary_provider_for_user( $user->ID );
+		}
+
+		// Allow the provider to re-send codes, etc.
+		if ( true === $provider->pre_process_authentication( $user ) ) {
+			$login_nonce = self::create_login_nonce( $user->ID );
+			if ( ! $login_nonce ) {
+				wp_die( esc_html__( 'Failed to create a login nonce.', 'two-factor' ) );
+			}
+
+			self::login_html( $user, $login_nonce['key'], $_REQUEST['redirect_to'], '', $provider );
+			exit;
+		}
+
+		// Ask the provider to verify the second factor.
+		if ( true !== $provider->validate_authentication( $user ) ) {
+			do_action( 'wp_login_failed', $user->user_login );
+
+			$login_nonce = self::create_login_nonce( $user->ID );
+			if ( ! $login_nonce ) {
+				wp_die( esc_html__( 'Failed to create a login nonce.', 'two-factor' ) );
+			}
+
+			self::login_html( $user, $login_nonce['key'], $_REQUEST['redirect_to'], esc_html__( 'ERROR: Invalid verification code.', 'two-factor' ), $provider );
+			exit;
+		}
+
+		self::delete_login_nonce( $user->ID );
+
+		$rememberme = false;
+		if ( isset( $_REQUEST['rememberme'] ) && $_REQUEST['rememberme'] ) {
+			$rememberme = true;
+		}
+
+		wp_set_auth_cookie( $user->ID, $rememberme );
+
+		// Must be global because that's how login_header() uses it.
+		global $interim_login;
+		$interim_login = isset( $_REQUEST['interim-login'] ); // WPCS: override ok.
+
+		if ( $interim_login ) {
+			$customize_login = isset( $_REQUEST['customize-login'] );
+			if ( $customize_login ) {
+				wp_enqueue_script( 'customize-base' );
+			}
+			$message       = '<p class="message">' . __( 'You have logged in successfully.', 'two-factor' ) . '</p>';
+			$interim_login = 'success'; // WPCS: override ok.
+			login_header( '', $message ); ?>
+			</div>
+			<?php
+			/** This action is documented in wp-login.php */
+			do_action( 'login_footer' ); ?>
+			<?php if ( $customize_login ) : ?>
+				<script type="text/javascript">setTimeout( function(){ new wp.customize.Messenger({ url: '<?php echo wp_customize_url(); /* WPCS: XSS OK. */ ?>', channel: 'login' }).send('login') }, 1000 );</script>
+			<?php endif; ?>
+			</body></html>
+			<?php
+			exit;
+		}
+		$redirect_to = apply_filters( 'login_redirect', $_REQUEST['redirect_to'], $_REQUEST['redirect_to'], $user );
+		wp_safe_redirect( $redirect_to );
+
+		exit;
+	}
+
+	/**
+	 * Filter the columns on the Users admin screen.
+	 *
+	 * @param  array $columns Available columns.
+	 * @return array          Updated array of columns.
+	 */
+	public static function filter_manage_users_columns( array $columns ) {
+		$columns['two-factor'] = __( 'Two-Factor', 'two-factor' );
+		return $columns;
+	}
+
+	/**
+	 * Output the 2FA column data on the Users screen.
+	 *
+	 * @param  string $output      The column output.
+	 * @param  string $column_name The column ID.
+	 * @param  int    $user_id     The user ID.
+	 * @return string              The column output.
+	 */
+	public static function manage_users_custom_column( $output, $column_name, $user_id ) {
+
+		if ( 'two-factor' !== $column_name ) {
+			return $output;
+		}
+
+		if ( ! self::is_user_using_two_factor( $user_id ) ) {
+			return sprintf( '<span class="dashicons-before dashicons-no-alt">%s</span>', esc_html__( 'Disabled', 'two-factor' ) );
+		} else {
+			$provider = self::get_primary_provider_for_user( $user_id );
+			return esc_html( $provider->get_label() );
+		}
+
+	}
+
+	/**
+	 * Add user profile fields.
+	 *
+	 * This executes during the `show_user_profile` & `edit_user_profile` actions.
+	 *
+	 * @since 0.1-dev
+	 *
+	 * @param WP_User $user WP_User object of the logged-in user.
+	 */
+	public static function user_two_factor_options( $user ) {
+		wp_enqueue_style( 'user-edit-2fa', plugins_url( 'user-edit.css', __FILE__ ) );
+
+		$enabled_providers = array_keys( self::get_available_providers_for_user( $user ) );
+		$primary_provider = self::get_primary_provider_for_user( $user->ID );
+
+		if ( ! empty( $primary_provider ) && is_object( $primary_provider ) ) {
+			$primary_provider_key = get_class( $primary_provider );
+		} else {
+			$primary_provider_key = null;
+		}
+
+		wp_nonce_field( 'user_two_factor_options', '_nonce_user_two_factor_options', false );
+
+		?>
+		<input type="hidden" name="<?php echo esc_attr( self::ENABLED_PROVIDERS_USER_META_KEY ); ?>[]" value="<?php /* Dummy input so $_POST value is passed when no providers are enabled. */ ?>" />
+		<table class="form-table" id="two-factor-options">
+			<tr>
+				<th>
+					<?php esc_html_e( 'Two-Factor Options', 'two-factor' ); ?>
+				</th>
+				<td>
+					<table class="two-factor-methods-table">
+						<thead>
+							<tr>
+								<th class="col-enabled" scope="col"><?php esc_html_e( 'Enabled', 'two-factor' ); ?></th>
+								<th class="col-primary" scope="col"><?php esc_html_e( 'Primary', 'two-factor' ); ?></th>
+								<th class="col-name" scope="col"><?php esc_html_e( 'Name', 'two-factor' ); ?></th>
+							</tr>
+						</thead>
+						<tbody>
+						<?php foreach ( self::get_providers() as $class => $object ) : ?>
+							<tr>
+								<th scope="row"><input type="checkbox" name="<?php echo esc_attr( self::ENABLED_PROVIDERS_USER_META_KEY ); ?>[]" value="<?php echo esc_attr( $class ); ?>" <?php checked( in_array( $class, $enabled_providers ) ); ?> /></th>
+								<th scope="row"><input type="radio" name="<?php echo esc_attr( self::PROVIDER_USER_META_KEY ); ?>" value="<?php echo esc_attr( $class ); ?>" <?php checked( $class, $primary_provider_key ); ?> /></th>
+								<td>
+									<?php $object->print_label(); ?>
+									<?php do_action( 'two-factor-user-options-' . $class, $user ); ?>
+								</td>
+							</tr>
+						<?php endforeach; ?>
+						</tbody>
+					</table>
+				</td>
+			</tr>
+		</table>
+		<?php
+		/**
+		 * Fires after the Two Factor methods table.
+		 *
+		 * To be used by Two Factor methods to add settings UI.
+		 *
+		 * @since 0.1-dev
+		 */
+		do_action( 'show_user_security_settings', $user );
+	}
+
+	/**
+	 * Update the user meta value.
+	 *
+	 * This executes during the `personal_options_update` & `edit_user_profile_update` actions.
+	 *
+	 * @since 0.1-dev
+	 *
+	 * @param int $user_id User ID.
+	 */
+	public static function user_two_factor_options_update( $user_id ) {
+		if ( isset( $_POST['_nonce_user_two_factor_options'] ) ) {
+			check_admin_referer( 'user_two_factor_options', '_nonce_user_two_factor_options' );
+
+			if ( ! isset( $_POST[ self::ENABLED_PROVIDERS_USER_META_KEY ] ) ||
+					! is_array( $_POST[ self::ENABLED_PROVIDERS_USER_META_KEY ] ) ) {
+				return;
+			}
+
+			$providers = self::get_providers();
+
+			$enabled_providers = $_POST[ self::ENABLED_PROVIDERS_USER_META_KEY ];
+
+			// Enable only the available providers.
+			$enabled_providers = array_intersect( $enabled_providers, array_keys( $providers ) );
+			update_user_meta( $user_id, self::ENABLED_PROVIDERS_USER_META_KEY, $enabled_providers );
+
+			// Primary provider must be enabled.
+			$new_provider = isset( $_POST[ self::PROVIDER_USER_META_KEY ] ) ? $_POST[ self::PROVIDER_USER_META_KEY ] : '';
+			if ( ! empty( $new_provider ) && in_array( $new_provider, $enabled_providers, true ) ) {
+				update_user_meta( $user_id, self::PROVIDER_USER_META_KEY, $new_provider );
+			}
+		}
+	}
+}
diff --git a/wp-content/plugins/two-factor/includes/Google/u2f-api.js b/wp-content/plugins/two-factor/includes/Google/u2f-api.js
new file mode 100644
index 0000000000000000000000000000000000000000..9244d14e74066eda7e6ad1d9912efbfaf540aad9
--- /dev/null
+++ b/wp-content/plugins/two-factor/includes/Google/u2f-api.js
@@ -0,0 +1,748 @@
+//Copyright 2014-2015 Google Inc. All rights reserved.
+
+//Use of this source code is governed by a BSD-style
+//license that can be found in the LICENSE file or at
+//https://developers.google.com/open-source/licenses/bsd
+
+/**
+ * @fileoverview The U2F api.
+ */
+'use strict';
+
+
+/**
+ * Namespace for the U2F api.
+ * @type {Object}
+ */
+var u2f = u2f || {};
+
+/**
+ * FIDO U2F Javascript API Version
+ * @number
+ */
+var js_api_version;
+
+/**
+ * The U2F extension id
+ * @const {string}
+ */
+// The Chrome packaged app extension ID.
+// Uncomment this if you want to deploy a server instance that uses
+// the package Chrome app and does not require installing the U2F Chrome extension.
+ u2f.EXTENSION_ID = 'kmendfapggjehodndflmmgagdbamhnfd';
+// The U2F Chrome extension ID.
+// Uncomment this if you want to deploy a server instance that uses
+// the U2F Chrome extension to authenticate.
+// u2f.EXTENSION_ID = 'pfboblefjcgdjicmnffhdgionmgcdmne';
+
+
+/**
+ * Message types for messsages to/from the extension
+ * @const
+ * @enum {string}
+ */
+u2f.MessageTypes = {
+    'U2F_REGISTER_REQUEST': 'u2f_register_request',
+    'U2F_REGISTER_RESPONSE': 'u2f_register_response',
+    'U2F_SIGN_REQUEST': 'u2f_sign_request',
+    'U2F_SIGN_RESPONSE': 'u2f_sign_response',
+    'U2F_GET_API_VERSION_REQUEST': 'u2f_get_api_version_request',
+    'U2F_GET_API_VERSION_RESPONSE': 'u2f_get_api_version_response'
+};
+
+
+/**
+ * Response status codes
+ * @const
+ * @enum {number}
+ */
+u2f.ErrorCodes = {
+    'OK': 0,
+    'OTHER_ERROR': 1,
+    'BAD_REQUEST': 2,
+    'CONFIGURATION_UNSUPPORTED': 3,
+    'DEVICE_INELIGIBLE': 4,
+    'TIMEOUT': 5
+};
+
+
+/**
+ * A message for registration requests
+ * @typedef {{
+ *   type: u2f.MessageTypes,
+ *   appId: ?string,
+ *   timeoutSeconds: ?number,
+ *   requestId: ?number
+ * }}
+ */
+u2f.U2fRequest;
+
+
+/**
+ * A message for registration responses
+ * @typedef {{
+ *   type: u2f.MessageTypes,
+ *   responseData: (u2f.Error | u2f.RegisterResponse | u2f.SignResponse),
+ *   requestId: ?number
+ * }}
+ */
+u2f.U2fResponse;
+
+
+/**
+ * An error object for responses
+ * @typedef {{
+ *   errorCode: u2f.ErrorCodes,
+ *   errorMessage: ?string
+ * }}
+ */
+u2f.Error;
+
+/**
+ * Data object for a single sign request.
+ * @typedef {enum {BLUETOOTH_RADIO, BLUETOOTH_LOW_ENERGY, USB, NFC}}
+ */
+u2f.Transport;
+
+
+/**
+ * Data object for a single sign request.
+ * @typedef {Array<u2f.Transport>}
+ */
+u2f.Transports;
+
+/**
+ * Data object for a single sign request.
+ * @typedef {{
+ *   version: string,
+ *   challenge: string,
+ *   keyHandle: string,
+ *   appId: string
+ * }}
+ */
+u2f.SignRequest;
+
+
+/**
+ * Data object for a sign response.
+ * @typedef {{
+ *   keyHandle: string,
+ *   signatureData: string,
+ *   clientData: string
+ * }}
+ */
+u2f.SignResponse;
+
+
+/**
+ * Data object for a registration request.
+ * @typedef {{
+ *   version: string,
+ *   challenge: string
+ * }}
+ */
+u2f.RegisterRequest;
+
+
+/**
+ * Data object for a registration response.
+ * @typedef {{
+ *   version: string,
+ *   keyHandle: string,
+ *   transports: Transports,
+ *   appId: string
+ * }}
+ */
+u2f.RegisterResponse;
+
+
+/**
+ * Data object for a registered key.
+ * @typedef {{
+ *   version: string,
+ *   keyHandle: string,
+ *   transports: ?Transports,
+ *   appId: ?string
+ * }}
+ */
+u2f.RegisteredKey;
+
+
+/**
+ * Data object for a get API register response.
+ * @typedef {{
+ *   js_api_version: number
+ * }}
+ */
+u2f.GetJsApiVersionResponse;
+
+
+//Low level MessagePort API support
+
+/**
+ * Sets up a MessagePort to the U2F extension using the
+ * available mechanisms.
+ * @param {function((MessagePort|u2f.WrappedChromeRuntimePort_))} callback
+ */
+u2f.getMessagePort = function(callback) {
+  if (typeof chrome != 'undefined' && chrome.runtime) {
+    // The actual message here does not matter, but we need to get a reply
+    // for the callback to run. Thus, send an empty signature request
+    // in order to get a failure response.
+    var msg = {
+        type: u2f.MessageTypes.U2F_SIGN_REQUEST,
+        signRequests: []
+    };
+    chrome.runtime.sendMessage(u2f.EXTENSION_ID, msg, function() {
+      if (!chrome.runtime.lastError) {
+        // We are on a whitelisted origin and can talk directly
+        // with the extension.
+        u2f.getChromeRuntimePort_(callback);
+      } else {
+        // chrome.runtime was available, but we couldn't message
+        // the extension directly, use iframe
+        u2f.getIframePort_(callback);
+      }
+    });
+  } else if (u2f.isAndroidChrome_()) {
+    u2f.getAuthenticatorPort_(callback);
+  } else if (u2f.isIosChrome_()) {
+    u2f.getIosPort_(callback);
+  } else {
+    // chrome.runtime was not available at all, which is normal
+    // when this origin doesn't have access to any extensions.
+    u2f.getIframePort_(callback);
+  }
+};
+
+/**
+ * Detect chrome running on android based on the browser's useragent.
+ * @private
+ */
+u2f.isAndroidChrome_ = function() {
+  var userAgent = navigator.userAgent;
+  return userAgent.indexOf('Chrome') != -1 &&
+  userAgent.indexOf('Android') != -1;
+};
+
+/**
+ * Detect chrome running on iOS based on the browser's platform.
+ * @private
+ */
+u2f.isIosChrome_ = function() {
+  return ["iPhone", "iPad", "iPod"].indexOf(navigator.platform) > -1;
+};
+
+/**
+ * Connects directly to the extension via chrome.runtime.connect.
+ * @param {function(u2f.WrappedChromeRuntimePort_)} callback
+ * @private
+ */
+u2f.getChromeRuntimePort_ = function(callback) {
+  var port = chrome.runtime.connect(u2f.EXTENSION_ID,
+      {'includeTlsChannelId': true});
+  setTimeout(function() {
+    callback(new u2f.WrappedChromeRuntimePort_(port));
+  }, 0);
+};
+
+/**
+ * Return a 'port' abstraction to the Authenticator app.
+ * @param {function(u2f.WrappedAuthenticatorPort_)} callback
+ * @private
+ */
+u2f.getAuthenticatorPort_ = function(callback) {
+  setTimeout(function() {
+    callback(new u2f.WrappedAuthenticatorPort_());
+  }, 0);
+};
+
+/**
+ * Return a 'port' abstraction to the iOS client app.
+ * @param {function(u2f.WrappedIosPort_)} callback
+ * @private
+ */
+u2f.getIosPort_ = function(callback) {
+  setTimeout(function() {
+    callback(new u2f.WrappedIosPort_());
+  }, 0);
+};
+
+/**
+ * A wrapper for chrome.runtime.Port that is compatible with MessagePort.
+ * @param {Port} port
+ * @constructor
+ * @private
+ */
+u2f.WrappedChromeRuntimePort_ = function(port) {
+  this.port_ = port;
+};
+
+/**
+ * Format and return a sign request compliant with the JS API version supported by the extension.
+ * @param {Array<u2f.SignRequest>} signRequests
+ * @param {number} timeoutSeconds
+ * @param {number} reqId
+ * @return {Object}
+ */
+u2f.formatSignRequest_ =
+  function(appId, challenge, registeredKeys, timeoutSeconds, reqId) {
+  if (js_api_version === undefined || js_api_version < 1.1) {
+    // Adapt request to the 1.0 JS API
+    var signRequests = [];
+    for (var i = 0; i < registeredKeys.length; i++) {
+      signRequests[i] = {
+          version: registeredKeys[i].version,
+          challenge: challenge,
+          keyHandle: registeredKeys[i].keyHandle,
+          appId: appId
+      };
+    }
+    return {
+      type: u2f.MessageTypes.U2F_SIGN_REQUEST,
+      signRequests: signRequests,
+      timeoutSeconds: timeoutSeconds,
+      requestId: reqId
+    };
+  }
+  // JS 1.1 API
+  return {
+    type: u2f.MessageTypes.U2F_SIGN_REQUEST,
+    appId: appId,
+    challenge: challenge,
+    registeredKeys: registeredKeys,
+    timeoutSeconds: timeoutSeconds,
+    requestId: reqId
+  };
+};
+
+/**
+ * Format and return a register request compliant with the JS API version supported by the extension..
+ * @param {Array<u2f.SignRequest>} signRequests
+ * @param {Array<u2f.RegisterRequest>} signRequests
+ * @param {number} timeoutSeconds
+ * @param {number} reqId
+ * @return {Object}
+ */
+u2f.formatRegisterRequest_ =
+  function(appId, registeredKeys, registerRequests, timeoutSeconds, reqId) {
+  if (js_api_version === undefined || js_api_version < 1.1) {
+    // Adapt request to the 1.0 JS API
+    for (var i = 0; i < registerRequests.length; i++) {
+      registerRequests[i].appId = appId;
+    }
+    var signRequests = [];
+    for (var i = 0; i < registeredKeys.length; i++) {
+      signRequests[i] = {
+          version: registeredKeys[i].version,
+          challenge: registerRequests[0],
+          keyHandle: registeredKeys[i].keyHandle,
+          appId: appId
+      };
+    }
+    return {
+      type: u2f.MessageTypes.U2F_REGISTER_REQUEST,
+      signRequests: signRequests,
+      registerRequests: registerRequests,
+      timeoutSeconds: timeoutSeconds,
+      requestId: reqId
+    };
+  }
+  // JS 1.1 API
+  return {
+    type: u2f.MessageTypes.U2F_REGISTER_REQUEST,
+    appId: appId,
+    registerRequests: registerRequests,
+    registeredKeys: registeredKeys,
+    timeoutSeconds: timeoutSeconds,
+    requestId: reqId
+  };
+};
+
+
+/**
+ * Posts a message on the underlying channel.
+ * @param {Object} message
+ */
+u2f.WrappedChromeRuntimePort_.prototype.postMessage = function(message) {
+  this.port_.postMessage(message);
+};
+
+
+/**
+ * Emulates the HTML 5 addEventListener interface. Works only for the
+ * onmessage event, which is hooked up to the chrome.runtime.Port.onMessage.
+ * @param {string} eventName
+ * @param {function({data: Object})} handler
+ */
+u2f.WrappedChromeRuntimePort_.prototype.addEventListener =
+    function(eventName, handler) {
+  var name = eventName.toLowerCase();
+  if (name == 'message' || name == 'onmessage') {
+    this.port_.onMessage.addListener(function(message) {
+      // Emulate a minimal MessageEvent object
+      handler({'data': message});
+    });
+  } else {
+    console.error('WrappedChromeRuntimePort only supports onMessage');
+  }
+};
+
+/**
+ * Wrap the Authenticator app with a MessagePort interface.
+ * @constructor
+ * @private
+ */
+u2f.WrappedAuthenticatorPort_ = function() {
+  this.requestId_ = -1;
+  this.requestObject_ = null;
+}
+
+/**
+ * Launch the Authenticator intent.
+ * @param {Object} message
+ */
+u2f.WrappedAuthenticatorPort_.prototype.postMessage = function(message) {
+  var intentUrl =
+    u2f.WrappedAuthenticatorPort_.INTENT_URL_BASE_ +
+    ';S.request=' + encodeURIComponent(JSON.stringify(message)) +
+    ';end';
+  document.location = intentUrl;
+};
+
+/**
+ * Tells what type of port this is.
+ * @return {String} port type
+ */
+u2f.WrappedAuthenticatorPort_.prototype.getPortType = function() {
+  return "WrappedAuthenticatorPort_";
+};
+
+
+/**
+ * Emulates the HTML 5 addEventListener interface.
+ * @param {string} eventName
+ * @param {function({data: Object})} handler
+ */
+u2f.WrappedAuthenticatorPort_.prototype.addEventListener = function(eventName, handler) {
+  var name = eventName.toLowerCase();
+  if (name == 'message') {
+    var self = this;
+    /* Register a callback to that executes when
+     * chrome injects the response. */
+    window.addEventListener(
+        'message', self.onRequestUpdate_.bind(self, handler), false);
+  } else {
+    console.error('WrappedAuthenticatorPort only supports message');
+  }
+};
+
+/**
+ * Callback invoked  when a response is received from the Authenticator.
+ * @param function({data: Object}) callback
+ * @param {Object} message message Object
+ */
+u2f.WrappedAuthenticatorPort_.prototype.onRequestUpdate_ =
+    function(callback, message) {
+  var messageObject = JSON.parse(message.data);
+  var intentUrl = messageObject['intentURL'];
+
+  var errorCode = messageObject['errorCode'];
+  var responseObject = null;
+  if (messageObject.hasOwnProperty('data')) {
+    responseObject = /** @type {Object} */ (
+        JSON.parse(messageObject['data']));
+  }
+
+  callback({'data': responseObject});
+};
+
+/**
+ * Base URL for intents to Authenticator.
+ * @const
+ * @private
+ */
+u2f.WrappedAuthenticatorPort_.INTENT_URL_BASE_ =
+  'intent:#Intent;action=com.google.android.apps.authenticator.AUTHENTICATE';
+
+/**
+ * Wrap the iOS client app with a MessagePort interface.
+ * @constructor
+ * @private
+ */
+u2f.WrappedIosPort_ = function() {};
+
+/**
+ * Launch the iOS client app request
+ * @param {Object} message
+ */
+u2f.WrappedIosPort_.prototype.postMessage = function(message) {
+  var str = JSON.stringify(message);
+  var url = "u2f://auth?" + encodeURI(str);
+  location.replace(url);
+};
+
+/**
+ * Tells what type of port this is.
+ * @return {String} port type
+ */
+u2f.WrappedIosPort_.prototype.getPortType = function() {
+  return "WrappedIosPort_";
+};
+
+/**
+ * Emulates the HTML 5 addEventListener interface.
+ * @param {string} eventName
+ * @param {function({data: Object})} handler
+ */
+u2f.WrappedIosPort_.prototype.addEventListener = function(eventName, handler) {
+  var name = eventName.toLowerCase();
+  if (name !== 'message') {
+    console.error('WrappedIosPort only supports message');
+  }
+};
+
+/**
+ * Sets up an embedded trampoline iframe, sourced from the extension.
+ * @param {function(MessagePort)} callback
+ * @private
+ */
+u2f.getIframePort_ = function(callback) {
+  // Create the iframe
+  var iframeOrigin = 'chrome-extension://' + u2f.EXTENSION_ID;
+  var iframe = document.createElement('iframe');
+  iframe.src = iframeOrigin + '/u2f-comms.html';
+  iframe.setAttribute('style', 'display:none');
+  document.body.appendChild(iframe);
+
+  var channel = new MessageChannel();
+  var ready = function(message) {
+    if (message.data == 'ready') {
+      channel.port1.removeEventListener('message', ready);
+      callback(channel.port1);
+    } else {
+      console.error('First event on iframe port was not "ready"');
+    }
+  };
+  channel.port1.addEventListener('message', ready);
+  channel.port1.start();
+
+  iframe.addEventListener('load', function() {
+    // Deliver the port to the iframe and initialize
+    iframe.contentWindow.postMessage('init', iframeOrigin, [channel.port2]);
+  });
+};
+
+
+//High-level JS API
+
+/**
+ * Default extension response timeout in seconds.
+ * @const
+ */
+u2f.EXTENSION_TIMEOUT_SEC = 30;
+
+/**
+ * A singleton instance for a MessagePort to the extension.
+ * @type {MessagePort|u2f.WrappedChromeRuntimePort_}
+ * @private
+ */
+u2f.port_ = null;
+
+/**
+ * Callbacks waiting for a port
+ * @type {Array<function((MessagePort|u2f.WrappedChromeRuntimePort_))>}
+ * @private
+ */
+u2f.waitingForPort_ = [];
+
+/**
+ * A counter for requestIds.
+ * @type {number}
+ * @private
+ */
+u2f.reqCounter_ = 0;
+
+/**
+ * A map from requestIds to client callbacks
+ * @type {Object.<number,(function((u2f.Error|u2f.RegisterResponse))
+ *                       |function((u2f.Error|u2f.SignResponse)))>}
+ * @private
+ */
+u2f.callbackMap_ = {};
+
+/**
+ * Creates or retrieves the MessagePort singleton to use.
+ * @param {function((MessagePort|u2f.WrappedChromeRuntimePort_))} callback
+ * @private
+ */
+u2f.getPortSingleton_ = function(callback) {
+  if (u2f.port_) {
+    callback(u2f.port_);
+  } else {
+    if (u2f.waitingForPort_.length == 0) {
+      u2f.getMessagePort(function(port) {
+        u2f.port_ = port;
+        u2f.port_.addEventListener('message',
+            /** @type {function(Event)} */ (u2f.responseHandler_));
+
+        // Careful, here be async callbacks. Maybe.
+        while (u2f.waitingForPort_.length)
+          u2f.waitingForPort_.shift()(u2f.port_);
+      });
+    }
+    u2f.waitingForPort_.push(callback);
+  }
+};
+
+/**
+ * Handles response messages from the extension.
+ * @param {MessageEvent.<u2f.Response>} message
+ * @private
+ */
+u2f.responseHandler_ = function(message) {
+  var response = message.data;
+  var reqId = response['requestId'];
+  if (!reqId || !u2f.callbackMap_[reqId]) {
+    console.error('Unknown or missing requestId in response.');
+    return;
+  }
+  var cb = u2f.callbackMap_[reqId];
+  delete u2f.callbackMap_[reqId];
+  cb(response['responseData']);
+};
+
+/**
+ * Dispatches an array of sign requests to available U2F tokens.
+ * If the JS API version supported by the extension is unknown, it first sends a
+ * message to the extension to find out the supported API version and then it sends
+ * the sign request.
+ * @param {string=} appId
+ * @param {string=} challenge
+ * @param {Array<u2f.RegisteredKey>} registeredKeys
+ * @param {function((u2f.Error|u2f.SignResponse))} callback
+ * @param {number=} opt_timeoutSeconds
+ */
+u2f.sign = function(appId, challenge, registeredKeys, callback, opt_timeoutSeconds) {
+  if (js_api_version === undefined) {
+    // Send a message to get the extension to JS API version, then send the actual sign request.
+    u2f.getApiVersion(
+        function (response) {
+          js_api_version = response['js_api_version'] === undefined ? 0 : response['js_api_version'];
+          console.log("Extension JS API Version: ", js_api_version);
+          u2f.sendSignRequest(appId, challenge, registeredKeys, callback, opt_timeoutSeconds);
+        });
+  } else {
+    // We know the JS API version. Send the actual sign request in the supported API version.
+    u2f.sendSignRequest(appId, challenge, registeredKeys, callback, opt_timeoutSeconds);
+  }
+};
+
+/**
+ * Dispatches an array of sign requests to available U2F tokens.
+ * @param {string=} appId
+ * @param {string=} challenge
+ * @param {Array<u2f.RegisteredKey>} registeredKeys
+ * @param {function((u2f.Error|u2f.SignResponse))} callback
+ * @param {number=} opt_timeoutSeconds
+ */
+u2f.sendSignRequest = function(appId, challenge, registeredKeys, callback, opt_timeoutSeconds) {
+  u2f.getPortSingleton_(function(port) {
+    var reqId = ++u2f.reqCounter_;
+    u2f.callbackMap_[reqId] = callback;
+    var timeoutSeconds = (typeof opt_timeoutSeconds !== 'undefined' ?
+        opt_timeoutSeconds : u2f.EXTENSION_TIMEOUT_SEC);
+    var req = u2f.formatSignRequest_(appId, challenge, registeredKeys, timeoutSeconds, reqId);
+    port.postMessage(req);
+  });
+};
+
+/**
+ * Dispatches register requests to available U2F tokens. An array of sign
+ * requests identifies already registered tokens.
+ * If the JS API version supported by the extension is unknown, it first sends a
+ * message to the extension to find out the supported API version and then it sends
+ * the register request.
+ * @param {string=} appId
+ * @param {Array<u2f.RegisterRequest>} registerRequests
+ * @param {Array<u2f.RegisteredKey>} registeredKeys
+ * @param {function((u2f.Error|u2f.RegisterResponse))} callback
+ * @param {number=} opt_timeoutSeconds
+ */
+u2f.register = function(appId, registerRequests, registeredKeys, callback, opt_timeoutSeconds) {
+  if (js_api_version === undefined) {
+    // Send a message to get the extension to JS API version, then send the actual register request.
+    u2f.getApiVersion(
+        function (response) {
+          js_api_version = response['js_api_version'] === undefined ? 0: response['js_api_version'];
+          console.log("Extension JS API Version: ", js_api_version);
+          u2f.sendRegisterRequest(appId, registerRequests, registeredKeys,
+              callback, opt_timeoutSeconds);
+        });
+  } else {
+    // We know the JS API version. Send the actual register request in the supported API version.
+    u2f.sendRegisterRequest(appId, registerRequests, registeredKeys,
+        callback, opt_timeoutSeconds);
+  }
+};
+
+/**
+ * Dispatches register requests to available U2F tokens. An array of sign
+ * requests identifies already registered tokens.
+ * @param {string=} appId
+ * @param {Array<u2f.RegisterRequest>} registerRequests
+ * @param {Array<u2f.RegisteredKey>} registeredKeys
+ * @param {function((u2f.Error|u2f.RegisterResponse))} callback
+ * @param {number=} opt_timeoutSeconds
+ */
+u2f.sendRegisterRequest = function(appId, registerRequests, registeredKeys, callback, opt_timeoutSeconds) {
+  u2f.getPortSingleton_(function(port) {
+    var reqId = ++u2f.reqCounter_;
+    u2f.callbackMap_[reqId] = callback;
+    var timeoutSeconds = (typeof opt_timeoutSeconds !== 'undefined' ?
+        opt_timeoutSeconds : u2f.EXTENSION_TIMEOUT_SEC);
+    var req = u2f.formatRegisterRequest_(
+        appId, registeredKeys, registerRequests, timeoutSeconds, reqId);
+    port.postMessage(req);
+  });
+};
+
+
+/**
+ * Dispatches a message to the extension to find out the supported
+ * JS API version.
+ * If the user is on a mobile phone and is thus using Google Authenticator instead
+ * of the Chrome extension, don't send the request and simply return 0.
+ * @param {function((u2f.Error|u2f.GetJsApiVersionResponse))} callback
+ * @param {number=} opt_timeoutSeconds
+ */
+u2f.getApiVersion = function(callback, opt_timeoutSeconds) {
+ u2f.getPortSingleton_(function(port) {
+   // If we are using Android Google Authenticator or iOS client app,
+   // do not fire an intent to ask which JS API version to use.
+   if (port.getPortType) {
+     var apiVersion;
+     switch (port.getPortType()) {
+       case 'WrappedIosPort_':
+       case 'WrappedAuthenticatorPort_':
+         apiVersion = 1.1;
+         break;
+
+       default:
+         apiVersion = 0;
+         break;
+     }
+     callback({ 'js_api_version': apiVersion });
+     return;
+   }
+    var reqId = ++u2f.reqCounter_;
+    u2f.callbackMap_[reqId] = callback;
+    var req = {
+      type: u2f.MessageTypes.U2F_GET_API_VERSION_REQUEST,
+      timeoutSeconds: (typeof opt_timeoutSeconds !== 'undefined' ?
+          opt_timeoutSeconds : u2f.EXTENSION_TIMEOUT_SEC),
+      requestId: reqId
+    };
+    port.postMessage(req);
+  });
+};
diff --git a/wp-content/plugins/two-factor/includes/Yubico/U2F.php b/wp-content/plugins/two-factor/includes/Yubico/U2F.php
new file mode 100644
index 0000000000000000000000000000000000000000..a11c78fbac34bad29e021822386fa169bd9fbc6c
--- /dev/null
+++ b/wp-content/plugins/two-factor/includes/Yubico/U2F.php
@@ -0,0 +1,507 @@
+<?php
+/* Copyright (c) 2014 Yubico AB
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *   * Redistributions in binary form must reproduce the above
+ *     copyright notice, this list of conditions and the following
+ *     disclaimer in the documentation and/or other materials provided
+ *     with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace u2flib_server;
+
+/** Constant for the version of the u2f protocol */
+const U2F_VERSION = "U2F_V2";
+
+/** Error for the authentication message not matching any outstanding
+ * authentication request */
+const ERR_NO_MATCHING_REQUEST = 1;
+
+/** Error for the authentication message not matching any registration */
+const ERR_NO_MATCHING_REGISTRATION = 2;
+
+/** Error for the signature on the authentication message not verifying with
+ * the correct key */
+const ERR_AUTHENTICATION_FAILURE = 3;
+
+/** Error for the challenge in the registration message not matching the
+ * registration challenge */
+const ERR_UNMATCHED_CHALLENGE = 4;
+
+/** Error for the attestation signature on the registration message not
+ * verifying */
+const ERR_ATTESTATION_SIGNATURE = 5;
+
+/** Error for the attestation verification not verifying */
+const ERR_ATTESTATION_VERIFICATION = 6;
+
+/** Error for not getting good random from the system */
+const ERR_BAD_RANDOM = 7;
+
+/** Error when the counter is lower than expected */
+const ERR_COUNTER_TOO_LOW = 8;
+
+/** Error decoding public key */
+const ERR_PUBKEY_DECODE = 9;
+
+/** Error user-agent returned error */
+const ERR_BAD_UA_RETURNING = 10;
+
+/** Error old OpenSSL version */
+const ERR_OLD_OPENSSL = 11;
+
+/** @internal */
+const PUBKEY_LEN = 65;
+
+class U2F
+{
+    /** @var string  */
+    private $appId;
+
+    /** @var null|string */
+    private $attestDir;
+
+    /** @internal */
+    private $FIXCERTS = array(
+        '349bca1031f8c82c4ceca38b9cebf1a69df9fb3b94eed99eb3fb9aa3822d26e8',
+        'dd574527df608e47ae45fbba75a2afdd5c20fd94a02419381813cd55a2a3398f',
+        '1d8764f0f7cd1352df6150045c8f638e517270e8b5dda1c63ade9c2280240cae',
+        'd0edc9a91a1677435a953390865d208c55b3183c6759c9b5a7ff494c322558eb',
+        '6073c436dcd064a48127ddbf6032ac1a66fd59a0c24434f070d4e564c124c897',
+        'ca993121846c464d666096d35f13bf44c1b05af205f9b4a1e00cf6cc10c5e511'
+    );
+
+    /**
+     * @param string $appId Application id for the running application
+     * @param string|null $attestDir Directory where trusted attestation roots may be found
+     * @throws Error If OpenSSL older than 1.0.0 is used
+     */
+    public function __construct($appId, $attestDir = null)
+    {
+        if(OPENSSL_VERSION_NUMBER < 0x10000000) {
+            throw new Error('OpenSSL has to be at least version 1.0.0, this is ' . OPENSSL_VERSION_TEXT, ERR_OLD_OPENSSL);
+        }
+        $this->appId = $appId;
+        $this->attestDir = $attestDir;
+    }
+
+    /**
+     * Called to get a registration request to send to a user.
+     * Returns an array of one registration request and a array of sign requests.
+     *
+     * @param array $registrations List of current registrations for this
+     * user, to prevent the user from registering the same authenticator several
+     * times.
+     * @return array An array of two elements, the first containing a
+     * RegisterRequest the second being an array of SignRequest
+     * @throws Error
+     */
+    public function getRegisterData(array $registrations = array())
+    {
+        $challenge = $this->createChallenge();
+        $request = new RegisterRequest($challenge, $this->appId);
+        $signs = $this->getAuthenticateData($registrations);
+        return array($request, $signs);
+    }
+
+    /**
+     * Called to verify and unpack a registration message.
+     *
+     * @param RegisterRequest $request this is a reply to
+     * @param object $response response from a user
+     * @param bool $includeCert set to true if the attestation certificate should be
+     * included in the returned Registration object
+     * @return Registration
+     * @throws Error
+     */
+    public function doRegister($request, $response, $includeCert = true)
+    {
+        if( !is_object( $request ) ) {
+            throw new \InvalidArgumentException('$request of doRegister() method only accepts object.');
+        }
+
+        if( !is_object( $response ) ) {
+            throw new \InvalidArgumentException('$response of doRegister() method only accepts object.');
+        }
+
+        if( property_exists( $response, 'errorCode') && $response->errorCode !== 0 ) {
+            throw new Error('User-agent returned error. Error code: ' . $response->errorCode, ERR_BAD_UA_RETURNING );
+        }
+
+        if( !is_bool( $includeCert ) ) {
+            throw new \InvalidArgumentException('$include_cert of doRegister() method only accepts boolean.');
+        }
+
+        $rawReg = $this->base64u_decode($response->registrationData);
+        $regData = array_values(unpack('C*', $rawReg));
+        $clientData = $this->base64u_decode($response->clientData);
+        $cli = json_decode($clientData);
+
+        if($cli->challenge !== $request->challenge) {
+            throw new Error('Registration challenge does not match', ERR_UNMATCHED_CHALLENGE );
+        }
+
+        $registration = new Registration();
+        $offs = 1;
+        $pubKey = substr($rawReg, $offs, PUBKEY_LEN);
+        $offs += PUBKEY_LEN;
+        // decode the pubKey to make sure it's good
+        $tmpKey = $this->pubkey_to_pem($pubKey);
+        if($tmpKey === null) {
+            throw new Error('Decoding of public key failed', ERR_PUBKEY_DECODE );
+        }
+        $registration->publicKey = base64_encode($pubKey);
+        $khLen = $regData[$offs++];
+        $kh = substr($rawReg, $offs, $khLen);
+        $offs += $khLen;
+        $registration->keyHandle = $this->base64u_encode($kh);
+
+        // length of certificate is stored in byte 3 and 4 (excluding the first 4 bytes)
+        $certLen = 4;
+        $certLen += ($regData[$offs + 2] << 8);
+        $certLen += $regData[$offs + 3];
+
+        $rawCert = $this->fixSignatureUnusedBits(substr($rawReg, $offs, $certLen));
+        $offs += $certLen;
+        $pemCert  = "-----BEGIN CERTIFICATE-----\r\n";
+        $pemCert .= chunk_split(base64_encode($rawCert), 64);
+        $pemCert .= "-----END CERTIFICATE-----";
+        if($includeCert) {
+            $registration->certificate = base64_encode($rawCert);
+        }
+        if($this->attestDir) {
+            if(openssl_x509_checkpurpose($pemCert, -1, $this->get_certs()) !== true) {
+                throw new Error('Attestation certificate can not be validated', ERR_ATTESTATION_VERIFICATION );
+            }
+        }
+
+        if(!openssl_pkey_get_public($pemCert)) {
+            throw new Error('Decoding of public key failed', ERR_PUBKEY_DECODE );
+        }
+        $signature = substr($rawReg, $offs);
+
+        $dataToVerify  = chr(0);
+        $dataToVerify .= hash('sha256', $request->appId, true);
+        $dataToVerify .= hash('sha256', $clientData, true);
+        $dataToVerify .= $kh;
+        $dataToVerify .= $pubKey;
+
+        if(openssl_verify($dataToVerify, $signature, $pemCert, 'sha256') === 1) {
+            return $registration;
+        } else {
+            throw new Error('Attestation signature does not match', ERR_ATTESTATION_SIGNATURE );
+        }
+    }
+
+    /**
+     * Called to get an authentication request.
+     *
+     * @param array $registrations An array of the registrations to create authentication requests for.
+     * @return array An array of SignRequest
+     * @throws Error
+     */
+    public function getAuthenticateData(array $registrations)
+    {
+        $sigs = array();
+        $challenge = $this->createChallenge();
+        foreach ($registrations as $reg) {
+            if( !is_object( $reg ) ) {
+                throw new \InvalidArgumentException('$registrations of getAuthenticateData() method only accepts array of object.');
+            }
+
+            $sig = new SignRequest();
+            $sig->appId = $this->appId;
+            $sig->keyHandle = $reg->keyHandle;
+            $sig->challenge = $challenge;
+            $sigs[] = $sig;
+        }
+        return $sigs;
+    }
+
+    /**
+     * Called to verify an authentication response
+     *
+     * @param array $requests An array of outstanding authentication requests
+     * @param array $registrations An array of current registrations
+     * @param object $response A response from the authenticator
+     * @return Registration
+     * @throws Error
+     *
+     * The Registration object returned on success contains an updated counter
+     * that should be saved for future authentications.
+     * If the Error returned is ERR_COUNTER_TOO_LOW this is an indication of
+     * token cloning or similar and appropriate action should be taken.
+     */
+    public function doAuthenticate(array $requests, array $registrations, $response)
+    {
+        if( !is_object( $response ) ) {
+            throw new \InvalidArgumentException('$response of doAuthenticate() method only accepts object.');
+        }
+
+        if( property_exists( $response, 'errorCode') && $response->errorCode !== 0 ) {
+            throw new Error('User-agent returned error. Error code: ' . $response->errorCode, ERR_BAD_UA_RETURNING );
+        }
+
+        /** @var object|null $req */
+        $req = null;
+
+        /** @var object|null $reg */
+        $reg = null;
+
+        $clientData = $this->base64u_decode($response->clientData);
+        $decodedClient = json_decode($clientData);
+        foreach ($requests as $req) {
+            if( !is_object( $req ) ) {
+                throw new \InvalidArgumentException('$requests of doAuthenticate() method only accepts array of object.');
+            }
+
+            if($req->keyHandle === $response->keyHandle && $req->challenge === $decodedClient->challenge) {
+                break;
+            }
+
+            $req = null;
+        }
+        if($req === null) {
+            throw new Error('No matching request found', ERR_NO_MATCHING_REQUEST );
+        }
+        foreach ($registrations as $reg) {
+            if( !is_object( $reg ) ) {
+                throw new \InvalidArgumentException('$registrations of doAuthenticate() method only accepts array of object.');
+            }
+
+            if($reg->keyHandle === $response->keyHandle) {
+                break;
+            }
+            $reg = null;
+        }
+        if($reg === null) {
+            throw new Error('No matching registration found', ERR_NO_MATCHING_REGISTRATION );
+        }
+        $pemKey = $this->pubkey_to_pem($this->base64u_decode($reg->publicKey));
+        if($pemKey === null) {
+            throw new Error('Decoding of public key failed', ERR_PUBKEY_DECODE );
+        }
+
+        $signData = $this->base64u_decode($response->signatureData);
+        $dataToVerify  = hash('sha256', $req->appId, true);
+        $dataToVerify .= substr($signData, 0, 5);
+        $dataToVerify .= hash('sha256', $clientData, true);
+        $signature = substr($signData, 5);
+
+        if(openssl_verify($dataToVerify, $signature, $pemKey, 'sha256') === 1) {
+            $ctr = unpack("Nctr", substr($signData, 1, 4));
+            $counter = $ctr['ctr'];
+            /* TODO: wrap-around should be handled somehow.. */
+            if($counter > $reg->counter) {
+                $reg->counter = $counter;
+                return $reg;
+            } else {
+                throw new Error('Counter too low.', ERR_COUNTER_TOO_LOW );
+            }
+        } else {
+            throw new Error('Authentication failed', ERR_AUTHENTICATION_FAILURE );
+        }
+    }
+
+    /**
+     * @return array
+     */
+    private function get_certs()
+    {
+        $files = array();
+        $dir = $this->attestDir;
+        if($dir && $handle = opendir($dir)) {
+            while(false !== ($entry = readdir($handle))) {
+                if(is_file("$dir/$entry")) {
+                    $files[] = "$dir/$entry";
+                }
+            }
+            closedir($handle);
+        }
+        return $files;
+    }
+
+    /**
+     * @param string $data
+     * @return string
+     */
+    private function base64u_encode($data)
+    {
+        return trim(strtr(base64_encode($data), '+/', '-_'), '=');
+    }
+
+    /**
+     * @param string $data
+     * @return string
+     */
+    private function base64u_decode($data)
+    {
+        return base64_decode(strtr($data, '-_', '+/'));
+    }
+
+    /**
+     * @param string $key
+     * @return null|string
+     */
+    private function pubkey_to_pem($key)
+    {
+        if(strlen($key) !== PUBKEY_LEN || $key[0] !== "\x04") {
+            return null;
+        }
+
+        /*
+         * Convert the public key to binary DER format first
+         * Using the ECC SubjectPublicKeyInfo OIDs from RFC 5480
+         *
+         *  SEQUENCE(2 elem)                        30 59
+         *   SEQUENCE(2 elem)                       30 13
+         *    OID1.2.840.10045.2.1 (id-ecPublicKey) 06 07 2a 86 48 ce 3d 02 01
+         *    OID1.2.840.10045.3.1.7 (secp256r1)    06 08 2a 86 48 ce 3d 03 01 07
+         *   BIT STRING(520 bit)                    03 42 ..key..
+         */
+        $der  = "\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01";
+        $der .= "\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07\x03\x42";
+        $der .= "\0".$key;
+
+        $pem  = "-----BEGIN PUBLIC KEY-----\r\n";
+        $pem .= chunk_split(base64_encode($der), 64);
+        $pem .= "-----END PUBLIC KEY-----";
+
+        return $pem;
+    }
+
+    /**
+     * @return string
+     * @throws Error
+     */
+    private function createChallenge()
+    {
+        $challenge = openssl_random_pseudo_bytes(32, $crypto_strong );
+        if( $crypto_strong !== true ) {
+            throw new Error('Unable to obtain a good source of randomness', ERR_BAD_RANDOM);
+        }
+
+        $challenge = $this->base64u_encode( $challenge );
+
+        return $challenge;
+    }
+
+    /**
+     * Fixes a certificate where the signature contains unused bits.
+     *
+     * @param string $cert
+     * @return mixed
+     */
+    private function fixSignatureUnusedBits($cert)
+    {
+        if(in_array(hash('sha256', $cert), $this->FIXCERTS)) {
+            $cert[strlen($cert) - 257] = "\0";
+        }
+        return $cert;
+    }
+}
+
+/**
+ * Class for building a registration request
+ *
+ * @package u2flib_server
+ */
+class RegisterRequest
+{
+    /** Protocol version */
+    public $version = U2F_VERSION;
+
+    /** Registration challenge */
+    public $challenge;
+
+    /** Application id */
+    public $appId;
+
+    /**
+     * @param string $challenge
+     * @param string $appId
+     * @internal
+     */
+    public function __construct($challenge, $appId)
+    {
+        $this->challenge = $challenge;
+        $this->appId = $appId;
+    }
+}
+
+/**
+ * Class for building up an authentication request
+ *
+ * @package u2flib_server
+ */
+class SignRequest
+{
+    /** Protocol version */
+    public $version = U2F_VERSION;
+
+    /** Authentication challenge */
+    public $challenge;
+
+    /** Key handle of a registered authenticator */
+    public $keyHandle;
+
+    /** Application id */
+    public $appId;
+}
+
+/**
+ * Class returned for successful registrations
+ *
+ * @package u2flib_server
+ */
+class Registration
+{
+    /** The key handle of the registered authenticator */
+    public $keyHandle;
+
+    /** The public key of the registered authenticator */
+    public $publicKey;
+
+    /** The attestation certificate of the registered authenticator */
+    public $certificate;
+
+    /** The counter associated with this registration */
+    public $counter = -1;
+}
+
+/**
+ * Error class, returned on errors
+ *
+ * @package u2flib_server
+ */
+class Error extends \Exception
+{
+    /**
+     * Override constructor and make message and code mandatory
+     * @param string $message
+     * @param int $code
+     * @param \Exception|null $previous
+     */
+    public function __construct($message, $code, \Exception $previous = null) {
+        parent::__construct($message, $code, $previous);
+    }
+}
diff --git a/wp-content/plugins/two-factor/includes/function.login-header.php b/wp-content/plugins/two-factor/includes/function.login-header.php
new file mode 100644
index 0000000000000000000000000000000000000000..647a0e6d94b9a220d64bfaad0dad0be6a0db261c
--- /dev/null
+++ b/wp-content/plugins/two-factor/includes/function.login-header.php
@@ -0,0 +1,227 @@
+<?php
+/**
+ * Extracted from wp-login.php since that file also loads WP core which we already have.
+ */
+
+/**
+ * Output the login page header.
+ *
+ * @param string   $title    Optional. WordPress login Page title to display in the `<title>` element.
+ *                           Default 'Log In'.
+ * @param string   $message  Optional. Message to display in header. Default empty.
+ * @param WP_Error $wp_error Optional. The error to pass. Default is a WP_Error instance.
+ */
+function login_header( $title = 'Log In', $message = '', $wp_error = null ) {
+	global $error, $interim_login, $action;
+
+	// Don't index any of these forms
+	add_action( 'login_head', 'wp_no_robots' );
+
+	add_action( 'login_head', 'wp_login_viewport_meta' );
+
+	if ( ! is_wp_error( $wp_error ) ) {
+		$wp_error = new WP_Error();
+	}
+
+	// Shake it!
+	$shake_error_codes = array( 'empty_password', 'empty_email', 'invalid_email', 'invalidcombo', 'empty_username', 'invalid_username', 'incorrect_password' );
+	/**
+	 * Filters the error codes array for shaking the login form.
+	 *
+	 * @since 3.0.0
+	 *
+	 * @param array $shake_error_codes Error codes that shake the login form.
+	 */
+	$shake_error_codes = apply_filters( 'shake_error_codes', $shake_error_codes );
+
+	if ( $shake_error_codes && $wp_error->get_error_code() && in_array( $wp_error->get_error_code(), $shake_error_codes ) )
+		add_action( 'login_head', 'wp_shake_js', 12 );
+
+	$login_title = get_bloginfo( 'name', 'display' );
+
+	/* translators: Login screen title. 1: Login screen name, 2: Network or site name */
+	$login_title = sprintf( __( '%1$s &lsaquo; %2$s &#8212; WordPress' ), $title, $login_title );
+
+	/**
+	 * Filters the title tag content for login page.
+	 *
+	 * @since 4.9.0
+	 *
+	 * @param string $login_title The page title, with extra context added.
+	 * @param string $title       The original page title.
+	 */
+	$login_title = apply_filters( 'login_title', $login_title, $title );
+
+	?><!DOCTYPE html>
+	<!--[if IE 8]>
+		<html xmlns="http://www.w3.org/1999/xhtml" class="ie8" <?php language_attributes(); ?>>
+	<![endif]-->
+	<!--[if !(IE 8) ]><!-->
+		<html xmlns="http://www.w3.org/1999/xhtml" <?php language_attributes(); ?>>
+	<!--<![endif]-->
+	<head>
+	<meta http-equiv="Content-Type" content="<?php bloginfo('html_type'); ?>; charset=<?php bloginfo('charset'); ?>" />
+	<title><?php echo $login_title; ?></title>
+	<?php
+
+	wp_enqueue_style( 'login' );
+
+	/*
+	 * Remove all stored post data on logging out.
+	 * This could be added by add_action('login_head'...) like wp_shake_js(),
+	 * but maybe better if it's not removable by plugins
+	 */
+	if ( 'loggedout' == $wp_error->get_error_code() ) {
+		?>
+		<script>if("sessionStorage" in window){try{for(var key in sessionStorage){if(key.indexOf("wp-autosave-")!=-1){sessionStorage.removeItem(key)}}}catch(e){}};</script>
+		<?php
+	}
+
+	/**
+	 * Enqueue scripts and styles for the login page.
+	 *
+	 * @since 3.1.0
+	 */
+	do_action( 'login_enqueue_scripts' );
+
+	/**
+	 * Fires in the login page header after scripts are enqueued.
+	 *
+	 * @since 2.1.0
+	 */
+	do_action( 'login_head' );
+
+	if ( is_multisite() ) {
+		$login_header_url   = network_home_url();
+		$login_header_title = get_network()->site_name;
+	} else {
+		$login_header_url   = __( 'https://wordpress.org/' );
+		$login_header_title = __( 'Powered by WordPress' );
+	}
+
+	/**
+	 * Filters link URL of the header logo above login form.
+	 *
+	 * @since 2.1.0
+	 *
+	 * @param string $login_header_url Login header logo URL.
+	 */
+	$login_header_url = apply_filters( 'login_headerurl', $login_header_url );
+
+	/**
+	 * Filters the title attribute of the header logo above login form.
+	 *
+	 * @since 2.1.0
+	 *
+	 * @param string $login_header_title Login header logo title attribute.
+	 */
+	$login_header_title = apply_filters( 'login_headertitle', $login_header_title );
+
+	/*
+	 * To match the URL/title set above, Multisite sites have the blog name,
+	 * while single sites get the header title.
+	 */
+	if ( is_multisite() ) {
+		$login_header_text = get_bloginfo( 'name', 'display' );
+	} else {
+		$login_header_text = $login_header_title;
+	}
+
+	$classes = array( 'login-action-' . $action, 'wp-core-ui' );
+	if ( is_rtl() )
+		$classes[] = 'rtl';
+	if ( $interim_login ) {
+		$classes[] = 'interim-login';
+		?>
+		<style type="text/css">html{background-color: transparent;}</style>
+		<?php
+
+		if ( 'success' ===  $interim_login )
+			$classes[] = 'interim-login-success';
+	}
+	$classes[] =' locale-' . sanitize_html_class( strtolower( str_replace( '_', '-', get_locale() ) ) );
+
+	/**
+	 * Filters the login page body classes.
+	 *
+	 * @since 3.5.0
+	 *
+	 * @param array  $classes An array of body classes.
+	 * @param string $action  The action that brought the visitor to the login page.
+	 */
+	$classes = apply_filters( 'login_body_class', $classes, $action );
+
+	?>
+	</head>
+	<body class="login <?php echo esc_attr( implode( ' ', $classes ) ); ?>">
+	<?php
+	/**
+	 * Fires in the login page header after the body tag is opened.
+	 *
+	 * @since 4.6.0
+	 */
+	do_action( 'login_header' );
+	?>
+	<div id="login">
+		<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>
+	<?php
+
+	unset( $login_header_url, $login_header_title );
+
+	/**
+	 * Filters the message to display above the login form.
+	 *
+	 * @since 2.1.0
+	 *
+	 * @param string $message Login message text.
+	 */
+	$message = apply_filters( 'login_message', $message );
+	if ( !empty( $message ) )
+		echo $message . "\n";
+
+	// In case a plugin uses $error rather than the $wp_errors object
+	if ( !empty( $error ) ) {
+		$wp_error->add('error', $error);
+		unset($error);
+	}
+
+	if ( $wp_error->get_error_code() ) {
+		$errors = '';
+		$messages = '';
+		foreach ( $wp_error->get_error_codes() as $code ) {
+			$severity = $wp_error->get_error_data( $code );
+			foreach ( $wp_error->get_error_messages( $code ) as $error_message ) {
+				if ( 'message' == $severity )
+					$messages .= '	' . $error_message . "<br />\n";
+				else
+					$errors .= '	' . $error_message . "<br />\n";
+			}
+		}
+		if ( ! empty( $errors ) ) {
+			/**
+			 * Filters the error messages displayed above the login form.
+			 *
+			 * @since 2.1.0
+			 *
+			 * @param string $errors Login error message.
+			 */
+			echo '<div id="login_error">' . apply_filters( 'login_errors', $errors ) . "</div>\n";
+		}
+		if ( ! empty( $messages ) ) {
+			/**
+			 * Filters instructional messages displayed above the login form.
+			 *
+			 * @since 2.5.0
+			 *
+			 * @param string $messages Login messages.
+			 */
+			echo '<p class="message">' . apply_filters( 'login_messages', $messages ) . "</p>\n";
+		}
+	}
+} // End of login_header()
+
+function wp_login_viewport_meta() {
+	?>
+	<meta name="viewport" content="width=device-width" />
+	<?php
+}
diff --git a/wp-content/plugins/two-factor/providers/class.two-factor-backup-codes.php b/wp-content/plugins/two-factor/providers/class.two-factor-backup-codes.php
new file mode 100644
index 0000000000000000000000000000000000000000..62ca51bbb686e49c5d88cb7f05c81d8388b96831
--- /dev/null
+++ b/wp-content/plugins/two-factor/providers/class.two-factor-backup-codes.php
@@ -0,0 +1,335 @@
+<?php
+/**
+ * Class for creating a backup codes provider.
+ *
+ * @since 0.1-dev
+ *
+ * @package Two_Factor
+ */
+class Two_Factor_Backup_Codes extends Two_Factor_Provider {
+
+	/**
+	 * The user meta backup codes key.
+	 *
+	 * @type string
+	 */
+	const BACKUP_CODES_META_KEY = '_two_factor_backup_codes';
+
+	/**
+	 * The number backup codes.
+	 *
+	 * @type int
+	 */
+	const NUMBER_OF_CODES = 10;
+
+	/**
+	 * Ensures only one instance of this class exists in memory at any one time.
+	 *
+	 * @since 0.1-dev
+	 */
+	static function get_instance() {
+		static $instance;
+		$class = __CLASS__;
+		if ( ! is_a( $instance, $class ) ) {
+			$instance = new $class;
+		}
+		return $instance;
+	}
+
+	/**
+	 * Class constructor.
+	 *
+	 * @since 0.1-dev
+	 */
+	protected function __construct() {
+		add_action( 'two-factor-user-options-' . __CLASS__, array( $this, 'user_options' ) );
+		add_action( 'admin_notices', array( $this, 'admin_notices' ) );
+		add_action( 'wp_ajax_two_factor_backup_codes_generate', array( $this, 'ajax_generate_json' ) );
+
+		return parent::__construct();
+	}
+
+	/**
+	 * Displays an admin notice when backup codes have run out.
+	 *
+	 * @since 0.1-dev
+	 */
+	public function admin_notices() {
+		$user = wp_get_current_user();
+
+		// Return if the provider is not enabled.
+		if ( ! in_array( __CLASS__, Two_Factor_Core::get_enabled_providers_for_user( $user->ID ) ) ) {
+			return;
+		}
+
+		// Return if we are not out of codes.
+		if ( $this->is_available_for_user( $user ) ) {
+			return;
+		}
+		?>
+		<div class="error">
+			<p>
+				<span>
+					<?php
+					printf( // WPCS: XSS OK.
+						__( 'Two-Factor: You are out of backup codes and need to <a href="%s">regenerate!</a>', 'two-factor' ),
+						esc_url( get_edit_user_link( $user->ID ) . '#two-factor-backup-codes' )
+					);
+					?>
+				<span>
+			</p>
+		</div>
+		<?php
+	}
+
+	/**
+	 * Returns the name of the provider.
+	 *
+	 * @since 0.1-dev
+	 */
+	public function get_label() {
+		return _x( 'Backup Verification Codes (Single Use)', 'Provider Label', 'two-factor' );
+	}
+
+	/**
+	 * Whether this Two Factor provider is configured and codes are available for the user specified.
+	 *
+	 * @since 0.1-dev
+	 *
+	 * @param WP_User $user WP_User object of the logged-in user.
+	 * @return boolean
+	 */
+	public function is_available_for_user( $user ) {
+		// Does this user have available codes?
+		if ( 0 < self::codes_remaining_for_user( $user ) ) {
+			return true;
+		}
+		return false;
+	}
+
+	/**
+	 * Inserts markup at the end of the user profile field for this provider.
+	 *
+	 * @since 0.1-dev
+	 *
+	 * @param WP_User $user WP_User object of the logged-in user.
+	 */
+	public function user_options( $user ) {
+		$ajax_nonce = wp_create_nonce( 'two-factor-backup-codes-generate-json-' . $user->ID );
+		$count = self::codes_remaining_for_user( $user );
+		?>
+		<p id="two-factor-backup-codes">
+			<button type="button" class="button button-two-factor-backup-codes-generate button-secondary hide-if-no-js">
+				<?php esc_html_e( 'Generate Verification Codes', 'two-factor' ); ?>
+			</button>
+			<span class="two-factor-backup-codes-count"><?php
+				echo esc_html( sprintf(
+					/* translators: %s: count */
+					_n( '%s unused code remaining.', '%s unused codes remaining.', $count, 'two-factor' ),
+					$count
+				) );
+				?></span>
+		</p>
+		<div class="two-factor-backup-codes-wrapper" style="display:none;">
+			<ol class="two-factor-backup-codes-unused-codes"></ol>
+			<p class="description"><?php esc_html_e( 'Write these down!  Once you navigate away from this page, you will not be able to view these codes again.', 'two-factor' ); ?></p>
+			<p>
+				<a class="button button-two-factor-backup-codes-download button-secondary hide-if-no-js" href="javascript:void(0);" id="two-factor-backup-codes-download-link" download="two-factor-backup-codes.txt"><?php esc_html_e( 'Download Codes', 'two-factor' ); ?></a>
+			<p>
+		</div>
+		<script type="text/javascript">
+			( function( $ ) {
+				$( '.button-two-factor-backup-codes-generate' ).click( function() {
+					$.ajax( {
+						method: 'POST',
+						url: ajaxurl,
+						data: {
+							action: 'two_factor_backup_codes_generate',
+							user_id: '<?php echo esc_js( $user->ID ); ?>',
+							nonce: '<?php echo esc_js( $ajax_nonce ); ?>'
+						},
+						dataType: 'JSON',
+						success: function( response ) {
+							var $codesList = $( '.two-factor-backup-codes-unused-codes' );
+
+							$( '.two-factor-backup-codes-wrapper' ).show();
+							$codesList.html( '' );
+
+							// Append the codes.
+							for ( i = 0; i < response.data.codes.length; i++ ) {
+								$codesList.append( '<li>' + response.data.codes[ i ] + '</li>' );
+							}
+
+							// Update counter.
+							$( '.two-factor-backup-codes-count' ).html( response.data.i18n.count );
+
+							// Build the download link
+							var txt_data = 'data:application/text;charset=utf-8,' + '\n';
+							txt_data += response.data.i18n.title.replace( /%s/g, document.domain ) + '\n\n';
+
+							for ( i = 0; i < response.data.codes.length; i++ ) {
+								txt_data += i + 1 + '. ' + response.data.codes[ i ] + '\n';
+							}
+
+							$( '#two-factor-backup-codes-download-link' ).attr( 'href', encodeURI( txt_data ) );
+						}
+					} );
+				} );
+			} )( jQuery );
+		</script>
+		<?php
+	}
+
+	/**
+	 * Generates backup codes & updates the user meta.
+	 *
+	 * @since 0.1-dev
+	 *
+	 * @param WP_User $user WP_User object of the logged-in user.
+	 * @param array   $args Optional arguments for assinging new codes.
+	 * @return array
+	 */
+	public function generate_codes( $user, $args = '' ) {
+		$codes = array();
+		$codes_hashed = array();
+
+		// Check for arguments.
+		if ( isset( $args['number'] ) ) {
+			$num_codes = (int) $args['number'];
+		} else {
+			$num_codes = self::NUMBER_OF_CODES;
+		}
+
+		// Append or replace (default).
+		if ( isset( $args['method'] ) && 'append' === $args['method'] ) {
+			$codes_hashed = (array) get_user_meta( $user->ID, self::BACKUP_CODES_META_KEY, true );
+		}
+
+		for ( $i = 0; $i < $num_codes; $i++ ) {
+			$code = $this->get_code();
+			$codes_hashed[] = wp_hash_password( $code );
+			$codes[] = $code;
+			unset( $code );
+		}
+
+		update_user_meta( $user->ID, self::BACKUP_CODES_META_KEY, $codes_hashed );
+
+		// Unhashed.
+		return $codes;
+	}
+
+	/**
+	 * Generates a JSON object of backup codes.
+	 *
+	 * @since 0.1-dev
+	 */
+	public function ajax_generate_json() {
+		$user = get_user_by( 'id', sanitize_text_field( $_POST['user_id'] ) );
+		check_ajax_referer( 'two-factor-backup-codes-generate-json-' . $user->ID, 'nonce' );
+
+		// Setup the return data.
+		$codes = $this->generate_codes( $user );
+		$count = self::codes_remaining_for_user( $user );
+		$i18n = array(
+			/* translators: %s: count */
+			'count' => esc_html( sprintf( _n( '%s unused code remaining.', '%s unused codes remaining.', $count, 'two-factor' ), $count ) ),
+			/* translators: %s: the site's domain */
+			'title' => esc_html__( 'Two-Factor Backup Codes for %s', 'two-factor' ),
+		);
+
+		// Send the response.
+		wp_send_json_success( array( 'codes' => $codes, 'i18n' => $i18n ) );
+	}
+
+	/**
+	 * Returns the number of unused codes for the specified user
+	 *
+	 * @param WP_User $user WP_User object of the logged-in user.
+	 * @return int $int  The number of unused codes remaining
+	 */
+	public static function codes_remaining_for_user( $user ) {
+		$backup_codes = get_user_meta( $user->ID, self::BACKUP_CODES_META_KEY, true );
+		if ( is_array( $backup_codes ) && ! empty( $backup_codes ) ) {
+			return count( $backup_codes );
+		}
+		return 0;
+	}
+
+	/**
+	 * Prints the form that prompts the user to authenticate.
+	 *
+	 * @since 0.1-dev
+	 *
+	 * @param WP_User $user WP_User object of the logged-in user.
+	 */
+	public function authentication_page( $user ) {
+		require_once( ABSPATH .  '/wp-admin/includes/template.php' );
+		?>
+		<p><?php esc_html_e( 'Enter a backup verification code.', 'two-factor' ); ?></p><br/>
+		<p>
+			<label for="authcode"><?php esc_html_e( 'Verification Code:', 'two-factor' ); ?></label>
+			<input type="tel" name="two-factor-backup-code" id="authcode" class="input" value="" size="20" pattern="[0-9]*" />
+		</p>
+		<?php
+		submit_button( __( 'Submit', 'two-factor' ) );
+	}
+
+	/**
+	 * Validates the users input token.
+	 *
+	 * In this class we just return true.
+	 *
+	 * @since 0.1-dev
+	 *
+	 * @param WP_User $user WP_User object of the logged-in user.
+	 * @return boolean
+	 */
+	public function validate_authentication( $user ) {
+		return $this->validate_code( $user, $_POST['two-factor-backup-code'] );
+	}
+
+	/**
+	 * Validates a backup code.
+	 *
+	 * Backup Codes are single use and are deleted upon a successful validation.
+	 *
+	 * @since 0.1-dev
+	 *
+	 * @param WP_User $user WP_User object of the logged-in user.
+	 * @param int     $code The backup code.
+	 * @return boolean
+	 */
+	public function validate_code( $user, $code ) {
+		$backup_codes = get_user_meta( $user->ID, self::BACKUP_CODES_META_KEY, true );
+
+		if ( is_array( $backup_codes ) && ! empty( $backup_codes ) ) {
+			foreach ( $backup_codes as $code_index => $code_hashed ) {
+				if ( wp_check_password( $code, $code_hashed, $user->ID ) ) {
+					$this->delete_code( $user, $code_hashed );
+					return true;
+				}
+			}
+		}
+		return false;
+	}
+
+	/**
+	 * Deletes a backup code.
+	 *
+	 * @since 0.1-dev
+	 *
+	 * @param WP_User $user WP_User object of the logged-in user.
+	 * @param string  $code_hashed The hashed the backup code.
+	 */
+	public function delete_code( $user, $code_hashed ) {
+		$backup_codes = get_user_meta( $user->ID, self::BACKUP_CODES_META_KEY, true );
+
+		// Delete the current code from the list since it's been used.
+		$backup_codes = array_flip( $backup_codes );
+		unset( $backup_codes[ $code_hashed ] );
+		$backup_codes = array_values( array_flip( $backup_codes ) );
+
+		// Update the backup code master list.
+		update_user_meta( $user->ID, self::BACKUP_CODES_META_KEY, $backup_codes );
+	}
+}
diff --git a/wp-content/plugins/two-factor/providers/class.two-factor-dummy.php b/wp-content/plugins/two-factor/providers/class.two-factor-dummy.php
new file mode 100644
index 0000000000000000000000000000000000000000..c28ccca7161786f1db1b99ae5991d601ea19ce89
--- /dev/null
+++ b/wp-content/plugins/two-factor/providers/class.two-factor-dummy.php
@@ -0,0 +1,93 @@
+<?php
+/**
+ * Class for creating a dummy provider.
+ *
+ * @since 0.1-dev
+ *
+ * @package Two_Factor
+ */
+class Two_Factor_Dummy extends Two_Factor_Provider {
+
+	/**
+	 * Ensures only one instance of this class exists in memory at any one time.
+	 *
+	 * @since 0.1-dev
+	 */
+	static function get_instance() {
+		static $instance;
+		$class = __CLASS__;
+		if ( ! is_a( $instance, $class ) ) {
+			$instance = new $class;
+		}
+		return $instance;
+	}
+
+	/**
+	 * Class constructor.
+	 *
+	 * @since 0.1-dev
+	 */
+	protected function __construct() {
+		add_action( 'two-factor-user-options-' . __CLASS__, array( $this, 'user_options' ) );
+		return parent::__construct();
+	}
+
+	/**
+	 * Returns the name of the provider.
+	 *
+	 * @since 0.1-dev
+	 */
+	public function get_label() {
+		return _x( 'Dummy Method', 'Provider Label', 'two-factor' );
+	}
+
+	/**
+	 * Prints the form that prompts the user to authenticate.
+	 *
+	 * @since 0.1-dev
+	 *
+	 * @param WP_User $user WP_User object of the logged-in user.
+	 */
+	public function authentication_page( $user ) {
+		require_once( ABSPATH .  '/wp-admin/includes/template.php' );
+		?>
+		<p><?php esc_html_e( 'Are you really you?', 'two-factor' ); ?></p>
+		<?php
+		submit_button( __( 'Yup.', 'two-factor' ) );
+	}
+
+	/**
+	 * Validates the users input token.
+	 *
+	 * In this class we just return true.
+	 *
+	 * @since 0.1-dev
+	 *
+	 * @param WP_User $user WP_User object of the logged-in user.
+	 * @return boolean
+	 */
+	public function validate_authentication( $user ) {
+		return true;
+	}
+
+	/**
+	 * Whether this Two Factor provider is configured and available for the user specified.
+	 *
+	 * @since 0.1-dev
+	 *
+	 * @param WP_User $user WP_User object of the logged-in user.
+	 * @return boolean
+	 */
+	public function is_available_for_user( $user ) {
+		return true;
+	}
+
+	/**
+	 * Inserts markup at the end of the user profile field for this provider.
+	 *
+	 * @since 0.1-dev
+	 *
+	 * @param WP_User $user WP_User object of the logged-in user.
+	 */
+	public function user_options( $user ) {}
+}
diff --git a/wp-content/plugins/two-factor/providers/class.two-factor-email.php b/wp-content/plugins/two-factor/providers/class.two-factor-email.php
new file mode 100644
index 0000000000000000000000000000000000000000..177885717a5f144406009cd0ce39cb9de8b00909
--- /dev/null
+++ b/wp-content/plugins/two-factor/providers/class.two-factor-email.php
@@ -0,0 +1,263 @@
+<?php
+/**
+ * Class for creating an email provider.
+ *
+ * @since 0.1-dev
+ *
+ * @package Two_Factor
+ */
+class Two_Factor_Email extends Two_Factor_Provider {
+
+	/**
+	 * The user meta token key.
+	 *
+	 * @type string
+	 */
+	const TOKEN_META_KEY = '_two_factor_email_token';
+
+	/**
+	 * Name of the input field used for code resend.
+	 *
+	 * @var string
+	 */
+	const INPUT_NAME_RESEND_CODE = 'two-factor-email-code-resend';
+
+	/**
+	 * Ensures only one instance of this class exists in memory at any one time.
+	 *
+	 * @since 0.1-dev
+	 */
+	static function get_instance() {
+		static $instance;
+		$class = __CLASS__;
+		if ( ! is_a( $instance, $class ) ) {
+			$instance = new $class;
+		}
+		return $instance;
+	}
+
+	/**
+	 * Class constructor.
+	 *
+	 * @since 0.1-dev
+	 */
+	protected function __construct() {
+		add_action( 'two-factor-user-options-' . __CLASS__, array( $this, 'user_options' ) );
+		return parent::__construct();
+	}
+
+	/**
+	 * Returns the name of the provider.
+	 *
+	 * @since 0.1-dev
+	 */
+	public function get_label() {
+		return _x( 'Email', 'Provider Label', 'two-factor' );
+	}
+
+	/**
+	 * Generate the user token.
+	 *
+	 * @since 0.1-dev
+	 *
+	 * @param int $user_id User ID.
+	 * @return string
+	 */
+	public function generate_token( $user_id ) {
+		$token = $this->get_code();
+		update_user_meta( $user_id, self::TOKEN_META_KEY, wp_hash( $token ) );
+		return $token;
+	}
+
+	/**
+	 * Check if user has a valid token already.
+	 *
+	 * @param  int $user_id User ID.
+	 * @return boolean      If user has a valid email token.
+	 */
+	public function user_has_token( $user_id ) {
+		$hashed_token = $this->get_user_token( $user_id );
+
+		if ( ! empty( $hashed_token ) ) {
+			return true;
+		} else {
+			return false;
+		}
+	}
+
+	/**
+	 * Get the authentication token for the user.
+	 *
+	 * @param  int $user_id    User ID.
+	 *
+	 * @return string|boolean  User token or `false` if no token found.
+	 */
+	public function get_user_token( $user_id ) {
+		$hashed_token = get_user_meta( $user_id, self::TOKEN_META_KEY, true );
+
+		if ( ! empty( $hashed_token ) && is_string( $hashed_token ) ) {
+			return $hashed_token;
+		}
+
+		return false;
+	}
+
+	/**
+	 * Validate the user token.
+	 *
+	 * @since 0.1-dev
+	 *
+	 * @param int    $user_id User ID.
+	 * @param string $token User token.
+	 * @return boolean
+	 */
+	public function validate_token( $user_id, $token ) {
+		$hashed_token = $this->get_user_token( $user_id );
+
+		// Bail if token is empty or it doesn't match.
+		if ( empty( $hashed_token ) || ( wp_hash( $token ) !== $hashed_token ) ) {
+			return false;
+		}
+
+		// Ensure that the token can't be re-used.
+		$this->delete_token( $user_id );
+
+		return true;
+	}
+
+	/**
+	 * Delete the user token.
+	 *
+	 * @since 0.1-dev
+	 *
+	 * @param int $user_id User ID.
+	 */
+	public function delete_token( $user_id ) {
+		delete_user_meta( $user_id, self::TOKEN_META_KEY );
+	}
+
+	/**
+	 * Generate and email the user token.
+	 *
+	 * @since 0.1-dev
+	 *
+	 * @param WP_User $user WP_User object of the logged-in user.
+	 * @return bool Whether the email contents were sent successfully.
+	 */
+	public function generate_and_email_token( $user ) {
+		$token = $this->generate_token( $user->ID );
+
+		/* translators: %s: site name */
+		$subject = wp_strip_all_tags( sprintf( __( 'Your login confirmation code for %s', 'two-factor' ), get_bloginfo( 'name' ) ) );
+		/* translators: %s: token */
+		$message = wp_strip_all_tags( sprintf( __( 'Enter %s to log in.', 'two-factor' ), $token ) );
+
+		return wp_mail( $user->user_email, $subject, $message );
+	}
+
+	/**
+	 * Prints the form that prompts the user to authenticate.
+	 *
+	 * @since 0.1-dev
+	 *
+	 * @param WP_User $user WP_User object of the logged-in user.
+	 */
+	public function authentication_page( $user ) {
+		if ( ! $user ) {
+			return;
+		}
+
+		if ( ! $this->user_has_token( $user->ID ) ) {
+			$this->generate_and_email_token( $user );
+		}
+
+		require_once( ABSPATH .  '/wp-admin/includes/template.php' );
+		?>
+		<p><?php esc_html_e( 'A verification code has been sent to the email address associated with your account.', 'two-factor' ); ?></p>
+		<p>
+			<label for="authcode"><?php esc_html_e( 'Verification Code:', 'two-factor' ); ?></label>
+			<input type="tel" name="two-factor-email-code" id="authcode" class="input" value="" size="20" pattern="[0-9]*" />
+			<?php submit_button( __( 'Log In', 'two-factor' ) ); ?>
+		</p>
+		<p class="two-factor-email-resend">
+			<input type="submit" class="button" name="<?php echo esc_attr( self::INPUT_NAME_RESEND_CODE ); ?>" value="<?php esc_attr_e( 'Resend Code', 'two-factor' ); ?>" />
+		</p>
+		<script type="text/javascript">
+			setTimeout( function(){
+				var d;
+				try{
+					d = document.getElementById('authcode');
+					d.value = '';
+					d.focus();
+				} catch(e){}
+			}, 200);
+		</script>
+		<?php
+	}
+
+	/**
+	 * Send the email code if missing or requested. Stop the authentication
+	 * validation if a new token has been generated and sent.
+	 *
+	 * @param  WP_USer $user WP_User object of the logged-in user.
+	 * @return boolean
+	 */
+	public function pre_process_authentication( $user ) {
+		if ( isset( $user->ID ) && isset( $_REQUEST[ self::INPUT_NAME_RESEND_CODE ] ) ) {
+			$this->generate_and_email_token( $user );
+			return true;
+		}
+
+		return false;
+	}
+
+	/**
+	 * Validates the users input token.
+	 *
+	 * @since 0.1-dev
+	 *
+	 * @param WP_User $user WP_User object of the logged-in user.
+	 * @return boolean
+	 */
+	public function validate_authentication( $user ) {
+		if ( ! isset( $user->ID ) || ! isset( $_REQUEST['two-factor-email-code'] ) ) {
+			return false;
+		}
+
+		return $this->validate_token( $user->ID, $_REQUEST['two-factor-email-code'] );
+	}
+
+	/**
+	 * Whether this Two Factor provider is configured and available for the user specified.
+	 *
+	 * @since 0.1-dev
+	 *
+	 * @param WP_User $user WP_User object of the logged-in user.
+	 * @return boolean
+	 */
+	public function is_available_for_user( $user ) {
+		return true;
+	}
+
+	/**
+	 * Inserts markup at the end of the user profile field for this provider.
+	 *
+	 * @since 0.1-dev
+	 *
+	 * @param WP_User $user WP_User object of the logged-in user.
+	 */
+	public function user_options( $user ) {
+		$email = $user->user_email;
+		?>
+		<div>
+			<?php
+			echo esc_html( sprintf(
+				/* translators: %s: email address */
+				__( 'Authentication codes will be sent to %s.', 'two-factor' ),
+				$email
+			) );
+			?>
+		</div>
+		<?php
+	}
+}
diff --git a/wp-content/plugins/two-factor/providers/class.two-factor-fido-u2f-admin-list-table.php b/wp-content/plugins/two-factor/providers/class.two-factor-fido-u2f-admin-list-table.php
new file mode 100644
index 0000000000000000000000000000000000000000..7942c9a9413919eb0603a128e7004d4df61486b3
--- /dev/null
+++ b/wp-content/plugins/two-factor/providers/class.two-factor-fido-u2f-admin-list-table.php
@@ -0,0 +1,152 @@
+<?php
+// Load the parent class if it doesn't exist.
+if ( ! class_exists( 'WP_List_Table' ) ) {
+	require_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php';
+}
+
+/**
+ * Class for displaying the list of security key items.
+ *
+ * @since 0.1-dev
+ * @access private
+ *
+ * @package Two_Factor
+ */
+class Two_Factor_FIDO_U2F_Admin_List_Table extends WP_List_Table {
+
+	/**
+	 * Get a list of columns.
+	 *
+	 * @since 0.1-dev
+	 *
+	 * @return array
+	 */
+	public function get_columns() {
+		return array(
+			'name'      => wp_strip_all_tags( __( 'Name', 'two-factor' ) ),
+			'added'   => wp_strip_all_tags( __( 'Added', 'two-factor' ) ),
+			'last_used' => wp_strip_all_tags( __( 'Last Used', 'two-factor' ) ),
+		);
+	}
+
+	/**
+	 * Prepares the list of items for displaying.
+	 *
+	 * @since 0.1-dev
+	 */
+	public function prepare_items() {
+		$columns  = $this->get_columns();
+		$hidden   = array();
+		$sortable = array();
+		$primary  = 'name';
+		$this->_column_headers = array( $columns, $hidden, $sortable, $primary );
+	}
+
+	/**
+	 * Generates content for a single row of the table
+	 *
+	 * @since 0.1-dev
+	 * @access protected
+	 *
+	 * @param object $item The current item.
+	 * @param string $column_name The current column name.
+	 * @return string
+	 */
+	protected function column_default( $item, $column_name ) {
+		switch ( $column_name ) {
+			case 'name':
+				$out = '<div class="hidden" id="inline_' . esc_attr( $item->keyHandle ) . '">';
+				$out .= '<div class="name">' . esc_html( $item->name ) . '</div>';
+				$out .= '</div>';
+
+				$actions = array(
+					'rename hide-if-no-js' => Two_Factor_FIDO_U2F_Admin::rename_link( $item ),
+					'delete' => Two_Factor_FIDO_U2F_Admin::delete_link( $item ),
+				);
+
+				return esc_html( $item->name ) . $out . self::row_actions( $actions );
+			case 'added':
+				return date( get_option( 'date_format', 'r' ), $item->added );
+			case 'last_used':
+				return date( get_option( 'date_format', 'r' ), $item->last_used );
+			default:
+				return 'WTF^^?';
+		}
+	}
+
+	/**
+	 * Generates custom table navigation to prevent conflicting nonces.
+	 *
+	 * @since 0.1-dev
+	 * @access protected
+	 *
+	 * @param string $which The location of the bulk actions: 'top' or 'bottom'.
+	 */
+	protected function display_tablenav( $which ) {
+		// Not used for the Security key list.
+	}
+
+	/**
+	 * Generates content for a single row of the table
+	 *
+	 * @since 0.1-dev
+	 * @access public
+	 *
+	 * @param object $item The current item.
+	 */
+	public function single_row( $item ) {
+		?>
+		<tr id="key-<?php echo esc_attr( $item->keyHandle ); ?>">
+		<?php $this->single_row_columns( $item ); ?>
+		</tr>
+		<?php
+	}
+
+	/**
+	 * Outputs the hidden row displayed when inline editing
+	 *
+	 * @since 0.1-dev
+	 */
+	public function inline_edit() {
+		?>
+		<table style="display: none">
+			<tbody id="inlineedit">
+				<tr id="inline-edit" class="inline-edit-row" style="display: none">
+					<td colspan="<?php echo esc_attr( $this->get_column_count() ); ?>" class="colspanchange">
+						<fieldset>
+							<div class="inline-edit-col">
+								<h4><?php esc_html_e( 'Quick Edit', 'two-factor' ); ?></h4>
+
+								<label>
+									<span class="title"><?php esc_html_e( 'Name', 'two-factor' ); ?></span>
+									<span class="input-text-wrap"><input type="text" name="name" class="ptitle" value="" /></span>
+								</label>
+							</div>
+						</fieldset>
+						<?php
+						$core_columns = array( 'name' => true, 'added' => true, 'last_used' => true );
+						list( $columns ) = $this->get_column_info();
+						foreach ( $columns as $column_name => $column_display_name ) {
+							if ( isset( $core_columns[ $column_name ] ) ) {
+								continue;
+							}
+
+							/** This action is documented in wp-admin/includes/class-wp-posts-list-table.php */
+							do_action( 'quick_edit_custom_box', $column_name, 'edit-security-keys' );
+						}
+						?>
+						<p class="inline-edit-save submit">
+							<a href="#inline-edit" class="cancel button-secondary alignleft"><?php esc_html_e( 'Cancel', 'two-factor' ); ?></a>
+							<a href="#inline-edit" class="save button-primary alignright"><?php esc_html_e( 'Update', 'two-factor' ); ?></a>
+							<span class="spinner"></span>
+							<span class="error" style="display:none;"></span>
+							<?php wp_nonce_field( 'keyinlineeditnonce', '_inline_edit', false ); ?>
+							<br class="clear" />
+						</p>
+					</td>
+				</tr>
+			</tbody>
+		</table>
+		<?php
+	}
+}
diff --git a/wp-content/plugins/two-factor/providers/class.two-factor-fido-u2f-admin.php b/wp-content/plugins/two-factor/providers/class.two-factor-fido-u2f-admin.php
new file mode 100644
index 0000000000000000000000000000000000000000..d4c4ac85434abcd60892bd30766fbe290d8c019a
--- /dev/null
+++ b/wp-content/plugins/two-factor/providers/class.two-factor-fido-u2f-admin.php
@@ -0,0 +1,341 @@
+<?php
+/**
+ * Class for registering & modifying FIDO U2F security keys.
+ *
+ * @since 0.1-dev
+ *
+ * @package Two_Factor
+ */
+class Two_Factor_FIDO_U2F_Admin {
+
+	/**
+	 * The user meta register data.
+	 *
+	 * @type string
+	 */
+	const REGISTER_DATA_USER_META_KEY = '_two_factor_fido_u2f_register_request';
+
+	/**
+	 * Add various hooks.
+	 *
+	 * @since 0.1-dev
+	 *
+	 * @access public
+	 * @static
+	 */
+	public static function add_hooks() {
+		add_action( 'admin_enqueue_scripts',       array( __CLASS__, 'enqueue_assets' ) );
+		add_action( 'show_user_security_settings', array( __CLASS__, 'show_user_profile' ) );
+		add_action( 'personal_options_update',     array( __CLASS__, 'catch_submission' ), 0 );
+		add_action( 'edit_user_profile_update',    array( __CLASS__, 'catch_submission' ), 0 );
+		add_action( 'load-profile.php',            array( __CLASS__, 'catch_delete_security_key' ) );
+		add_action( 'load-user-edit.php',          array( __CLASS__, 'catch_delete_security_key' ) );
+		add_action( 'wp_ajax_inline-save-key',     array( __CLASS__, 'wp_ajax_inline_save' ) );
+	}
+
+	/**
+	 * Enqueue assets.
+	 *
+	 * @since 0.1-dev
+	 *
+	 * @access public
+	 * @static
+	 *
+	 * @param string $hook Current page.
+	 */
+	public static function enqueue_assets( $hook ) {
+		if ( ! in_array( $hook, array( 'user-edit.php', 'profile.php' ) ) ) {
+			return;
+		}
+
+		$user_id = get_current_user_id();
+		$security_keys = Two_Factor_FIDO_U2F::get_security_keys( $user_id );
+
+		// @todo Ensure that scripts don't fail because of missing u2fL10n
+		try {
+			$data = Two_Factor_FIDO_U2F::$u2f->getRegisterData( $security_keys );
+			list( $req,$sigs ) = $data;
+
+			update_user_meta( $user_id, self::REGISTER_DATA_USER_META_KEY, $req );
+		} catch ( Exception $e ) {
+			return false;
+		}
+
+		wp_enqueue_style(
+			'fido-u2f-admin',
+			plugins_url( 'css/fido-u2f-admin.css', __FILE__ ),
+			null,
+			self::asset_version()
+		);
+
+		wp_enqueue_script(
+			'fido-u2f-admin',
+			plugins_url( 'js/fido-u2f-admin.js', __FILE__ ),
+			array( 'jquery', 'fido-u2f-api' ),
+			self::asset_version(),
+			true
+		);
+
+		/**
+		 * Pass a U2F challenge and user data to our scripts
+		 */
+
+		$translation_array = array(
+			'register' => array(
+				'request' => $req,
+				'sigs' => $sigs,
+			),
+			'text' => array(
+				'insert' => esc_html__( 'Now insert (and tap) your Security Key.', 'two-factor' ),
+				'error' => esc_html__( 'U2F request failed.', 'two-factor' ),
+				'error_codes' => array(
+					// Map u2f.ErrorCodes to error messages.
+					0 => esc_html__( 'Request OK.', 'two-factor' ),
+					1 => esc_html__( 'Other U2F error.', 'two-factor' ),
+					2 => esc_html__( 'Bad U2F request.', 'two-factor' ),
+					3 => esc_html__( 'Unsupported U2F configuration.', 'two-factor' ),
+					4 => esc_html__( 'U2F device ineligible.', 'two-factor' ),
+					5 => esc_html__( 'U2F request timeout reached.', 'two-factor' ),
+				),
+				'u2f_not_supported' => esc_html__( 'FIDO U2F appears to be not supported by your web browser. Try using Google Chrome or Firefox.', 'two-factor' ),
+			),
+		);
+
+		wp_localize_script(
+			'fido-u2f-admin',
+			'u2fL10n',
+			$translation_array
+		);
+
+		/**
+		 * Script for admin UI
+		 */
+
+		wp_enqueue_script(
+			'inline-edit-key',
+			plugins_url( 'js/fido-u2f-admin-inline-edit.js', __FILE__ ),
+			array( 'jquery' ),
+			self::asset_version(),
+			true
+		);
+
+		wp_localize_script(
+			'inline-edit-key',
+			'inlineEditL10n',
+			array(
+				'error' => esc_html__( 'Error while saving the changes.', 'two-factor' ),
+			)
+		);
+	}
+
+	/**
+	 * Return the current asset version number.
+	 *
+	 * Added as own helper to allow swapping the implementation once we inject
+	 * it as a dependency.
+	 *
+	 * @return string
+	 */
+	protected static function asset_version() {
+		return Two_Factor_FIDO_U2F::asset_version();
+	}
+
+	/**
+	 * Display the security key section in a users profile.
+	 *
+	 * This executes during the `show_user_security_settings` action.
+	 *
+	 * @since 0.1-dev
+	 *
+	 * @access public
+	 * @static
+	 *
+	 * @param WP_User $user WP_User object of the logged-in user.
+	 */
+	public static function show_user_profile( $user ) {
+		wp_nonce_field( "user_security_keys-{$user->ID}", '_nonce_user_security_keys' );
+		$new_key = false;
+
+		$security_keys = Two_Factor_FIDO_U2F::get_security_keys( $user->ID );
+		if ( $security_keys ) {
+			foreach ( $security_keys as &$security_key ) {
+				if ( property_exists( $security_key, 'new' ) ) {
+					$new_key = true;
+					unset( $security_key->new );
+
+					// If we've got a new one, update the db record to not save it there any longer.
+					Two_Factor_FIDO_U2F::update_security_key( $user->ID, $security_key );
+				}
+			}
+			unset( $security_key );
+		}
+
+		?>
+		<div class="security-keys" id="security-keys-section">
+			<h3><?php esc_html_e( 'Security Keys', 'two-factor' ); ?></h3>
+
+			<?php if ( ! is_ssl() ) : ?>
+			<p class="u2f-error-https">
+				<em><?php esc_html_e( 'U2F requires an HTTPS connection. You won\'t be able to add new security keys over HTTP.', 'two-factor' ); ?></em>
+			</p>
+			<?php endif; ?>
+
+			<div class="register-security-key">
+				<input type="hidden" name="do_new_security_key" id="do_new_security_key" />
+				<input type="hidden" name="u2f_response" id="u2f_response" />
+				<button type="button" class="button button-secondary" id="register_security_key"><?php echo esc_html( _x( 'Register New Key', 'security key', 'two-factor' ) ); ?></button>
+				<span class="spinner"></span>
+				<span class="security-key-status"></span>
+			</div>
+
+			<?php if ( $new_key ) : ?>
+			<div class="notice notice-success is-dismissible">
+				<p class="new-security-key"><?php esc_html_e( 'Your new security key registered.', 'two-factor' ); ?></p>
+			</div>
+			<?php endif; ?>
+
+			<p><a href="https://support.google.com/accounts/answer/6103523"><?php esc_html_e( 'You can find FIDO U2F Security Key devices for sale from here.', 'two-factor' ); ?></a></p>
+
+			<?php
+				require( TWO_FACTOR_DIR . 'providers/class.two-factor-fido-u2f-admin-list-table.php' );
+				$u2f_list_table = new Two_Factor_FIDO_U2F_Admin_List_Table();
+				$u2f_list_table->items = $security_keys;
+				$u2f_list_table->prepare_items();
+				$u2f_list_table->display();
+				$u2f_list_table->inline_edit();
+			?>
+		</div>
+		<?php
+	}
+
+	/**
+	 * Catch the non-ajax submission from the new form.
+	 *
+	 * This executes during the `personal_options_update` & `edit_user_profile_update` actions.
+	 *
+	 * @since 0.1-dev
+	 *
+	 * @access public
+	 * @static
+	 *
+	 * @param int $user_id User ID.
+	 * @return false
+	 */
+	public static function catch_submission( $user_id ) {
+		if ( ! empty( $_REQUEST['do_new_security_key'] ) ) {
+			check_admin_referer( "user_security_keys-{$user_id}", '_nonce_user_security_keys' );
+
+			try {
+				$response = json_decode( stripslashes( $_POST['u2f_response'] ) );
+				$reg = Two_Factor_FIDO_U2F::$u2f->doRegister( get_user_meta( $user_id, self::REGISTER_DATA_USER_META_KEY, true ), $response );
+				$reg->new = true;
+
+				Two_Factor_FIDO_U2F::add_security_key( $user_id, $reg );
+			} catch ( Exception $e ) {
+				return false;
+			}
+
+			delete_user_meta( $user_id, self::REGISTER_DATA_USER_META_KEY );
+
+			wp_safe_redirect( add_query_arg( array(
+				'new_app_pass' => 1,
+			), wp_get_referer() ) . '#security-keys-section' );
+			exit;
+		}
+	}
+
+	/**
+	 * Catch the delete security key request.
+	 *
+	 * This executes during the `load-profile.php` & `load-user-edit.php` actions.
+	 *
+	 * @since 0.1-dev
+	 *
+	 * @access public
+	 * @static
+	 */
+	public static function catch_delete_security_key() {
+		$user_id = get_current_user_id();
+		if ( ! empty( $_REQUEST['delete_security_key'] ) ) {
+			$slug = $_REQUEST['delete_security_key'];
+			check_admin_referer( "delete_security_key-{$slug}", '_nonce_delete_security_key' );
+
+			Two_Factor_FIDO_U2F::delete_security_key( $user_id, $slug );
+
+			wp_safe_redirect( remove_query_arg( 'new_app_pass', wp_get_referer() ) . '#security-keys-section' );
+		}
+	}
+
+	/**
+	 * Generate a link to rename a specified security key.
+	 *
+	 * @since 0.1-dev
+	 *
+	 * @access public
+	 * @static
+	 *
+	 * @param array $item The current item.
+	 * @return string
+	 */
+	public static function rename_link( $item ) {
+		return sprintf( '<a href="#" class="editinline">%s</a>', esc_html__( 'Rename', 'two-factor' ) );
+	}
+
+	/**
+	 * Generate a link to delete a specified security key.
+	 *
+	 * @since 0.1-dev
+	 *
+	 * @access public
+	 * @static
+	 *
+	 * @param array $item The current item.
+	 * @return string
+	 */
+	public static function delete_link( $item ) {
+		$delete_link = add_query_arg( 'delete_security_key', $item->keyHandle );
+		$delete_link = wp_nonce_url( $delete_link, "delete_security_key-{$item->keyHandle}", '_nonce_delete_security_key' );
+		return sprintf( '<a href="%1$s">%2$s</a>', esc_url( $delete_link ), esc_html__( 'Delete', 'two-factor' ) );
+	}
+
+	/**
+	 * Ajax handler for quick edit saving for a security key.
+	 *
+	 * @since 0.1-dev
+	 *
+	 * @access public
+	 * @static
+	 */
+	public static function wp_ajax_inline_save() {
+		check_ajax_referer( 'keyinlineeditnonce', '_inline_edit' );
+
+		require( TWO_FACTOR_DIR . 'providers/class.two-factor-fido-u2f-admin-list-table.php' );
+		$wp_list_table = new Two_Factor_FIDO_U2F_Admin_List_Table();
+
+		if ( ! isset( $_POST['keyHandle'] ) ) {
+			wp_die();
+		}
+
+		$user_id = get_current_user_id();
+
+		$security_keys = Two_Factor_FIDO_U2F::get_security_keys( $user_id );
+		if ( ! $security_keys ) {
+			wp_die();
+		}
+
+		foreach ( $security_keys as &$key ) {
+			if ( $key->keyHandle === $_POST['keyHandle'] ) {
+				break;
+			}
+		}
+
+		$key->name = $_POST['name'];
+
+		$updated = Two_Factor_FIDO_U2F::update_security_key( $user_id, $key );
+		if ( ! $updated ) {
+			wp_die( esc_html__( 'Item not updated.', 'two-factor' ) );
+		}
+		$wp_list_table->single_row( $key );
+		wp_die();
+	}
+}
diff --git a/wp-content/plugins/two-factor/providers/class.two-factor-fido-u2f.php b/wp-content/plugins/two-factor/providers/class.two-factor-fido-u2f.php
new file mode 100644
index 0000000000000000000000000000000000000000..54644251369ffce55bc88a61879831e7b002fdcb
--- /dev/null
+++ b/wp-content/plugins/two-factor/providers/class.two-factor-fido-u2f.php
@@ -0,0 +1,384 @@
+<?php
+/**
+ * Class for creating a FIDO Universal 2nd Factor provider.
+ *
+ * @since 0.1-dev
+ *
+ * @package Two_Factor
+ */
+class Two_Factor_FIDO_U2F extends Two_Factor_Provider {
+
+	/**
+	 * U2F Library
+	 *
+	 * @var u2flib_server\U2F
+	 */
+	public static $u2f;
+
+	/**
+	 * The user meta registered key.
+	 *
+	 * @type string
+	 */
+	const REGISTERED_KEY_USER_META_KEY = '_two_factor_fido_u2f_registered_key';
+
+	/**
+	 * The user meta authenticate data.
+	 *
+	 * @type string
+	 */
+	const AUTH_DATA_USER_META_KEY = '_two_factor_fido_u2f_login_request';
+
+	/**
+	 * Version number for the bundled assets.
+	 *
+	 * @var string
+	 */
+	const U2F_ASSET_VERSION = '0.2.0';
+
+	/**
+	 * Ensures only one instance of this class exists in memory at any one time.
+	 *
+	 * @return \Two_Factor_FIDO_U2F
+	 */
+	static function get_instance() {
+		static $instance;
+
+		if ( ! isset( $instance ) ) {
+			$instance = new self();
+		}
+
+		return $instance;
+	}
+
+	/**
+	 * Class constructor.
+	 *
+	 * @since 0.1-dev
+	 */
+	protected function __construct() {
+		if ( version_compare( PHP_VERSION, '5.3.0', '<' ) ) {
+			return;
+		}
+
+		require_once( TWO_FACTOR_DIR . 'includes/Yubico/U2F.php' );
+		self::$u2f = new u2flib_server\U2F( self::get_u2f_app_id() );
+
+		require_once( TWO_FACTOR_DIR . 'providers/class.two-factor-fido-u2f-admin.php' );
+		Two_Factor_FIDO_U2F_Admin::add_hooks();
+
+		wp_register_script(
+			'fido-u2f-api',
+			plugins_url( 'includes/Google/u2f-api.js', dirname( __FILE__ ) ),
+			null,
+			self::asset_version(),
+			true
+		);
+
+		wp_register_script(
+			'fido-u2f-login',
+			plugins_url( 'js/fido-u2f-login.js', __FILE__ ),
+			array( 'jquery', 'fido-u2f-api' ),
+			self::asset_version(),
+			true
+		);
+
+		add_action( 'two-factor-user-options-' . __CLASS__, array( $this, 'user_options' ) );
+
+		return parent::__construct();
+	}
+
+	/**
+	 * Get the asset version number.
+	 *
+	 * TODO: There should be a plugin-level helper for getting the current plugin version.
+	 *
+	 * @return string
+	 */
+	public static function asset_version() {
+		return self::U2F_ASSET_VERSION;
+	}
+
+	/**
+	 * Return the U2F AppId. U2F requires the AppID to use HTTPS
+	 * and a top-level domain.
+	 *
+	 * @return string AppID URI
+	 */
+	public static function get_u2f_app_id() {
+		$url_parts = wp_parse_url( home_url() );
+
+		if ( ! empty( $url_parts['port'] ) ) {
+			return sprintf( 'https://%s:%d', $url_parts['host'], $url_parts['port'] );
+		} else {
+			return sprintf( 'https://%s', $url_parts['host'] );
+		}
+	}
+
+	/**
+	 * Returns the name of the provider.
+	 *
+	 * @since 0.1-dev
+	 */
+	public function get_label() {
+		return _x( 'FIDO Universal 2nd Factor (U2F)', 'Provider Label', 'two-factor' );
+	}
+
+	/**
+	 * Enqueue assets for login form.
+	 *
+	 * @since 0.1-dev
+	 */
+	public function login_enqueue_assets() {
+		wp_enqueue_script( 'fido-u2f-login' );
+	}
+
+	/**
+	 * Prints the form that prompts the user to authenticate.
+	 *
+	 * @since 0.1-dev
+	 *
+	 * @param WP_User $user WP_User object of the logged-in user.
+	 * @return null
+	 */
+	public function authentication_page( $user ) {
+		require_once( ABSPATH . '/wp-admin/includes/template.php' );
+
+		// U2F doesn't work without HTTPS
+		if ( ! is_ssl() ) {
+			?>
+			<p><?php esc_html_e( 'U2F requires an HTTPS connection. Please use an alternative 2nd factor method.', 'two-factor' ); ?></p>
+			<?php
+
+			return;
+		}
+
+		try {
+			$keys = self::get_security_keys( $user->ID );
+			$data = self::$u2f->getAuthenticateData( $keys );
+			update_user_meta( $user->ID, self::AUTH_DATA_USER_META_KEY, $data );
+		} catch ( Exception $e ) {
+			?>
+			<p><?php esc_html_e( 'An error occurred while creating authentication data.', 'two-factor' ); ?></p>
+			<?php
+			return null;
+		}
+
+		wp_localize_script(
+			'fido-u2f-login',
+			'u2fL10n',
+			array(
+				'request' => $data,
+			)
+		);
+
+		wp_enqueue_script( 'fido-u2f-login' );
+
+		?>
+		<p><?php esc_html_e( 'Now insert (and tap) your Security Key.', 'two-factor' ); ?></p>
+		<input type="hidden" name="u2f_response" id="u2f_response" />
+		<?php
+	}
+
+	/**
+	 * Validates the users input token.
+	 *
+	 * @since 0.1-dev
+	 *
+	 * @param WP_User $user WP_User object of the logged-in user.
+	 * @return boolean
+	 */
+	public function validate_authentication( $user ) {
+		$requests = get_user_meta( $user->ID, self::AUTH_DATA_USER_META_KEY, true );
+
+		$response = json_decode( stripslashes( $_REQUEST['u2f_response'] ) );
+
+		$keys = self::get_security_keys( $user->ID );
+
+		try {
+			$reg = self::$u2f->doAuthenticate( $requests, $keys, $response );
+
+			$reg->last_used = current_time( 'timestamp' );
+
+			self::update_security_key( $user->ID, $reg );
+
+			return true;
+		} catch ( Exception $e ) {
+			return false;
+		}
+	}
+
+	/**
+	 * Whether this Two Factor provider is configured and available for the user specified.
+	 *
+	 * @since 0.1-dev
+	 *
+	 * @param WP_User $user WP_User object of the logged-in user.
+	 * @return boolean
+	 */
+	public function is_available_for_user( $user ) {
+		return (bool) self::get_security_keys( $user->ID );
+	}
+
+	/**
+	 * Inserts markup at the end of the user profile field for this provider.
+	 *
+	 * @since 0.1-dev
+	 *
+	 * @param WP_User $user WP_User object of the logged-in user.
+	 */
+	public function user_options( $user ) {
+		?>
+		<p>
+			<?php esc_html_e( 'Requires an HTTPS connection. Configure your security keys in the "Security Keys" section below.', 'two-factor' ); ?>
+		</p>
+		<?php
+	}
+
+	/**
+	 * Add registered security key to a user.
+	 *
+	 * @since 0.1-dev
+	 *
+	 * @param int    $user_id  User ID.
+	 * @param object $register The data of registered security key.
+	 * @return int|bool Meta ID on success, false on failure.
+	 */
+	public static function add_security_key( $user_id, $register ) {
+		if ( ! is_numeric( $user_id ) ) {
+			return false;
+		}
+
+		if (
+			! is_object( $register )
+				|| ! property_exists( $register, 'keyHandle' ) || empty( $register->keyHandle )
+				|| ! property_exists( $register, 'publicKey' ) || empty( $register->publicKey )
+				|| ! property_exists( $register, 'certificate' ) || empty( $register->certificate )
+				|| ! property_exists( $register, 'counter' ) || ( -1 > $register->counter )
+		) {
+			return false;
+		}
+
+		$register = array(
+			'keyHandle'   => $register->keyHandle,
+			'publicKey'   => $register->publicKey,
+			'certificate' => $register->certificate,
+			'counter'     => $register->counter,
+		);
+
+		$register['name']      = __( 'New Security Key', 'two-factor' );
+		$register['added']     = current_time( 'timestamp' );
+		$register['last_used'] = $register['added'];
+
+		return add_user_meta( $user_id, self::REGISTERED_KEY_USER_META_KEY, $register );
+	}
+
+	/**
+	 * Retrieve registered security keys for a user.
+	 *
+	 * @since 0.1-dev
+	 *
+	 * @param int $user_id User ID.
+	 * @return array|bool Array of keys on success, false on failure.
+	 */
+	public static function get_security_keys( $user_id ) {
+		if ( ! is_numeric( $user_id ) ) {
+			return false;
+		}
+
+		$keys = get_user_meta( $user_id, self::REGISTERED_KEY_USER_META_KEY );
+		if ( $keys ) {
+			foreach ( $keys as &$key ) {
+				$key = (object) $key;
+			}
+			unset( $key );
+		}
+
+		return $keys;
+	}
+
+	/**
+	 * Update registered security key.
+	 *
+	 * Use the $prev_value parameter to differentiate between meta fields with the
+	 * same key and user ID.
+	 *
+	 * If the meta field for the user does not exist, it will be added.
+	 *
+	 * @since 0.1-dev
+	 *
+	 * @param int    $user_id  User ID.
+	 * @param object $data The data of registered security key.
+	 * @return int|bool Meta ID if the key didn't exist, true on successful update, false on failure.
+	 */
+	public static function update_security_key( $user_id, $data ) {
+		if ( ! is_numeric( $user_id ) ) {
+			return false;
+		}
+
+		if (
+			! is_object( $data )
+				|| ! property_exists( $data, 'keyHandle' ) || empty( $data->keyHandle )
+				|| ! property_exists( $data, 'publicKey' ) || empty( $data->publicKey )
+				|| ! property_exists( $data, 'certificate' ) || empty( $data->certificate )
+				|| ! property_exists( $data, 'counter' ) || ( -1 > $data->counter )
+		) {
+			return false;
+		}
+
+		$keys = self::get_security_keys( $user_id );
+		if ( $keys ) {
+			foreach ( $keys as $key ) {
+				if ( $key->keyHandle === $data->keyHandle ) {
+					return update_user_meta( $user_id, self::REGISTERED_KEY_USER_META_KEY, (array) $data, (array) $key );
+				}
+			}
+		}
+
+		return self::add_security_key( $user_id, $data );
+	}
+
+	/**
+	 * Remove registered security key matching criteria from a user.
+	 *
+	 * @since 0.1-dev
+	 *
+	 * @param int    $user_id   User ID.
+	 * @param string $keyHandle Optional. Key handle.
+	 * @return bool True on success, false on failure.
+	 */
+	public static function delete_security_key( $user_id, $keyHandle = null ) {
+		global $wpdb;
+
+		if ( ! is_numeric( $user_id ) ) {
+			return false;
+		}
+
+		$user_id = absint( $user_id );
+		if ( ! $user_id ) {
+			return false;
+		}
+
+		$table = $wpdb->usermeta;
+
+		$keyHandle = wp_unslash( $keyHandle );
+		$keyHandle = maybe_serialize( $keyHandle );
+
+		$query = $wpdb->prepare( "SELECT umeta_id FROM $table WHERE meta_key = '%s' AND user_id = %d", self::REGISTERED_KEY_USER_META_KEY, $user_id );
+
+		if ( $keyHandle ) {
+			$query .= $wpdb->prepare( ' AND meta_value LIKE %s', '%:"' . $keyHandle . '";s:%' );
+		}
+
+		$meta_ids = $wpdb->get_col( $query );
+		if ( ! count( $meta_ids ) ) {
+			return false;
+		}
+
+		foreach ( $meta_ids as $meta_id ) {
+			delete_metadata_by_mid( 'user', $meta_id );
+		}
+
+		return true;
+	}
+}
diff --git a/wp-content/plugins/two-factor/providers/class.two-factor-provider.php b/wp-content/plugins/two-factor/providers/class.two-factor-provider.php
new file mode 100644
index 0000000000000000000000000000000000000000..97a4a7fcd59aac7c8a668f36e10e946b7f0d0f09
--- /dev/null
+++ b/wp-content/plugins/two-factor/providers/class.two-factor-provider.php
@@ -0,0 +1,96 @@
+<?php
+/**
+ * Abstract class for creating two factor authentication providers.
+ *
+ * @since 0.1-dev
+ *
+ * @package Two_Factor
+ */
+abstract class Two_Factor_Provider {
+
+	/**
+	 * Class constructor.
+	 *
+	 * @since 0.1-dev
+	 */
+	protected function __construct() {
+		return $this;
+	}
+
+	/**
+	 * Returns the name of the provider.
+	 *
+	 * @since 0.1-dev
+	 *
+	 * @return string
+	 */
+	abstract function get_label();
+
+	/**
+	 * Prints the name of the provider.
+	 *
+	 * @since 0.1-dev
+	 */
+	public function print_label() {
+		echo esc_html( $this->get_label() );
+	}
+
+	/**
+	 * Prints the form that prompts the user to authenticate.
+	 *
+	 * @since 0.1-dev
+	 *
+	 * @param WP_User $user WP_User object of the logged-in user.
+	 */
+	abstract function authentication_page( $user );
+
+	/**
+	 * Allow providers to do extra processing before the authentication.
+	 * Return `true` to prevent the authentication and render the
+	 * authentication page.
+	 *
+	 * @param  WP_User $user WP_User object of the logged-in user.
+	 * @return boolean
+	 */
+	public function pre_process_authentication( $user ) {
+		return false;
+	}
+
+	/**
+	 * Validates the users input token.
+	 *
+	 * @since 0.1-dev
+	 *
+	 * @param WP_User $user WP_User object of the logged-in user.
+	 * @return boolean
+	 */
+	abstract function validate_authentication( $user );
+
+	/**
+	 * Whether this Two Factor provider is configured and available for the user specified.
+	 *
+	 * @param WP_User $user WP_User object of the logged-in user.
+	 * @return boolean
+	 */
+	abstract function is_available_for_user( $user );
+
+	/**
+	 * Generate a random eight-digit string to send out as an auth code.
+	 *
+	 * @since 0.1-dev
+	 *
+	 * @param int          $length The code length.
+	 * @param string|array $chars Valid auth code characters.
+	 * @return string
+	 */
+	public function get_code( $length = 8, $chars = '1234567890' ) {
+		$code = '';
+		if ( is_array( $chars ) ) {
+			$chars = implode( '', $chars );
+		}
+		for ( $i = 0; $i < $length; $i++ ) {
+			$code .= substr( $chars, wp_rand( 0, strlen( $chars ) - 1 ), 1 );
+		}
+		return $code;
+	}
+}
diff --git a/wp-content/plugins/two-factor/providers/class.two-factor-totp.php b/wp-content/plugins/two-factor/providers/class.two-factor-totp.php
new file mode 100644
index 0000000000000000000000000000000000000000..d9a56781a7cc86e7a1f5d2b6d37c47740545b5ff
--- /dev/null
+++ b/wp-content/plugins/two-factor/providers/class.two-factor-totp.php
@@ -0,0 +1,509 @@
+<?php
+/**
+ * Class for creating a Time Based One-Time Password provider.
+ *
+ * @package Two_Factor
+ */
+
+/**
+ * Class Two_Factor_Totp
+ */
+class Two_Factor_Totp extends Two_Factor_Provider {
+
+	/**
+	 * The user meta token key.
+	 *
+	 * @var string
+	 */
+	const SECRET_META_KEY = '_two_factor_totp_key';
+
+	/**
+	 * The user meta token key.
+	 *
+	 * @var string
+	 */
+	const NOTICES_META_KEY = '_two_factor_totp_notices';
+
+	const DEFAULT_KEY_BIT_SIZE = 160;
+	const DEFAULT_CRYPTO = 'sha1';
+	const DEFAULT_DIGIT_COUNT = 6;
+	const DEFAULT_TIME_STEP_SEC = 30;
+	const DEFAULT_TIME_STEP_ALLOWANCE = 4;
+	private static $_base_32_chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567';
+
+	/**
+	 * Class constructor. Sets up hooks, etc.
+	 */
+	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' ) );
+		return parent::__construct();
+	}
+
+	/**
+	 * Ensures only one instance of this class exists in memory at any one time.
+	 */
+	public static function get_instance() {
+		static $instance;
+		if ( ! isset( $instance ) ) {
+			$instance = new self();
+		}
+		return $instance;
+	}
+
+	/**
+	 * Returns the name of the provider.
+	 */
+	public function get_label() {
+		return _x( 'Time Based One-Time Password (Google Authenticator)', 'Provider Label', 'two-factor' );
+	}
+
+	/**
+	 * Display TOTP options on the user settings page.
+	 *
+	 * @param WP_User $user The current user being edited.
+	 * @return false
+	 */
+	public function user_two_factor_options( $user ) {
+		if ( ! isset( $user->ID ) ) {
+			return false;
+		}
+
+		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();
+
+		?>
+		<div id="two-factor-totp-options">
+		<?php if ( empty( $key ) ) :
+			$key = $this->generate_key();
+			$site_name = get_bloginfo( 'name', 'display' );
+			$totp_title = apply_filters( 'two_factor_totp_title', $site_name . ':' . $user->user_login, $user );
+			?>
+			<p>
+				<?php esc_html_e( 'Please scan the QR code or manually enter the key, then enter an authentication code from your app in order to complete setup.', 'two-factor' ); ?>
+			</p>
+			<p>
+				<img src="<?php echo esc_url( $this->get_google_qr_code( $totp_title, $key, $site_name ) ); ?>" id="two-factor-totp-qrcode" />
+			</p>
+			<p>
+				<code><?php echo esc_html( $key ); ?></code>
+			</p>
+			<p>
+				<input type="hidden" name="two-factor-totp-key" value="<?php echo esc_attr( $key ); ?>" />
+				<label for="two-factor-totp-authcode">
+					<?php esc_html_e( 'Authentication Code:', 'two-factor' ); ?>
+					<input type="tel" name="two-factor-totp-authcode" id="two-factor-totp-authcode" class="input" value="" size="20" pattern="[0-9]*" />
+				</label>
+				<input type="submit" class="button" name="two-factor-totp-submit" value="<?php esc_attr_e( 'Submit', 'two-factor' ); ?>" />
+			</p>
+		<?php else : ?>
+			<p class="success">
+				<?php esc_html_e( 'Secret key configured and registered.', 'two-factor' ); ?>
+			</p>
+			<p>
+				<input type="submit" class="button" name="two-factor-totp-delete" value="<?php esc_attr_e( 'Reset Key', 'two-factor' ); ?>" />
+				<em class="description">
+					<?php esc_html_e( 'You will have to re-scan the QR code on all devices as the previous codes will stop working.', 'two-factor' ); ?>
+				</em>
+			</p>
+		<?php endif; ?>
+		</div>
+		<?php
+	}
+
+	/**
+	 * Save the options specified in `::user_two_factor_options()`
+	 *
+	 * @param integer $user_id The user ID whose options are being updated.
+	 * @return false
+	 */
+	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'] ) ) {
+					if ( $this->is_valid_authcode( $_POST['two-factor-totp-key'], $_POST['two-factor-totp-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' );
+						}
+					} else {
+						$errors[] = __( 'Invalid Two Factor Authentication code.', 'two-factor' );
+					}
+				} else {
+					$errors[] = __( 'Invalid Two Factor Authentication secret key.', 'two-factor' );
+				}
+			}
+
+			if ( ! empty( $errors ) ) {
+				$notices['error'] = $errors;
+			}
+
+			if ( ! empty( $notices ) ) {
+				update_user_meta( $user_id, self::NOTICES_META_KEY, $notices );
+			}
+		}
+	}
+
+	/**
+	 * Get the TOTP secret key for a user.
+	 *
+	 * @param  int $user_id User ID.
+	 *
+	 * @return string
+	 */
+	public function get_user_totp_key( $user_id ) {
+		return (string) get_user_meta( $user_id, self::SECRET_META_KEY, true );
+	}
+
+	/**
+	 * Set the TOTP secret key for a user.
+	 *
+	 * @param int    $user_id User ID.
+	 * @param string $key TOTP secret key.
+	 *
+	 * @return boolean If the key was stored successfully.
+	 */
+	public function set_user_totp_key( $user_id, $key ) {
+		return update_user_meta( $user_id, self::SECRET_META_KEY, $key );
+	}
+
+	/**
+	 * Delete the TOTP secret key for a user.
+	 *
+	 * @param  int $user_id User ID.
+	 *
+	 * @return boolean If the key was deleted successfully.
+	 */
+	public function delete_user_totp_key( $user_id ) {
+		return delete_user_meta( $user_id, self::SECRET_META_KEY );
+	}
+
+	/**
+	 * Check if the TOTP secret key has a proper format.
+	 *
+	 * @param  string $key TOTP secret key.
+	 *
+	 * @return boolean
+	 */
+	public function is_valid_key( $key ) {
+		$check = sprintf( '/^[%s]+$/', self::$_base_32_chars );
+
+		if ( 1 === preg_match( $check, $key ) ) {
+			return true;
+		}
+
+		return false;
+	}
+
+	/**
+	 * Display any available admin notices.
+	 */
+	public function admin_notices() {
+		$notices = get_user_meta( get_current_user_id(), self::NOTICES_META_KEY, true );
+
+		if ( ! empty( $notices ) ) {
+			delete_user_meta( get_current_user_id(), self::NOTICES_META_KEY );
+			foreach ( $notices as $class => $messages ) {
+				?>
+				<div class="<?php echo esc_attr( $class ) ?>">
+					<?php
+					foreach ( $messages as $msg ) {
+						?>
+						<p>
+							<span><?php echo esc_html( $msg ); ?><span>
+						</p>
+						<?php
+					}
+					?>
+				</div>
+				<?php
+			}
+		}
+	}
+
+	/**
+	 * Validates authentication.
+	 *
+	 * @param WP_User $user WP_User object of the logged-in user.
+	 *
+	 * @return bool Whether the user gave a valid code
+	 */
+	public function validate_authentication( $user ) {
+		if ( ! empty( $_REQUEST['authcode'] ) ) { // WPCS: CSRF ok, nonce verified by login_form_validate_2fa().
+			return $this->is_valid_authcode(
+				$this->get_user_totp_key( $user->ID ),
+				sanitize_text_field( $_REQUEST['authcode'] ) // WPCS: CSRF ok, nonce verified by login_form_validate_2fa().
+			);
+		}
+
+		return false;
+	}
+
+	/**
+	 * Checks if a given code is valid for a given key, allowing for a certain amount of time drift
+	 *
+	 * @param string $key      The share secret key to use.
+	 * @param string $authcode The code to test.
+	 *
+	 * @return bool Whether the code is valid within the time frame
+	 */
+	public static function is_valid_authcode( $key, $authcode ) {
+		/**
+		 * Filter the maximum ticks to allow when checking valid codes.
+		 *
+		 * Ticks are the allowed offset from the correct time in 30 second increments,
+		 * so the default of 4 allows codes that are two minutes to either side of server time
+		 *
+		 * @param int $max_ticks Max ticks of time correction to allow. Default 4.
+		 */
+		$max_ticks = apply_filters( 'two-factor-totp-time-step-allowance', self::DEFAULT_TIME_STEP_ALLOWANCE );
+
+		// Array of all ticks to allow, sorted using absolute value to test closest match first.
+		$ticks = range( - $max_ticks, $max_ticks );
+		usort( $ticks, array( __CLASS__, 'abssort' ) );
+
+		$time = time() / self::DEFAULT_TIME_STEP_SEC;
+
+		foreach ( $ticks as $offset ) {
+			$log_time = $time + $offset;
+			if ( self::calc_totp( $key, $log_time ) === $authcode ) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+	/**
+	 * Generates key
+	 *
+	 * @param int $bitsize Nume of bits to use for key.
+	 *
+	 * @return string $bitsize long string composed of available base32 chars.
+	 */
+	public static function generate_key( $bitsize = self::DEFAULT_KEY_BIT_SIZE ) {
+		$bytes = ceil( $bitsize / 8 );
+		$secret = wp_generate_password( $bytes, true, true );
+
+		return self::base32_encode( $secret );
+	}
+
+	/**
+	 * Pack stuff
+	 *
+	 * @param string $value The value to be packed.
+	 *
+	 * @return string Binary packed string.
+	 */
+	public static function pack64( $value ) {
+		// 64bit mode (PHP_INT_SIZE == 8).
+		if ( PHP_INT_SIZE >= 8 ) {
+			// If we're on PHP 5.6.3+ we can use the new 64bit pack functionality.
+			if ( version_compare( PHP_VERSION, '5.6.3', '>=' ) && PHP_INT_SIZE >= 8 ) {
+				return pack( 'J', $value );
+			}
+			$highmap = 0xffffffff << 32;
+			$higher  = ( $value & $highmap ) >> 32;
+		} else {
+			/*
+			 * 32bit PHP can't shift 32 bits like that, so we have to assume 0 for the higher
+			 * and not pack anything beyond it's limits.
+			 */
+			$higher = 0;
+		}
+
+		$lowmap  = 0xffffffff;
+		$lower   = $value & $lowmap;
+
+		return pack( 'NN', $higher, $lower );
+	}
+
+	/**
+	 * Calculate a valid code given the shared secret key
+	 *
+	 * @param string $key        The shared secret key to use for calculating code.
+	 * @param mixed  $step_count The time step used to calculate the code, which is the floor of time() divided by step size.
+	 * @param int    $digits     The number of digits in the returned code.
+	 * @param string $hash       The hash used to calculate the code.
+	 * @param int    $time_step  The size of the time step.
+	 *
+	 * @return string The totp code
+	 */
+	public static function calc_totp( $key, $step_count = false, $digits = self::DEFAULT_DIGIT_COUNT, $hash = self::DEFAULT_CRYPTO, $time_step = self::DEFAULT_TIME_STEP_SEC ) {
+		$secret = self::base32_decode( $key );
+
+		if ( false === $step_count ) {
+			$step_count = floor( time() / $time_step );
+		}
+
+		$timestamp = self::pack64( $step_count );
+
+		$hash = hash_hmac( $hash, $timestamp, $secret, true );
+
+		$offset = ord( $hash[19] ) & 0xf;
+
+		$code = (
+				( ( ord( $hash[ $offset + 0 ] ) & 0x7f ) << 24 ) |
+				( ( ord( $hash[ $offset + 1 ] ) & 0xff ) << 16 ) |
+				( ( ord( $hash[ $offset + 2 ] ) & 0xff ) << 8 ) |
+				( ord( $hash[ $offset + 3 ] ) & 0xff )
+			) % pow( 10, $digits );
+
+		return str_pad( $code, $digits, '0', STR_PAD_LEFT );
+	}
+
+	/**
+	 * Uses the Google Charts API to build a QR Code for use with an otpauth url
+	 *
+	 * @param string $name  The name to display in the Authentication app.
+	 * @param string $key   The secret key to share with the Authentication app.
+	 * @param string $title The title to display in the Authentication app.
+	 *
+	 * @return string A URL to use as an img src to display the QR code
+	 */
+	public static function get_google_qr_code( $name, $key, $title = null ) {
+		// Encode to support spaces, question marks and other characters.
+		$name = rawurlencode( $name );
+		$google_url = urlencode( 'otpauth://totp/' . $name . '?secret=' . $key );
+		if ( isset( $title ) ) {
+			$google_url .= urlencode( '&issuer=' . rawurlencode( $title ) );
+		}
+		return 'https://chart.googleapis.com/chart?chs=200x200&chld=M|0&cht=qr&chl=' . $google_url;
+	}
+
+	/**
+	 * Whether this Two Factor provider is configured and available for the user specified.
+	 *
+	 * @param WP_User $user WP_User object of the logged-in user.
+	 *
+	 * @return boolean
+	 */
+	public function is_available_for_user( $user ) {
+		// Only available if the secret key has been saved for the user.
+		$key = $this->get_user_totp_key( $user->ID );
+
+		return ! empty( $key );
+	}
+
+	/**
+	 * Prints the form that prompts the user to authenticate.
+	 *
+	 * @param WP_User $user WP_User object of the logged-in user.
+	 */
+	public function authentication_page( $user ) {
+		require_once( ABSPATH .  '/wp-admin/includes/template.php' );
+		?>
+		<p>
+			<label for="authcode"><?php esc_html_e( 'Authentication Code:', 'two-factor' ); ?></label>
+			<input type="tel" name="authcode" id="authcode" class="input" value="" size="20" pattern="[0-9]*" />
+		</p>
+		<script type="text/javascript">
+			setTimeout( function(){
+				var d;
+				try{
+					d = document.getElementById('authcode');
+					d.value = '';
+					d.focus();
+				} catch(e){}
+			}, 200);
+		</script>
+		<?php
+		submit_button( __( 'Authenticate', 'two-factor' ) );
+	}
+
+	/**
+	 * Returns a base32 encoded string.
+	 *
+	 * @param string $string String to be encoded using base32.
+	 *
+	 * @return string base32 encoded string without padding.
+	 */
+	public static function base32_encode( $string ) {
+		if ( empty( $string ) ) {
+			return '';
+		}
+
+		$binary_string = '';
+
+		foreach ( str_split( $string ) as $character ) {
+			$binary_string .= str_pad( base_convert( ord( $character ), 10, 2 ), 8, '0', STR_PAD_LEFT );
+		}
+
+		$five_bit_sections = str_split( $binary_string, 5 );
+		$base32_string = '';
+
+		foreach ( $five_bit_sections as $five_bit_section ) {
+			$base32_string .= self::$_base_32_chars[ base_convert( str_pad( $five_bit_section, 5, '0' ), 2, 10 ) ];
+		}
+
+		return $base32_string;
+	}
+
+	/**
+	 * Decode a base32 string and return a binary representation
+	 *
+	 * @param string $base32_string The base 32 string to decode.
+	 *
+	 * @throws Exception If string contains non-base32 characters.
+	 *
+	 * @return string Binary representation of decoded string
+	 */
+	public static function base32_decode( $base32_string ) {
+
+		$base32_string 	= strtoupper( $base32_string );
+
+		if ( ! preg_match( '/^[' . self::$_base_32_chars . ']+$/', $base32_string, $match ) ) {
+			throw new Exception( 'Invalid characters in the base32 string.' );
+		}
+
+		$l 	= strlen( $base32_string );
+		$n	= 0;
+		$j	= 0;
+		$binary = '';
+
+		for ( $i = 0; $i < $l; $i++ ) {
+
+			$n = $n << 5; // Move buffer left by 5 to make room.
+			$n = $n + strpos( self::$_base_32_chars, $base32_string[ $i ] ); 	// Add value into buffer.
+			$j += 5; // Keep track of number of bits in buffer.
+
+			if ( $j >= 8 ) {
+				$j -= 8;
+				$binary .= chr( ( $n & ( 0xFF << $j ) ) >> $j );
+			}
+		}
+
+		return $binary;
+	}
+
+	/**
+	 * Used with usort to sort an array by distance from 0
+	 *
+	 * @param int $a First array element.
+	 * @param int $b Second array element.
+	 *
+	 * @return int -1, 0, or 1 as needed by usort
+	 */
+	private static function abssort( $a, $b ) {
+		$a = abs( $a );
+		$b = abs( $b );
+		if ( $a === $b ) {
+			return 0;
+		}
+		return ($a < $b) ? -1 : 1;
+	}
+}
diff --git a/wp-content/plugins/two-factor/providers/css/fido-u2f-admin.css b/wp-content/plugins/two-factor/providers/css/fido-u2f-admin.css
new file mode 100644
index 0000000000000000000000000000000000000000..947dbf43255ea44863424506c2419d6c35c2656b
--- /dev/null
+++ b/wp-content/plugins/two-factor/providers/css/fido-u2f-admin.css
@@ -0,0 +1,10 @@
+#security-keys-section .wp-list-table {
+	margin-bottom: 2em;
+}
+#security-keys-section .register-security-key .spinner {
+	float: none;
+}
+#security-keys-section .security-key-status {
+	vertical-align: middle;
+	font-style: italic;
+}
diff --git a/wp-content/plugins/two-factor/providers/js/fido-u2f-admin-inline-edit.js b/wp-content/plugins/two-factor/providers/js/fido-u2f-admin-inline-edit.js
new file mode 100644
index 0000000000000000000000000000000000000000..8f40372babda610ccee947155f213f29b10df4de
--- /dev/null
+++ b/wp-content/plugins/two-factor/providers/js/fido-u2f-admin-inline-edit.js
@@ -0,0 +1,145 @@
+/* global inlineEditL10n, ajaxurl */
+var inlineEditKey;
+
+( function( $ ) {
+	inlineEditKey = {
+
+		init: function() {
+			var t = this,
+				row = $( '#security-keys-section #inline-edit' );
+
+			t.what = '#key-';
+
+			$( '#security-keys-section #the-list' ).on( 'click', 'a.editinline', function() {
+				inlineEditKey.edit( this );
+				return false;
+			} );
+
+			// Prepare the edit row.
+			row.keyup( function( event ) {
+				if ( 27 === event.which ) {
+					return inlineEditKey.revert();
+				}
+			} );
+
+			$( 'a.cancel', row ).click( function() {
+				return inlineEditKey.revert();
+			} );
+
+			$( 'a.save', row ).click( function() {
+				return inlineEditKey.save( this );
+			} );
+
+			$( 'input, select', row ).keydown( function( event ) {
+				if ( 13 === event.which ) {
+					return inlineEditKey.save( this );
+				}
+			} );
+		},
+
+		toggle: function( el ) {
+			var t = this;
+			'none' === $( t.what + t.getId( el ) ).css( 'display' ) ? t.revert() : t.edit( el );
+		},
+
+		edit: function( id ) {
+			var editRow, rowData, val,
+				t = this;
+			t.revert();
+
+			if ( 'object' === typeof id ) {
+				id = t.getId( id );
+			}
+
+			editRow = $( '#inline-edit' ).clone( true ), rowData = $( '#inline_' + id );
+			$( 'td', editRow ).attr( 'colspan', $( 'th:visible, td:visible', '#security-keys-section .widefat thead' ).length );
+
+			$( t.what + id ).hide().after( editRow ).after( '<tr class="hidden"></tr>' );
+
+			val = $( '.name', rowData );
+			val.find( 'img' ).replaceWith( function() {
+				return this.alt;
+			} );
+			val = val.text();
+			$( ':input[name="name"]', editRow ).val( val );
+
+			$( editRow ).attr( 'id', 'edit-' + id ).addClass( 'inline-editor' ).show();
+			$( '.ptitle', editRow ).eq( 0 ).focus();
+
+			return false;
+		},
+
+		save: function( id ) {
+			var params, fields;
+
+			if ( 'object' === typeof id ) {
+				id = this.getId( id );
+			}
+
+			$( '#security-keys-section table.widefat .spinner' ).addClass( 'is-active' );
+
+			params = {
+				action: 'inline-save-key',
+				keyHandle: id
+			};
+
+			fields = $( '#edit-' + id ).find( ':input' ).serialize();
+			params = fields + '&' + $.param( params );
+
+			// Make ajax request.
+			$.post( ajaxurl, params,
+				function( r ) {
+					var row, newID, optionValue;
+					$( '#security-keys-section table.widefat .spinner' ).removeClass( 'is-active' );
+
+					if ( r ) {
+						if ( -1 !== r.indexOf( '<tr' ) ) {
+							$( inlineEditKey.what + id ).siblings( 'tr.hidden' ).addBack().remove();
+							newID = $( r ).attr( 'id' );
+
+							$( '#edit-' + id ).before( r ).remove();
+
+							if ( newID ) {
+								optionValue = newID.replace( 'key-', '' );
+								row = $( '#' + newID );
+							} else {
+								optionValue = id;
+								row = $( inlineEditKey.what + id );
+							}
+
+							row.hide().fadeIn();
+						} else {
+							$( '#edit-' + id + ' .inline-edit-save .error' ).html( r ).show();
+						}
+					} else {
+						$( '#edit-' + id + ' .inline-edit-save .error' ).html( inlineEditL10n.error ).show();
+					}
+				}
+			);
+			return false;
+		},
+
+		revert: function() {
+			var id = $( '#security-keys-section table.widefat tr.inline-editor' ).attr( 'id' );
+
+			if ( id ) {
+				$( '#security-keys-section table.widefat .spinner' ).removeClass( 'is-active' );
+				$( '#' + id ).siblings( 'tr.hidden' ).addBack().remove();
+				id = id.replace( /\w+\-/, '' );
+				$( this.what + id ).show();
+			}
+
+			return false;
+		},
+
+		getId: function( o ) {
+			var id = 'TR' === o.tagName ? o.id : $( o ).parents( 'tr' ).attr( 'id' );
+			return id.replace( /\w+\-/, '' );
+		}
+	};
+
+	$( document ).ready( function() {
+		inlineEditKey.init();
+	} );
+
+} )( jQuery );
diff --git a/wp-content/plugins/two-factor/providers/js/fido-u2f-admin.js b/wp-content/plugins/two-factor/providers/js/fido-u2f-admin.js
new file mode 100644
index 0000000000000000000000000000000000000000..66bb0238a880ff324d1fd20f7ebf46d58e80acb5
--- /dev/null
+++ b/wp-content/plugins/two-factor/providers/js/fido-u2f-admin.js
@@ -0,0 +1,48 @@
+/* global u2f, u2fL10n */
+( function( $ ) {
+	var $button = $( '#register_security_key' );
+	var $statusNotice = $( '#security-keys-section .security-key-status' );
+	var u2fSupported = ( window.u2f && 'register' in window.u2f );
+
+	if ( ! u2fSupported ) {
+		$statusNotice.text( u2fL10n.text.u2f_not_supported );
+	}
+
+	$button.click( function() {
+		var registerRequest;
+
+		if ( $( this ).prop( 'disabled' ) ) {
+			return false;
+		}
+
+		$( this ).prop( 'disabled', true );
+		$( '.register-security-key .spinner' ).addClass( 'is-active' );
+		$statusNotice.text( '' );
+
+		registerRequest = {
+			version: u2fL10n.register.request.version,
+			challenge: u2fL10n.register.request.challenge
+		};
+
+		window.u2f.register( u2fL10n.register.request.appId, [ registerRequest ], u2fL10n.register.sigs, function( data ) {
+			$( '.register-security-key .spinner' ).removeClass( 'is-active' );
+			$button.prop( 'disabled', false );
+
+			if ( data.errorCode ) {
+				if ( u2fL10n.text.error_codes[ data.errorCode ] ) {
+					$statusNotice.text( u2fL10n.text.error_codes[ data.errorCode ] );
+				} else {
+					$statusNotice.text( u2fL10n.text.error_codes[ u2fL10n.text.error ] );
+				}
+
+				return false;
+			}
+
+			$( '#do_new_security_key' ).val( 'true' );
+			$( '#u2f_response' ).val( JSON.stringify( data ) );
+
+			// See: http://stackoverflow.com/questions/833032/submit-is-not-a-function-error-in-javascript
+			$( '<form>' )[0].submit.call( $( '#your-profile' )[0] );
+		} );
+	} );
+} )( jQuery );
diff --git a/wp-content/plugins/two-factor/providers/js/fido-u2f-login.js b/wp-content/plugins/two-factor/providers/js/fido-u2f-login.js
new file mode 100644
index 0000000000000000000000000000000000000000..0fe4cb1ab5f2a4fa012de47b3561b2fbdcf5aea3
--- /dev/null
+++ b/wp-content/plugins/two-factor/providers/js/fido-u2f-login.js
@@ -0,0 +1,16 @@
+/* global u2f, u2fL10n */
+( function( $ ) {
+	if ( ! window.u2fL10n ) {
+		window.console.error( 'u2fL10n is not defined' );
+		return;
+	}
+
+	u2f.sign( u2fL10n.request[0].appId, u2fL10n.request[0].challenge, u2fL10n.request, function( data ) {
+		if ( data.errorCode ) {
+			window.console.error( 'Registration Failed', data.errorCode );
+		} else {
+			$( '#u2f_response' ).val( JSON.stringify( data ) );
+			$( '#loginform' ).submit();
+		}
+	} );
+} )( jQuery );
diff --git a/wp-content/plugins/two-factor/readme.md b/wp-content/plugins/two-factor/readme.md
new file mode 100644
index 0000000000000000000000000000000000000000..97bf5210a377c398fda13c3705eb8596b7df7fca
--- /dev/null
+++ b/wp-content/plugins/two-factor/readme.md
@@ -0,0 +1,51 @@
+<!-- DO NOT EDIT THIS FILE; it is auto-generated from readme.txt -->
+# Two-Factor
+
+![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)  
+**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.2  
+**Stable tag:** trunk (master)  
+
+[![Build Status](https://travis-ci.org/georgestephanis/two-factor.svg?branch=master)](https://travis-ci.org/georgestephanis/two-factor) [![Coverage Status](https://coveralls.io/repos/georgestephanis/two-factor/badge.svg?branch=master)](https://coveralls.io/github/georgestephanis/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:
+
+- 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://stephanis.info/2013/08/14/two-cents-on-two-factor/).
+
+## Screenshots ##
+
+### Two-factor options under User Profile.
+
+![Two-factor options under User Profile.](assets/screenshot-1.png)
+
+### U2F Security Keys section under User Profile.
+
+![U2F Security Keys section under User Profile.](assets/screenshot-2.png)
+
+## Get Involved ##
+
+Development happens [on GitHub](https://github.com/georgestephanis/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/georgestephanis/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 ##
+
+See the [release history](https://github.com/georgestephanis/two-factor/releases).
+
diff --git a/wp-content/plugins/two-factor/readme.txt b/wp-content/plugins/two-factor/readme.txt
new file mode 100644
index 0000000000000000000000000000000000000000..6baa4caa8561a961a584c41e93beb1f3339ed590
--- /dev/null
+++ b/wp-content/plugins/two-factor/readme.txt
@@ -0,0 +1,42 @@
+=== Two-Factor ===
+Contributors: georgestephanis, valendesigns, stevenkword, extendwings, sgrant, aaroncampbell, johnbillion, stevegrunwell, netweb, kasparsd
+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.2
+Stable tag: trunk
+
+Enable Two-Factor Authentication using time-based one-time passwords (OTP, Google Authenticator), Universal 2nd Factor (FIDO U2F, YubiKey), email and backup verification codes.
+
+== 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:
+
+- 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://stephanis.info/2013/08/14/two-cents-on-two-factor/).
+
+
+== Screenshots ==
+
+1. Two-factor options under User Profile.
+2. U2F Security Keys section under User Profile.
+
+
+== Get Involved ==
+
+Development happens [on GitHub](https://github.com/georgestephanis/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/georgestephanis/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 ==
+
+See the [release history](https://github.com/georgestephanis/two-factor/releases).
diff --git a/wp-content/plugins/two-factor/two-factor.php b/wp-content/plugins/two-factor/two-factor.php
new file mode 100644
index 0000000000000000000000000000000000000000..636e29cd7ebc37abe555cbe40cbd8b15ad1b9d2c
--- /dev/null
+++ b/wp-content/plugins/two-factor/two-factor.php
@@ -0,0 +1,28 @@
+<?php
+/**
+ * Plugin Name: Two Factor
+ * Plugin URI: https://wordpress.org/plugins/two-factor/
+ * Description: A prototype extensible core to enable Two-Factor Authentication.
+ * Author: Plugin Contributors
+ * Version: 0.4.7
+ * Author URI: https://github.com/georgestephanis/two-factor/graphs/contributors
+ * Network: True
+ * Text Domain: two-factor
+ */
+
+/**
+ * Shortcut constant to the path of this file.
+ */
+define( 'TWO_FACTOR_DIR', plugin_dir_path( __FILE__ ) );
+
+/**
+ * Include the base class here, so that other plugins can also extend it.
+ */
+require_once( TWO_FACTOR_DIR . 'providers/class.two-factor-provider.php' );
+
+/**
+ * Include the core that handles the common bits.
+ */
+require_once( TWO_FACTOR_DIR . 'class.two-factor-core.php' );
+
+Two_Factor_Core::add_hooks();
diff --git a/wp-content/plugins/two-factor/user-edit.css b/wp-content/plugins/two-factor/user-edit.css
new file mode 100644
index 0000000000000000000000000000000000000000..9572fb6fc28f04c98b2715e0cc33400584602c8d
--- /dev/null
+++ b/wp-content/plugins/two-factor/user-edit.css
@@ -0,0 +1,37 @@
+
+.two-factor-methods-table {
+	background-color: #fff;
+	border: 1px solid #e5e5e5;
+	border-spacing: 0;
+}
+
+.two-factor-methods-table thead,
+.two-factor-methods-table tfoot {
+	background: #fff;
+}
+
+.two-factor-methods-table thead th {
+	padding: 0.5em;
+}
+
+.two-factor-methods-table .col-primary,
+.two-factor-methods-table .col-enabled {
+	width: 5%;
+}
+
+.two-factor-methods-table .col-name {
+	width: 90%;
+}
+
+.two-factor-methods-table tbody th {
+	text-align: center;
+}
+
+.two-factor-methods-table tbody th,
+.two-factor-methods-table tbody td {
+	vertical-align: top;
+}
+
+.two-factor-methods-table tbody tr:nth-child(odd) {
+	background-color: #f9f9f9;
+}
\ No newline at end of file