/**
  * Build rewrite rules.
  *
  * @since 4.0
  *
  * @param mixed $input options to build rules from
  *
  * @return array         rules to write
  */
 public static function build_rewrite_rules($input = null)
 {
     $server_type = ITSEC_Lib::get_server();
     //Get the server type to build the right rules
     //Get the rules from the database if input wasn't sent
     if ($input === null) {
         $input = get_site_option('itsec_tweaks');
     }
     $rules = '';
     //initialize all rules to blank string
     //Process Protect Files Rules
     if ($input['protect_files'] === true) {
         if ($server_type === 'nginx') {
             //NGINX rules
             $rules .= "\t# " . __('Rules to block access to WordPress specific files and wp-includes', 'it-l10n-ithemes-security-pro') . PHP_EOL . "\tlocation ~ /\\.ht { deny all; }" . PHP_EOL . "\tlocation ~ wp-config.php { deny all; }" . PHP_EOL . "\tlocation ~ readme.html { deny all; }" . PHP_EOL . "\tlocation ~ readme.txt { deny all; }" . PHP_EOL . "\tlocation ~ /install.php { deny all; }" . PHP_EOL . "\tlocation ^wp-includes/(.*).php { deny all; }" . PHP_EOL . "\tlocation ^/wp-admin/includes(.*)\$ { deny all; }" . PHP_EOL;
         } else {
             //rules for all other servers
             $rules .= "# " . __('Rules to block access to WordPress specific files', 'it-l10n-ithemes-security-pro') . PHP_EOL . "<files .htaccess>" . PHP_EOL . "\tOrder allow,deny" . PHP_EOL . "\tDeny from all" . PHP_EOL . "</files>" . PHP_EOL . "<files readme.html>" . PHP_EOL . "\tOrder allow,deny" . PHP_EOL . "\tDeny from all" . PHP_EOL . "</files>" . PHP_EOL . "<files readme.txt>" . PHP_EOL . "\tOrder allow,deny" . PHP_EOL . "\tDeny from all" . PHP_EOL . "</files>" . PHP_EOL . "<files install.php>" . PHP_EOL . "\tOrder allow,deny" . PHP_EOL . "\tDeny from all" . PHP_EOL . "</files>" . PHP_EOL . "<files wp-config.php>" . PHP_EOL . "\tOrder allow,deny" . PHP_EOL . "\tDeny from all" . PHP_EOL . "</files>" . PHP_EOL;
         }
     }
     //Rules to disanle XMLRPC
     if ($input['disable_xmlrpc'] == 2) {
         if (strlen($rules) > 1) {
             $rules .= PHP_EOL;
         }
         $rules .= "# " . __('Rules to disable XML-RPC', 'it-l10n-ithemes-security-pro') . PHP_EOL;
         if ($server_type === 'nginx') {
             //NGINX rules
             $rules .= "\tlocation ~ xmlrpc.php { deny all; }" . PHP_EOL;
         } else {
             //rules for all other servers
             $rules .= "<files xmlrpc.php>" . PHP_EOL . "\tOrder allow,deny" . PHP_EOL . "\tDeny from all" . PHP_EOL . "</files>" . PHP_EOL;
         }
     }
     //Primary Rules for Directory Browsing
     if ($input['directory_browsing'] == true) {
         if (strlen($rules) > 1) {
             $rules .= PHP_EOL;
         }
         $rules .= "# " . __('Rules to disable directory browsing', 'it-l10n-ithemes-security-pro') . PHP_EOL;
         if ($server_type !== 'nginx') {
             //Don't use this on NGINX
             $rules .= "Options -Indexes" . PHP_EOL;
         }
     }
     //Apache rewrite rules (and related NGINX rules)
     if ($input['protect_files'] == true || $input['uploads_php'] == true || $input['request_methods'] == true || $input['suspicious_query_strings'] == true || $input['non_english_characters'] == true || $input['comment_spam'] == true) {
         if (strlen($rules) > 1) {
             $rules .= PHP_EOL;
         }
         //Open Apache rewrite rules
         if ($server_type !== 'nginx') {
             $rules .= "<IfModule mod_rewrite.c>" . PHP_EOL . "\tRewriteEngine On" . PHP_EOL;
         }
         //Rewrite Rules for Protect Files
         if ($input['protect_files'] == true && $server_type !== 'nginx') {
             $rules .= PHP_EOL . "\t# " . __('Rules to protect wp-includes', 'it-l10n-ithemes-security-pro') . PHP_EOL;
             $rules .= "\tRewriteRule ^wp-admin/includes/ - [F]" . PHP_EOL . "\tRewriteRule !^wp-includes/ - [S=3]" . PHP_EOL . "\tRewriteCond %{SCRIPT_FILENAME} !^(.*)wp-includes/ms-files.php" . PHP_EOL . "\tRewriteRule ^wp-includes/[^/]+\\.php\$ - [F]" . PHP_EOL . "\tRewriteRule ^wp-includes/js/tinymce/langs/.+\\.php - [F]" . PHP_EOL . "\tRewriteRule ^wp-includes/theme-compat/ - [F]" . PHP_EOL;
         }
         //Rewrite Rules for Disable PHP in Uploads
         if ($input['uploads_php'] === true) {
             $rules .= PHP_EOL . "\t# " . __('Rules to prevent php execution in uploads', 'it-l10n-ithemes-security-pro') . PHP_EOL;
             if ($server_type !== 'nginx') {
                 $rules .= "\tRewriteRule ^(.*)/uploads/(.*).php(.?) - [F]" . PHP_EOL;
             } else {
                 //rules for all other servers
                 $rules .= "\tlocation ^(.*)/uploads/(.*).php(.?){ deny all; }" . PHP_EOL;
             }
         }
         //Apache rewrite rules for disable http methods
         if ($input['request_methods'] == true) {
             $rules .= PHP_EOL . "\t# " . __('Rules to block unneeded HTTP methods', 'it-l10n-ithemes-security-pro') . PHP_EOL;
             if ($server_type === 'nginx') {
                 //NGINX rules
                 $rules .= "\tif (\$request_method ~* \"^(TRACE|DELETE|TRACK)\"){ return 403; }" . PHP_EOL;
             } else {
                 //rules for all other servers
                 $rules .= "\tRewriteCond %{REQUEST_METHOD} ^(TRACE|DELETE|TRACK) [NC]" . PHP_EOL . "\tRewriteRule ^(.*)\$ - [F]" . PHP_EOL;
             }
         }
         //Process suspicious query rules
         if ($input['suspicious_query_strings'] == true) {
             $rules .= PHP_EOL . "\t# " . __('Rules to block suspicious URIs', 'it-l10n-ithemes-security-pro') . PHP_EOL;
             if ($server_type === 'nginx') {
                 //NGINX rules
                 $rules .= "\tset \$susquery 0;" . PHP_EOL . "\tif (\$args ~* \"\\.\\./\") { set \$susquery 1; }" . PHP_EOL . "\tif (\$args ~* \"\\.(bash|git|hg|log|svn|swp|cvs)\") { set \$susquery 1; }" . PHP_EOL . "\tif (\$args ~* \"etc/passwd\") { set \$susquery 1; }" . PHP_EOL . "\tif (\$args ~* \"boot.ini\") { set \$susquery 1; }" . PHP_EOL . "\tif (\$args ~* \"ftp:\") { set \$susquery 1; }" . PHP_EOL . "\tif (\$args ~* \"http:\") { set \$susquery 1; }" . PHP_EOL . "\tif (\$args ~* \"https:\") { set \$susquery 1; }" . PHP_EOL . "\tif (\$args ~* \"(<|%3C).*script.*(>|%3E)\") { set \$susquery 1; }" . PHP_EOL . "\tif (\$args ~* \"mosConfig_[a-zA-Z_]{1,21}(=|%3D)\") { set \$susquery 1; }" . PHP_EOL . "\tif (\$args ~* \"base64_encode\") { set \$susquery 1; }" . PHP_EOL . "\tif (\$args ~* \"(%24&x)\") { set \$susquery 1; }" . PHP_EOL . "\tif (\$args ~* \"(127.0)\") { set \$susquery 1; }" . PHP_EOL . "\tif (\$args ~* \"(globals|encode|localhost|loopback)\") { set \$susquery 1; }" . PHP_EOL . "\tif (\$args ~* \"(request|insert|concat|union|declare)\") { set \$susquery 1; }" . PHP_EOL . "\tif (\$args !~ \"^loggedout=true\"){ set \$susquery 0; }" . PHP_EOL . "\tif (\$args !~ \"^action=jetpack-sso\"){ set \$susquery 0; }" . PHP_EOL . "\tif (\$args !~ \"^action=rp\"){ set \$susquery 0; }" . PHP_EOL . "\tif (\$http_cookie !~ \"^.*wordpress_logged_in_.*\$\"){ set \$susquery 0; }" . PHP_EOL . "\tif (\$http_referer !~ \"^http://maps.googleapis.com(.*)\$\"){ set \$susquery 0; }" . PHP_EOL . "\tif (\$susquery = 1) { return 403; } " . PHP_EOL;
             } else {
                 //rules for all other servers
                 $rules .= "\tRewriteCond %{QUERY_STRING} \\.\\.\\/ [NC,OR]" . PHP_EOL . "\tRewriteCond %{QUERY_STRING} ^.*\\.(bash|git|hg|log|svn|swp|cvs) [NC,OR]" . PHP_EOL . "\tRewriteCond %{QUERY_STRING} etc/passwd [NC,OR]" . PHP_EOL . "\tRewriteCond %{QUERY_STRING} boot\\.ini [NC,OR]" . PHP_EOL . "\tRewriteCond %{QUERY_STRING} ftp\\:  [NC,OR]" . PHP_EOL . "\tRewriteCond %{QUERY_STRING} http\\:  [NC,OR]" . PHP_EOL . "\tRewriteCond %{QUERY_STRING} https\\:  [NC,OR]" . PHP_EOL . "\tRewriteCond %{QUERY_STRING} (\\<|%3C).*script.*(\\>|%3E) [NC,OR]" . PHP_EOL . "\tRewriteCond %{QUERY_STRING} mosConfig_[a-zA-Z_]{1,21}(=|%3D) [NC,OR]" . PHP_EOL . "\tRewriteCond %{QUERY_STRING} base64_encode.*\\(.*\\) [NC,OR]" . PHP_EOL . "\tRewriteCond %{QUERY_STRING} ^.*(%24&x).* [NC,OR]" . PHP_EOL . "\tRewriteCond %{QUERY_STRING} ^.*(127\\.0).* [NC,OR]" . PHP_EOL . "\tRewriteCond %{QUERY_STRING} ^.*(globals|encode|localhost|loopback).* [NC,OR]" . PHP_EOL . "\tRewriteCond %{QUERY_STRING} ^.*(request|concat|insert|union|declare).* [NC]" . PHP_EOL . "\tRewriteCond %{QUERY_STRING} !^loggedout=true" . PHP_EOL . "\tRewriteCond %{QUERY_STRING} !^action=jetpack-sso" . PHP_EOL . "\tRewriteCond %{QUERY_STRING} !^action=rp" . PHP_EOL . "\tRewriteCond %{HTTP_COOKIE} !^.*wordpress_logged_in_.*\$" . PHP_EOL . "\tRewriteCond %{HTTP_REFERER} !^http://maps\\.googleapis\\.com(.*)\$" . PHP_EOL . "\tRewriteRule ^(.*)\$ - [F]" . PHP_EOL;
             }
         }
         //Process filtering of foreign characters
         if ($input['non_english_characters'] == true) {
             $rules .= PHP_EOL . "\t# " . __('Rules to block foreign characters in URLs', 'it-l10n-ithemes-security-pro') . PHP_EOL;
             if ($server_type === 'nginx') {
                 //NGINX rules
                 $rules .= "\tif (\$args ~* \"(%0|%A|%B|%C|%D|%E|%F)\") { return 403; }" . PHP_EOL;
             } else {
                 //rules for all other servers
                 $rules .= "\tRewriteCond %{QUERY_STRING} ^.*(%0|%A|%B|%C|%D|%E|%F).* [NC]" . PHP_EOL . "\tRewriteRule ^(.*)\$ - [F]" . PHP_EOL;
             }
         }
         //Process Comment spam rules
         if ($input['comment_spam'] == true) {
             $rules .= PHP_EOL . "\t# " . __('Rules to help reduce spam', 'it-l10n-ithemes-security-pro') . PHP_EOL;
             if ($server_type === 'nginx') {
                 //NGINX rules
                 $rules .= "\tlocation /wp-comments-post.php {" . PHP_EOL . "\t\tvalid_referers jetpack.wordpress.com/jetpack-comment/ " . ITSEC_Lib::get_domain(get_site_url(), false) . ";" . PHP_EOL . "\t\tset \$rule_0 0;" . PHP_EOL . "\t\tif (\$request_method ~ \"POST\"){ set \$rule_0 1\$rule_0; }" . PHP_EOL . "\t\tif (\$invalid_referer) { set \$rule_0 2\$rule_0; }" . PHP_EOL . "\t\tif (\$http_user_agent ~ \"^\$\"){ set \$rule_0 3\$rule_0; }" . PHP_EOL . "\t\tif (\$rule_0 = \"3210\") { return 403; }" . PHP_EOL . "\t}";
             } else {
                 //rules for all other servers
                 $rules .= "\tRewriteCond %{REQUEST_METHOD} POST" . PHP_EOL . "\tRewriteCond %{REQUEST_URI} ^(.*)wp-comments-post\\.php*" . PHP_EOL . "\tRewriteCond %{HTTP_REFERER} !^" . ITSEC_Lib::get_domain(get_site_url()) . ".* " . PHP_EOL . "\tRewriteCond %{HTTP_REFERER} !^http://jetpack\\.wordpress\\.com/jetpack-comment/ [OR]" . PHP_EOL . "\tRewriteCond %{HTTP_USER_AGENT} ^\$" . PHP_EOL . "\tRewriteRule ^(.*)\$ - [F]" . PHP_EOL;
             }
         }
         //Close Apache Rewrite rules
         if ($server_type !== 'nginx') {
             //non NGINX rules
             $rules .= "</IfModule>";
         }
     }
     if (strlen($rules) > 0) {
         $rules = explode(PHP_EOL, $rules);
     } else {
         $rules = false;
     }
     //create a proper array for writing
     return array('type' => 'htaccess', 'priority' => 10, 'name' => 'Tweaks', 'rules' => $rules);
 }
	protected function get_valid_referers( $server_type ) {
		$valid_referers = array();
		
		if ( 'apache' === $server_type ) {
			$domain = ITSEC_Lib::get_domain( get_site_url() );
			
			if ( '*' == $domain ) {
				$valid_referers[] = $domain;
			} else {
				$valid_referers[] = "*.$domain";
			}
		} else if ( 'nginx' === $server_type ) {
			$valid_referers[] = 'server_names';
		} else {
			return array();
		}
		
		$valid_referers[] = 'jetpack.wordpress.com/jetpack-comment/';
		$valid_referers = apply_filters( 'itsec_filter_valid_comment_referers', $valid_referers, $server_type );
		
		if ( is_string( $valid_referers ) ) {
			$valid_referers = array( $valid_referers );
		} else if ( ! is_array( $valid_referers ) ) {
			$valid_referers = array();
		}
		
		foreach ( $valid_referers as $index => $referer ) {
			$valid_referers[$index] = preg_replace( '|^https?://|', '', $referer );
		}
		
		return $valid_referers;
	}
	/**
	 * Sanitize and update user options.
	 *
	 * Sanitizes and updates user options when a user saves two-factor settings
	 * on their own profile.
	 *
	 * @since 1.2.0
	 *
	 * @param int $user_id user id
	 *
	 * @return void
	 */
	public function personal_options_update( $user_id ) {

		$enabled       = 'off';
		$enabled_input = isset( $_POST['itsec_two_factor_enabled'] ) ? sanitize_text_field( $_POST['itsec_two_factor_enabled'] ) : 'off';
		$description   = isset( $_POST['itsec_two_factor_description'] ) ? sanitize_text_field( $_POST['itsec_two_factor_description'] ) : ITSEC_Lib::get_domain( get_site_url(), false, false );
		$key           = isset( $_POST['itsec_two_factor_key'] ) ? sanitize_text_field( $_POST['itsec_two_factor_key'] ) : ITSEC_Lib::get_random( 16, true );
		$use_app       = isset( $_POST['itsec_two_factor_use_app'] ) ? sanitize_text_field( $_POST['itsec_two_factor_use_app'] ) : 'off';

		$app_passes = array();

		if ( isset( $_POST['itsec_app_pass'] ) ) {

			$saved_passes = get_user_option( 'itsec_two_factor_app_pass', $user_id );

			if ( false === $saved_passes ) {

				$saved_passes = array();

			} elseif ( ! is_array( $saved_passes ) ) {

				$app_passes = array(
					__( 'unknown', 'it-l10n-ithemes-security-pro' ) => $saved_passes,
				);

			}

			//Prevent duplicates or changing password to all hashes
			foreach ( $_POST['itsec_app_pass'] as $app_pass ) {

				$name = sanitize_text_field( trim( $app_pass['name'] ) );

				if ( ! isset( $saved_passes[ $name ] ) ) {

					$pass = wp_hash_password( strtoupper( str_replace( ' ', '', sanitize_text_field( trim( $app_pass['pass'] ) ) ) ) );

					$app_passes[ $name ] = $pass;

				} else {

					$app_passes[ $name ] = $saved_passes[ $name ];

				}

			}

		}

		$time = floor( time() / 30 ); //time to check

		if ( ( 'off' === get_user_option( 'itsec_two_factor_enabled', $user_id ) && 'on' === $enabled_input ) || ( $key !== get_user_option( 'itsec_two_factor_key', $user_id ) ) ) {

			if ( isset( $_POST['itsec_two_factor_confirm'] ) ) {

				$code = sanitize_text_field( trim( $_POST['itsec_two_factor_confirm'] ) );

			} else {

				$code = false;

			}

			if ( false !== $code && 0 < strlen( $code ) ) {

				$good_code = false;

				$offset = isset( $this->settings['offset'] ) ? intval( $this->settings['offset'] ) : 1;

				//Check both sides of the time
				for ( $i = - $offset; $i <= $offset; $i ++ ) {

					$log_time = $time + $i;

					if ( $this->get_code( $key, $log_time ) === $code ) {

						$enabled   = $enabled_input;
						$good_code = true;

					}

				}

			} else {

				$good_code = false;

			}

			if ( false === $good_code ) {
				add_action( 'user_profile_update_errors', array( $this, 'user_profile_update_errors' ), 10, 3 );
			}

		} else {

			$enabled = $enabled_input;

		}

		update_user_option( $user_id, 'itsec_two_factor_enabled', $enabled, true );
		update_user_option( $user_id, 'itsec_two_factor_description', $description, true );
		update_user_option( $user_id, 'itsec_two_factor_key', $key, true );

		if ( 'off' !== $use_app ) {

			if ( 1 > sizeof( $app_passes ) ) {

				$use_app = 'off';
				delete_user_option( $user_id, 'itsec_two_factor_app_pass', true );

			} else {

				update_user_option( $user_id, 'itsec_two_factor_app_pass', $app_passes, true );

			}

		}

		update_user_option( $user_id, 'itsec_two_factor_use_app', $use_app, true );

	}