File: /home/mahdetej/public_html/wp-content/plugins/Melli-shild/admin/class-darkshield-settings.php
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
class DarkShield_Settings {
public function register_settings() {
register_setting( Melli_Shield_Config::SETTINGS_GROUP, Melli_Shield_Config::OPTION_SETTINGS, array(
'type' => 'array',
'sanitize_callback' => array( $this, 'sanitize_settings' ),
) );
register_setting( Melli_Shield_Config::SETTINGS_GROUP, Melli_Shield_Config::OPTION_ALLOWED_SERVICES, array(
'type' => 'string',
'sanitize_callback' => array( $this, 'sanitize_services' ),
'default' => '',
) );
// Mode
add_settings_section( 'ds_mode', __( 'Shield Mode', 'darkshield' ), function() {
echo '<p>' . esc_html__( 'Select the operating mode.', 'darkshield' ) . '</p>';
}, Melli_Shield_Config::PAGE_SETTINGS );
add_settings_field( 'ds_mode_field', __( 'Current Mode', 'darkshield' ), array( $this, 'render_mode' ), Melli_Shield_Config::PAGE_SETTINGS, 'ds_mode' );
// Blockers
add_settings_section( 'ds_blockers', __( 'Blocker Options', 'darkshield' ), function() {
echo '<p>' . esc_html__( 'Enable or disable individual blockers.', 'darkshield' ) . '</p>';
}, Melli_Shield_Config::PAGE_SETTINGS );
$blockers = array(
'block_fonts' => array( __( 'Block External Fonts', 'darkshield' ), __( 'Google Fonts, Typekit, Font Awesome', 'darkshield' ) ),
'block_cdn' => array( __( 'Block External CDNs', 'darkshield' ), __( 'cdnjs, jsDelivr, unpkg', 'darkshield' ) ),
'block_analytics' => array( __( 'Block Analytics & Tracking', 'darkshield' ), __( 'Google Analytics, GTM, Hotjar, Clarity', 'darkshield' ) ),
'block_updates' => array( __( 'Block WordPress Updates', 'darkshield' ), __( 'Core, plugin, theme update checks', 'darkshield' ) ),
'block_gravatar' => array( __( 'Block Gravatar', 'darkshield' ), __( 'Replace with local SVG avatar', 'darkshield' ) ),
'block_embeds' => array( __( 'Block External Embeds', 'darkshield' ), __( 'YouTube, Vimeo, Twitter oEmbed', 'darkshield' ) ),
'block_recaptcha' => array( __( 'Block reCAPTCHA', 'darkshield' ), __( 'reCAPTCHA, hCaptcha, Turnstile', 'darkshield' ) ),
'block_heartbeat' => array( __( 'Limit Heartbeat API', 'darkshield' ), __( 'Reduce to 120s, disable in Offline', 'darkshield' ) ),
'block_email' => array( __( 'Block Emails (Offline)', 'darkshield' ), __( 'Intercept and log instead of sending', 'darkshield' ) ),
'allow_messenger' => array( __( 'Allow Messenger APIs', 'darkshield' ), __( 'Telegram, Slack, Discord, Push', 'darkshield' ) ),
);
foreach ( $blockers as $key => $info ) {
add_settings_field(
'ds_' . $key,
$info[0],
array( $this, 'render_checkbox' ),
Melli_Shield_Config::PAGE_SETTINGS,
'ds_blockers',
array( 'key' => $key, 'desc' => $info[1] )
);
}
// Services
add_settings_section( 'ds_services', __( 'Allowed Service URLs', 'darkshield' ), function() {
echo '<p>' . esc_html__( 'Domains for SMS, Telegram, payment gateways. Allowed in ALL modes including Offline.', 'darkshield' ) . '</p>';
}, Melli_Shield_Config::PAGE_SETTINGS );
add_settings_field( 'ds_services_field', __( 'Service Domains', 'darkshield' ), array( $this, 'render_services' ), Melli_Shield_Config::PAGE_SETTINGS, 'ds_services' );
// Logging
add_settings_section( 'ds_log', __( 'Logging', 'darkshield' ), function() {
echo '<p>' . esc_html__( 'Configure request logging.', 'darkshield' ) . '</p>';
}, Melli_Shield_Config::PAGE_SETTINGS );
add_settings_field( 'ds_log_enabled', __( 'Enable Logging', 'darkshield' ), array( $this, 'render_checkbox' ), Melli_Shield_Config::PAGE_SETTINGS, 'ds_log', array( 'key' => 'log_enabled', 'desc' => __( 'Log blocked and allowed requests.', 'darkshield' ) ) );
add_settings_field( 'ds_log_retention', __( 'Retention (days)', 'darkshield' ), array( $this, 'render_number' ), Melli_Shield_Config::PAGE_SETTINGS, 'ds_log', array( 'key' => 'log_retention', 'min' => 1, 'max' => 365 ) );
}
// ========================================
// Field Renderers
// ========================================
public function render_mode() {
$mode = DarkShield_Utils::get_mode();
$modes = array(
'normal' => array( '🟢', __( 'Normal — All requests allowed', 'darkshield' ), '#00a32a' ),
'national' => array( '🟡', __( 'National — Only Iranian domains allowed', 'darkshield' ), '#dba617' ),
'offline' => array( '🔴', __( 'Offline — All external blocked', 'darkshield' ), '#d63638' ),
);
foreach ( $modes as $key => $m ) {
$style = ( $mode === $key ) ? 'font-weight:bold;color:' . $m[2] . ';' : '';
printf(
'<label style="display:block;margin-bottom:10px;padding:8px 12px;border:1px solid #ddd;border-radius:4px;%s"><input type="radio" name="darkshield_settings[mode]" value="%s" %s /> %s %s</label>',
esc_attr( $style ),
esc_attr( $key ),
checked( $mode, $key, false ),
esc_html( $m[0] ),
esc_html( $m[1] )
);
}
}
public function render_checkbox( $args ) {
$val = DarkShield_Utils::get_setting( $args['key'], 0 );
$desc = isset( $args['desc'] ) ? $args['desc'] : '';
printf(
'<label><input type="checkbox" name="%1$s[%2$s]" value="1" %3$s /> %4$s</label>',
esc_attr( Melli_Shield_Config::OPTION_SETTINGS ),
esc_attr( $args['key'] ),
checked( 1, $val, false ),
esc_html( $desc )
);
}
public function render_number( $args ) {
$val = DarkShield_Utils::get_setting( $args['key'], 30 );
$min = isset( $args['min'] ) ? $args['min'] : 1;
$max = isset( $args['max'] ) ? $args['max'] : 365;
printf(
'<input type="number" name="%1$s[%2$s]" value="%3$d" min="%4$d" max="%5$d" class="small-text msh-input" />',
esc_attr( Melli_Shield_Config::OPTION_SETTINGS ),
esc_attr( $args['key'] ),
(int) $val,
(int) $min,
(int) $max
);
}
// ========================================
// Service Domains + Quick Add
// ========================================
public function render_services() {
$services = get_option( Melli_Shield_Config::OPTION_ALLOWED_SERVICES, '' );
$opt = Melli_Shield_Config::OPTION_ALLOWED_SERVICES;
?>
<textarea name="<?php echo esc_attr( $opt ); ?>" rows="8" class="msh-input msh-services-textarea"
placeholder="api.kavenegar.com api.telegram.org api.zarinpal.com"
><?php echo esc_textarea( $services ); ?></textarea>
<p class="msh-card__hint"><?php esc_html_e( 'هر خط یک دامنه. با افزودن example.com، زیردامنهها هم مجاز میشوند.', 'melli-shield' ); ?></p>
<div class="msh-quick-section">
<p class="msh-quick-section__title"><?php esc_html_e( 'افزودن سریع', 'melli-shield' ); ?></p>
<p class="msh-quick-section__title"><?php esc_html_e( 'سرویسهای ایرانی', 'melli-shield' ); ?></p>
<div class="msh-quick-chips">
<?php
$iranian = array(
__( 'ارائهدهندگان SMS', 'melli-shield' ) => "api.kavenegar.com\nrest.payamak-panel.com\napi.sms.ir\napi.ghasedak.me\napi.melipayamak.com\napi2.ippanel.com\napi.limosms.com\napi.farazsms.com\nsms.magfa.com\napi.payamresan.com",
__( 'زرینپال', 'melli-shield' ) => "api.zarinpal.com\nwww.zarinpal.com\nsandbox.zarinpal.com",
__( 'آیدیپی', 'melli-shield' ) => "api.idpay.ir",
__( 'نکستپی', 'melli-shield' ) => "api.nextpay.org\nnextpay.org",
__( 'پی.آیآر', 'melli-shield' ) => "pay.ir\napi.pay.ir",
__( 'زیبال', 'melli-shield' ) => "gateway.zibal.ir\napi.zibal.ir",
__( 'پیپینگ', 'melli-shield' ) => "api.payping.ir",
__( 'وندار', 'melli-shield' ) => "api.vandar.io\nipg.vandar.io",
__( 'بانکهای شاپرک', 'melli-shield' ) => "sep.shaparak.ir\npec.shaparak.ir\nbpm.shaparak.ir\nsadad.shaparak.ir\nmabna.shaparak.ir\nasan.shaparak.ir\nikc.shaparak.ir\nmellat.shaparak.ir\npna.shaparak.ir",
__( 'جیبیت', 'melli-shield' ) => "api.jibit.ir\nnapi.jibit.ir",
__( 'پیانآ', 'melli-shield' ) => "pna.shaparak.ir\nrefund.pna.co.ir",
__( 'سیزپی', 'melli-shield' ) => "rt.sizpay.ir",
__( 'آقای پرداخت', 'melli-shield' ) => "panel.aqayepardakht.ir",
__( 'بیتپی', 'melli-shield' ) => "bitpay.ir\napi.bitpay.ir",
__( 'نقشه ایرانی', 'melli-shield' ) => "api.neshan.org\napi.cedarmaps.com\nmap.ir\napi.balad.ir",
__( 'CDN ایرانی', 'melli-shield' ) => "cdn.arvancloud.ir\nstatic.arvancloud.ir\narvancloud.com",
__( 'یکتانت', 'melli-shield' ) => "cdn.yektanet.com\nyektanet.com",
);
$this->render_quick_buttons( $iranian );
?>
</div>
<p class="msh-quick-section__title"><?php esc_html_e( 'پیامرسان', 'melli-shield' ); ?></p>
<div class="msh-quick-chips">
<?php
$messenger = array(
__( 'Telegram', 'darkshield' ) => 'api.telegram.org',
__( 'Slack', 'darkshield' ) => "hooks.slack.com\napi.slack.com",
__( 'Discord', 'darkshield' ) => "discord.com\ndiscordapp.com",
__( 'WhatsApp', 'darkshield' ) => "api.whatsapp.com\ngraph.facebook.com",
__( 'Push Services', 'darkshield' ) => "fcm.googleapis.com\nonesignal.com\napi.pusher.com\napi.pushover.net",
);
$this->render_quick_buttons( $messenger );
?>
</div>
<p class="msh-quick-section__title"><?php esc_html_e( 'درگاه بینالمللی', 'melli-shield' ); ?></p>
<div class="msh-quick-chips">
<?php
$intl_payment = array(
__( 'PayPal', 'darkshield' ) => "api.paypal.com\nwww.paypal.com\napi-m.paypal.com\napi-3t.paypal.com\nipnpb.paypal.com",
__( 'Stripe', 'darkshield' ) => "api.stripe.com\njs.stripe.com\nhooks.stripe.com\ncheckout.stripe.com\nfiles.stripe.com",
__( 'Square', 'darkshield' ) => "connect.squareup.com\napi.squareup.com\nweb.squarecdn.com",
__( 'Mollie', 'darkshield' ) => "api.mollie.com\nwww.mollie.com",
__( 'Razorpay', 'darkshield' ) => "api.razorpay.com\ncheckout.razorpay.com",
__( 'Paddle', 'darkshield' ) => "vendors.paddle.com\ncheckout.paddle.com\nsandbox-vendors.paddle.com",
__( 'Braintree', 'darkshield' ) => "api.braintreegateway.com\npayments.braintree-api.com\nclient-analytics.braintreegateway.com",
__( 'Authorize.net', 'darkshield' ) => "api.authorize.net\napi2.authorize.net\naccept.authorize.net",
__( '2Checkout', 'darkshield' ) => "api.2checkout.com\nwww.2checkout.com\nsecure.2checkout.com",
__( 'Klarna', 'darkshield' ) => "api.klarna.com\napi-na.klarna.com\napi-oc.klarna.com",
__( 'Adyen', 'darkshield' ) => "checkout-live.adyen.com\npal-live.adyen.com",
__( 'WooCommerce', 'darkshield' ) => "woocommerce.com\napi.woocommerce.com",
);
$this->render_quick_buttons( $intl_payment );
?>
</div>
<p class="msh-quick-section__title"><?php esc_html_e( 'ایمیل', 'melli-shield' ); ?></p>
<div class="msh-quick-chips">
<?php
$email = array(
__( 'Mailchimp', 'darkshield' ) => "api.mailchimp.com\nus1.api.mailchimp.com",
__( 'SendGrid', 'darkshield' ) => "api.sendgrid.com",
__( 'Mailgun', 'darkshield' ) => "api.mailgun.net",
__( 'Amazon SES', 'darkshield' ) => "email.us-east-1.amazonaws.com\nemail.eu-west-1.amazonaws.com",
__( 'Brevo', 'darkshield' ) => "api.sendinblue.com\napi.brevo.com",
__( 'Postmark', 'darkshield' ) => "api.postmarkapp.com",
__( 'SparkPost', 'darkshield' ) => "api.sparkpost.com",
);
$this->render_quick_buttons( $email );
?>
</div>
<p class="msh-quick-section__title"><?php esc_html_e( 'سایر APIها', 'melli-shield' ); ?></p>
<div class="msh-quick-chips">
<?php
$other = array(
__( 'Google APIs', 'darkshield' ) => "www.googleapis.com\nmaps.googleapis.com\ntranslate.googleapis.com\nfcm.googleapis.com",
__( 'Cloudflare', 'darkshield' ) => "api.cloudflare.com\nchallenges.cloudflare.com",
__( 'reCAPTCHA', 'darkshield' ) => "www.google.com\nwww.gstatic.com\nwww.recaptcha.net",
__( 'hCaptcha', 'darkshield' ) => "hcaptcha.com\njs.hcaptcha.com\napi.hcaptcha.com",
__( 'Zapier', 'darkshield' ) => "hooks.zapier.com",
__( 'GitHub API', 'darkshield' ) => "api.github.com\nraw.githubusercontent.com",
__( 'OpenAI', 'darkshield' ) => "api.openai.com",
);
$this->render_quick_buttons( $other );
?>
</div>
</div>
<div class="msh-info-box">
<strong><?php esc_html_e( 'تفاوت سرویس مجاز و لیست سفید:', 'melli-shield' ); ?></strong>
<?php esc_html_e( 'هر دو از مسدودسازی معافاند. سرویسها برای API و درگاه مناسباند؛ لیست سفید برای دامنههای عمومی در صفحه جداگانه.', 'melli-shield' ); ?>
</div>
<?php
}
/**
* Render Quick Add buttons from array.
*
* @param array $groups Label => domains pairs.
*/
private function render_quick_buttons( $groups ) {
foreach ( $groups as $label => $domains ) {
$tooltip = str_replace( "\n", ', ', $domains );
printf(
'<button type="button" class="msh-btn msh-btn--chip msh-quick-add" data-domains="%s" title="%s">+ %s</button>',
esc_attr( $domains ),
esc_attr( $tooltip ),
esc_html( $label )
);
}
}
// ========================================
// Sanitize
// ========================================
public function sanitize_settings( $input ) {
$s = array();
// Checkboxes
$checks = array(
'block_fonts', 'block_cdn', 'block_analytics', 'block_updates',
'block_gravatar', 'block_embeds', 'block_recaptcha', 'block_heartbeat',
'block_email', 'log_enabled', 'allow_messenger',
);
foreach ( $checks as $k ) {
$s[ $k ] = isset( $input[ $k ] ) ? 1 : 0;
}
// Number
$s['log_retention'] = isset( $input['log_retention'] )
? max( 1, min( 365, absint( $input['log_retention'] ) ) )
: 30;
return $s;
}
public function sanitize_services( $input ) {
if ( empty( $input ) ) {
return '';
}
$clean = array();
foreach ( explode( "\n", $input ) as $line ) {
$d = strtolower( trim( $line ) );
$d = preg_replace( '#^https?://#', '', $d );
$d = preg_replace( '#^www\.#', '', $d );
$d = preg_replace( '#/.*$#', '', $d );
$d = preg_replace( '#:\d+$#', '', $d );
$d = sanitize_text_field( $d );
if ( ! empty( $d ) && strpos( $d, '.' ) !== false ) {
$clean[] = $d;
}
}
$clean = array_unique( $clean );
sort( $clean );
return implode( "\n", $clean );
}
}