diff --git a/admin/CF7_AntiSpam_Admin_Customizations.php b/admin/CF7_AntiSpam_Admin_Customizations.php index f6d4d72..3071068 100644 --- a/admin/CF7_AntiSpam_Admin_Customizations.php +++ b/admin/CF7_AntiSpam_Admin_Customizations.php @@ -5,6 +5,7 @@ use CF7_AntiSpam\Core\CF7_AntiSpam; use CF7_AntiSpam\Core\CF7_Antispam_Geoip; use WP_Query; +use function cli\err; /** * The plugin settings. @@ -1007,6 +1008,37 @@ private function cf7a_input_cron_schedule( $input, $input_name, $cron_task, $sch } + private function cf7a_clean_agnostic( $value ) { + if ( is_bool( $value ) ) { + $input = boolval( $value ); + } elseif ( is_numeric( $value ) ) { + $input = floatval( $value ); + } else { + $input = sanitize_text_field( $value ); + } + return $input; + } + + /** + * Clean and sanitize a value recursively. + * + * @param string $key The key of the value to be cleaned. + * @param mixed $value The value to be cleaned. + * + * @return array|bool|int|string + */ + private function cf7a_clean_recursive( $json_data ) { + $input = array(); + foreach ( $json_data as $key => $value ) { + if ( is_array( $value ) || is_object( $value ) ) { + $input[ $key ] = $this->cf7a_clean_recursive( $value ); + } else { + $input[ $key ] = $this->cf7a_clean_agnostic( $value ); + } + } + return $input; + } + /** * Sanitize each setting field as needed * @@ -1014,10 +1046,29 @@ private function cf7a_input_cron_schedule( $input, $input_name, $cron_task, $sch * @return array $options sanitized */ public function cf7a_sanitize_options( $input ) { - $new_input['cf7a_enabled'] = isset( $input['cf7a_enabled'] ) ? 1 : 0; + /* get the import options */ + $new_input = $this->options; + $import_data = isset( $_POST['to-import'] ) ? $_POST['to-import'] : false; + if ( ! empty( $import_data ) ) { + $json_data = json_decode( wp_unslash( $_POST['to-import'] ) ); + $input = $this->cf7a_clean_recursive( $json_data ); + // monkey pathing arrays that needs to be imploded + $input['bad_ip_list'] = implode( ',', $input['bad_ip_list'] ); + $input['ip_whitelist'] = implode( ',', $input['ip_whitelist'] ); + $input['bad_email_strings_list'] = implode( ',', $input['bad_email_strings_list'] ); + $input['bad_user_agent_list'] = implode( ',', $input['bad_user_agent_list'] ); + $input['dnsbl_list'] = implode( ',', $input['dnsbl_list'] ); + $input['honeypot_input_names'] = implode( ',', $input['honeypot_input_names'] ); + $input['bad_words_list'] = implode( ',', $input['bad_words_list'] ); + $input['languages_locales']['allowed'] = implode( ',', $input['languages_locales']['allowed'] ); + $input['languages_locales']['disallowed'] = implode( ',', $input['languages_locales']['disallowed'] ); + $input['cf7a_enabled'] = 1; + $input['cf7a_enable'] = 1; + $input['cf7a_version'] = CF7ANTISPAM_VERSION; + } + error_log( print_r( $input, true ) ); - /* get the existing options */ - $new_input = $this->options; + $new_input['cf7a_enabled'] = isset( $input['cf7a_enabled'] ) ? 1 : 0; $new_input['cf7a_enable'] = isset( $input['cf7a_enable'] ) ? $input['cf7a_enable'] : $new_input['cf7a_enable']; @@ -1036,15 +1087,17 @@ public function cf7a_sanitize_options( $input ) { * Checking if the enable_geoip_download is not set (note the name is $new_input but actually is the copy of the stored options) * and the user has chosen to enable the geoip, in this case download the database if needed */ - if ( empty( $new_input['enable_geoip_download'] ) && isset( $input['enable_geoip_download'] ) ) { + if ( empty( $import_data ) && empty( $new_input['enable_geoip_download'] ) && isset( $input['enable_geoip_download'] ) ) { $this->cf7a_enable_geo( $new_input['enable_geoip_download'] ); } $new_input['enable_geoip_download'] = isset( $input['enable_geoip_download'] ) ? 1 : 0; - $new_input['geoip_dbkey'] = isset( $input['geoip_dbkey'] ) ? sanitize_textarea_field( $input['geoip_dbkey'] ) : false; + + + $new_input['geoip_dbkey'] = isset( $input['geoip_dbkey'] ) ? sanitize_textarea_field( $input['geoip_dbkey'] ) : false; /* browser language check enabled */ - $new_input['check_language'] = isset( $input['check_language'] ) ? 1 : 0; + $new_input['check_language'] = ! empty( $input['check_language'] ) ? 1 : 0; /* geo-ip location check enabled */ $new_input['check_geo_location'] = isset( $input['check_geo_location'] ) ? 1 : 0; @@ -1057,6 +1110,7 @@ public function cf7a_sanitize_options( $input ) { ? $this->cf7a_settings_format_user_input( sanitize_textarea_field( $input['languages_locales']['disallowed'] ) ) : array(); + /* max attempts before ban */ $new_input['max_attempts'] = isset( $input['max_attempts'] ) ? intval( $input['max_attempts'] ) : 3; @@ -1126,7 +1180,7 @@ public function cf7a_sanitize_options( $input ) { /* honeyform */ $new_input['check_honeyform'] = isset( $input['check_honeyform'] ) ? 1 : 0; $new_input['honeyform_position'] = ! empty( $input['honeyform_position'] ) ? sanitize_title( $input['honeyform_position'] ) : 'wp_body_open'; - $new_input['honeyform_excluded_pages'] = ! empty( $input['honeyform_excluded_pages'] ) ? cf7a_str_array_to_uint_array( $input['honeyform_excluded_pages'] ) : ''; + $new_input['honeyform_excluded_pages'] = ! empty( $input['honeyform_excluded_pages'] ) ? cf7a_str_array_to_uint_array( $input['honeyform_excluded_pages'] ) : array(); /* identity protection */ $new_input['mailbox_protection_multiple_send'] = isset( $input['mailbox_protection_multiple_send'] ) ? 1 : 0; @@ -1526,9 +1580,8 @@ public function cf7a_honeyform_excluded_pages_callback() { } } - $admin_options = get_option( 'cf7a_options' ); - $excluded = isset( $admin_options['honeyform_excluded_pages'] ) ? $admin_options['honeyform_excluded_pages'] : array(); - $str_excluded = ''; + $excluded = isset( $this->options['honeyform_excluded_pages'] ) ? $this->options['honeyform_excluded_pages'] : array(); + $str_excluded = ''; if ( is_array( $excluded ) ) { foreach ( $excluded as $entry ) { $str_excluded .= ''; diff --git a/admin/CF7_AntiSpam_Admin_Display.php b/admin/CF7_AntiSpam_Admin_Display.php index f1e7650..f8a332e 100644 --- a/admin/CF7_AntiSpam_Admin_Display.php +++ b/admin/CF7_AntiSpam_Admin_Display.php @@ -110,7 +110,10 @@ public function cf7a_display_content() { ?> + cf7a_export_options(); } /** @@ -188,6 +191,35 @@ public static function cf7a_get_blacklisted_table() { } } + private function cf7a_export_options() { + + ?> +
+

+
+ + + + + + + + + + + +
+ + +
+
+
+ 0 && intval( $value ) == $value; + return is_int( $value ) || is_numeric( $value ) && $value > 0 && intval( $value ) == $value; } ) ); diff --git a/engine/CF7_AntiSpam_Activator.php b/engine/CF7_AntiSpam_Activator.php index 22f51bb..84e1e5d 100644 --- a/engine/CF7_AntiSpam_Activator.php +++ b/engine/CF7_AntiSpam_Activator.php @@ -39,53 +39,54 @@ class CF7_AntiSpam_Activator { */ public static function init_vars() { self::$default_cf7a_options = array( - 'cf7a_enable' => true, - 'cf7a_version' => CF7ANTISPAM_VERSION, - 'cf7a_customizations_class' => CF7ANTISPAM_HONEYPOT_CLASS, - 'cf7a_customizations_prefix' => CF7ANTISPAM_PREFIX, - 'cf7a_cipher' => 'aes-128-cbc', - 'cf7a_score_preset' => 'weak', - 'cf7a_disable_reload' => true, - 'check_bot_fingerprint' => true, - 'check_bot_fingerprint_extras' => true, - 'append_on_submit' => true, - 'check_time' => true, - 'check_time_min' => 6, - 'check_time_max' => YEAR_IN_SECONDS, - 'check_bad_ip' => true, - 'autostore_bad_ip' => true, - 'max_attempts' => 3, - 'unban_after' => 'disabled', - 'check_bad_words' => true, - 'check_bad_email_strings' => true, - 'check_bad_user_agent' => true, - 'check_dnsbl' => false, - 'check_refer' => true, - 'check_honeypot' => true, - 'check_honeyform' => false, - 'identity_protection_user' => false, - 'identity_protection_wp' => false, - 'enable_geoip_download' => false, - 'geoip_dbkey' => false, - 'check_language' => false, - 'check_geo_location' => false, - 'honeyform_position' => 'the_content', - 'enable_b8' => true, - 'b8_threshold' => 0.95, - 'enable_advanced_settings' => 0, - 'bad_words_list' => array(), - 'bad_ip_list' => array(), - 'ip_whitelist' => array(), - 'bad_email_strings_list' => array(), - 'bad_user_agent_list' => array(), - 'dnsbl_list' => array(), - 'honeypot_input_names' => array(), - 'honeyform_excluded_pages' => array(), - 'languages_locales' => array( + 'cf7a_enable' => true, + 'cf7a_version' => CF7ANTISPAM_VERSION, + 'cf7a_customizations_class' => CF7ANTISPAM_HONEYPOT_CLASS, + 'cf7a_customizations_prefix' => CF7ANTISPAM_PREFIX, + 'cf7a_cipher' => 'aes-128-cbc', + 'cf7a_score_preset' => 'weak', + 'cf7a_disable_reload' => true, + 'check_bot_fingerprint' => true, + 'check_bot_fingerprint_extras' => true, + 'append_on_submit' => true, + 'check_time' => true, + 'check_time_min' => 6, + 'check_time_max' => YEAR_IN_SECONDS, + 'check_bad_ip' => true, + 'autostore_bad_ip' => true, + 'max_attempts' => 3, + 'unban_after' => 'disabled', + 'check_bad_words' => true, + 'check_bad_email_strings' => true, + 'check_bad_user_agent' => true, + 'check_dnsbl' => false, + 'check_refer' => true, + 'check_honeypot' => true, + 'check_honeyform' => false, + 'identity_protection_user' => false, + 'identity_protection_wp' => false, + 'enable_geoip_download' => false, + 'geoip_dbkey' => false, + 'check_language' => false, + 'check_geo_location' => false, + 'honeyform_position' => 'the_content', + 'enable_b8' => true, + 'b8_threshold' => 0.95, + 'enable_advanced_settings' => 0, + 'mailbox_protection_multiple_send' => 0, + 'bad_words_list' => array(), + 'bad_ip_list' => array(), + 'ip_whitelist' => array(), + 'bad_email_strings_list' => array(), + 'bad_user_agent_list' => array(), + 'dnsbl_list' => array(), + 'honeypot_input_names' => array(), + 'honeyform_excluded_pages' => array(), + 'languages_locales' => array( 'allowed' => array(), 'disallowed' => array(), ), - 'score' => array( + 'score' => array( '_fingerprinting' => 0.1, '_time' => 0.3, '_bad_string' => 0.5, @@ -213,7 +214,19 @@ public static function update_options( $reset_options = false ) { $options = get_option( 'cf7a_options' ); - if ( false !== $options && ! $reset_options ) { + if ( false === $options || $reset_options ) { + + // Delete all options + if ( $reset_options === true ) { + delete_option( 'cf7a_options' ); + } + + /* if the plugin options are missing Init the plugin with the default option + the default settings */ + $new_options = array_merge( self::$default_cf7a_options, self::$default_cf7a_options_bootstrap ); + + add_option( 'cf7a_options', $new_options ); + + } else { /* update the plugin options but add the new options automatically */ if ( isset( $options['cf7a_version'] ) ) { @@ -226,11 +239,6 @@ public static function update_options( $reset_options = false ) { cf7a_log( 'CF7-antispam plugin options updated', 1 ); update_option( 'cf7a_options', $new_options ); - } else { - /* if the plugin options are missing Init the plugin with the default option + the default settings */ - $new_options = array_merge( self::$default_cf7a_options, self::$default_cf7a_options_bootstrap ); - - add_option( 'cf7a_options', $new_options ); } cf7a_log( $new_options, 1 ); diff --git a/src/admin-scripts.js b/src/admin-scripts.js index fb6f025..d2be9d9 100644 --- a/src/admin-scripts.js +++ b/src/admin-scripts.js @@ -5,3 +5,5 @@ import './integration/integration.scss'; import './settings/settings.js'; import './settings/settings.scss'; + +import './settings/importExport.js'; diff --git a/src/settings/importExport.js b/src/settings/importExport.js new file mode 100644 index 0000000..ba92206 --- /dev/null +++ b/src/settings/importExport.js @@ -0,0 +1,85 @@ +window.onload = function () { + // Example for download button + document + .getElementById('cf7a_download_button') + .addEventListener('click', () => downloadOptions()); + + document + .getElementById('import-export-options') + .addEventListener('submit', (e) => importExportOptions(e)); +}; + +/** + * Import and export options from/to JSON + * + * @param {SubmitEvent} e The submit event from the form + */ +function importExportOptions(e) { + e.preventDefault(); + + // eslint-disable-next-line no-alert + const confirmImport = confirm( + 'Are you sure you want to import options? This will overwrite your current settings.' + ); + if (!confirmImport) { + return; + } + /** + * Parse the JSON string and get the cf7-antispam options + */ + const optionsContent = document.getElementById('cf7a_options_area').value; + let cf7aOptions = null; + try { + cf7aOptions = JSON.parse(optionsContent); + } catch (err) { + // eslint-disable-next-line no-console + console.error(err); + // eslint-disable-next-line no-alert + alert('Invalid JSON. Please check your file and try again.'); + return; + } + /** + * Get the submit form data and append the cf7-ntispam options to the form data options + * @type {FormData} + */ + const data = new FormData(e.target); + data.append('to-import', encodeURIComponent(JSON.stringify(cf7aOptions))); + + // Make an AJAX request to save the merged options + fetch(e.target.getAttribute('action'), { + method: 'POST', + body: data, + }) + .then((response) => response) + .then((response) => { + // Handle the response + // eslint-disable-next-line no-console + console.log(response); + if (response.status === 200) { + // emulate the php non async behavior + window.location.href = response.url; + } + }) + .catch((error) => { + // Handle the error + // eslint-disable-next-line no-console + console.error(error); + }); +} + +function downloadOptions() { + const optionsContent = document.getElementById('cf7a_options_area').value; + const blob = new Blob([optionsContent], { + type: 'application/json', + }); + const url = window.URL.createObjectURL(blob); + const a = document.createElement('a'); + a.style.display = 'none'; + a.href = url; + a.download = 'cf7a-' + new Date().getTime() / 1000 + '.json'; + document.body.appendChild(a); + a.click(); + window.URL.revokeObjectURL(url); + // eslint-disable-next-line no-alert + alert('Your file has downloaded!'); +}