v2.1.6
This commit is contained in:
parent
6269b77f13
commit
c2ead8e434
13 changed files with 800 additions and 251 deletions
|
|
@ -72,6 +72,16 @@ class Plugin {
|
|||
*/
|
||||
private array $client_cache = array();
|
||||
|
||||
/**
|
||||
* Credential field being force-cleared during a direct option update.
|
||||
*
|
||||
* Set only for the duration of handle_clear_credential() to bypass the
|
||||
* keep-existing logic in sanitize_settings() via a priority-11 filter.
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
private ?string $clearing_field = null;
|
||||
|
||||
/**
|
||||
* Retrieves the instance.
|
||||
*
|
||||
|
|
@ -100,6 +110,10 @@ class Plugin {
|
|||
\add_action( 'admin_init', array( $this, 'handle_refresh_quota_request' ) );
|
||||
\add_action( 'admin_notices', array( $this, 'display_admin_notices' ) );
|
||||
\add_action( 'network_admin_notices', array( $this, 'display_admin_notices' ) );
|
||||
\add_action( 'admin_post_robotstxt_smtp_amazonses_clear_access_key', array( $this, 'handle_clear_access_key' ) );
|
||||
\add_action( 'admin_post_robotstxt_smtp_amazonses_clear_secret_key', array( $this, 'handle_clear_secret_key' ) );
|
||||
\add_action( 'admin_notices', array( $this, 'display_clear_key_notice' ) );
|
||||
\add_action( 'network_admin_notices', array( $this, 'display_clear_key_notice' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1023,21 +1037,42 @@ class Plugin {
|
|||
* @return void
|
||||
*/
|
||||
public function render_access_key_field(): void {
|
||||
$settings = $this->get_stored_settings();
|
||||
$has_access_key = '' !== $settings[ self::OPTION_ACCESS_KEY ];
|
||||
$placeholder_label = $has_access_key ? \__( 'Leave empty to keep the stored access key.', 'robotstxt-smtp-amazonses' ) : '';
|
||||
$settings = $this->get_stored_settings();
|
||||
$has_access_key = '' !== $settings[ self::OPTION_ACCESS_KEY ];
|
||||
$placeholder = $has_access_key ? \__( 'Leave empty to keep the stored access key.', 'robotstxt-smtp-amazonses' ) : '';
|
||||
$scope = \is_network_admin() ? 'network' : 'site';
|
||||
?>
|
||||
<input
|
||||
name="<?php echo \esc_attr( $this->get_field_name( self::OPTION_ACCESS_KEY ) ); ?>"
|
||||
type="text"
|
||||
id="robotstxt_smtp_amazon_ses_access_key"
|
||||
class="regular-text"
|
||||
value=""
|
||||
autocomplete="off"
|
||||
placeholder="<?php echo \esc_attr( $placeholder_label ); ?>"
|
||||
/>
|
||||
<p class="description"><?php \esc_html_e( 'Provide the IAM access key ID with permissions to send email through Amazon SES. Leave the field empty to retain the existing value.', 'robotstxt-smtp-amazonses' ); ?></p>
|
||||
<?php
|
||||
<input
|
||||
name="<?php echo \esc_attr( $this->get_field_name( self::OPTION_ACCESS_KEY ) ); ?>"
|
||||
type="text"
|
||||
id="robotstxt_smtp_amazon_ses_access_key"
|
||||
class="regular-text"
|
||||
value=""
|
||||
autocomplete="off"
|
||||
placeholder="<?php echo \esc_attr( $placeholder ); ?>"
|
||||
/>
|
||||
<?php if ( $has_access_key ) : ?>
|
||||
<a href="
|
||||
<?php
|
||||
echo \esc_url(
|
||||
\wp_nonce_url(
|
||||
\add_query_arg(
|
||||
array(
|
||||
'action' => 'robotstxt_smtp_amazonses_clear_access_key',
|
||||
'robotstxt_smtp_scope' => $scope,
|
||||
),
|
||||
\admin_url( 'admin-post.php' )
|
||||
),
|
||||
'robotstxt_smtp_amazonses_clear_access_key'
|
||||
)
|
||||
);
|
||||
?>
|
||||
" class="button button-secondary" style="margin-left: 6px;">
|
||||
<?php \esc_html_e( 'Clear access key', 'robotstxt-smtp-amazonses' ); ?>
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
<p class="description"><?php \esc_html_e( 'Provide the IAM access key ID with permissions to send email through Amazon SES. Leave the field empty to retain the existing value.', 'robotstxt-smtp-amazonses' ); ?></p>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1046,21 +1081,42 @@ class Plugin {
|
|||
* @return void
|
||||
*/
|
||||
public function render_secret_key_field(): void {
|
||||
$settings = $this->get_stored_settings();
|
||||
$has_secret_key = '' !== $settings[ self::OPTION_SECRET_KEY ];
|
||||
$placeholder_label = $has_secret_key ? \__( 'Leave empty to keep the stored secret access key.', 'robotstxt-smtp-amazonses' ) : '';
|
||||
$settings = $this->get_stored_settings();
|
||||
$has_secret_key = '' !== $settings[ self::OPTION_SECRET_KEY ];
|
||||
$placeholder = $has_secret_key ? \__( 'Leave empty to keep the stored secret access key.', 'robotstxt-smtp-amazonses' ) : '';
|
||||
$scope = \is_network_admin() ? 'network' : 'site';
|
||||
?>
|
||||
<input
|
||||
name="<?php echo \esc_attr( $this->get_field_name( self::OPTION_SECRET_KEY ) ); ?>"
|
||||
type="password"
|
||||
id="robotstxt_smtp_amazon_ses_secret_key"
|
||||
class="regular-text"
|
||||
value=""
|
||||
autocomplete="new-password"
|
||||
placeholder="<?php echo \esc_attr( $placeholder_label ); ?>"
|
||||
/>
|
||||
<p class="description"><?php \esc_html_e( 'Enter the secret access key associated with the IAM user. Leave the field empty to retain the existing value.', 'robotstxt-smtp-amazonses' ); ?></p>
|
||||
<?php
|
||||
<input
|
||||
name="<?php echo \esc_attr( $this->get_field_name( self::OPTION_SECRET_KEY ) ); ?>"
|
||||
type="password"
|
||||
id="robotstxt_smtp_amazon_ses_secret_key"
|
||||
class="regular-text"
|
||||
value=""
|
||||
autocomplete="new-password"
|
||||
placeholder="<?php echo \esc_attr( $placeholder ); ?>"
|
||||
/>
|
||||
<?php if ( $has_secret_key ) : ?>
|
||||
<a href="
|
||||
<?php
|
||||
echo \esc_url(
|
||||
\wp_nonce_url(
|
||||
\add_query_arg(
|
||||
array(
|
||||
'action' => 'robotstxt_smtp_amazonses_clear_secret_key',
|
||||
'robotstxt_smtp_scope' => $scope,
|
||||
),
|
||||
\admin_url( 'admin-post.php' )
|
||||
),
|
||||
'robotstxt_smtp_amazonses_clear_secret_key'
|
||||
)
|
||||
);
|
||||
?>
|
||||
" class="button button-secondary" style="margin-left: 6px;">
|
||||
<?php \esc_html_e( 'Clear secret key', 'robotstxt-smtp-amazonses' ); ?>
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
<p class="description"><?php \esc_html_e( 'Enter the secret access key associated with the IAM user. Leave the field empty to retain the existing value.', 'robotstxt-smtp-amazonses' ); ?></p>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1685,4 +1741,157 @@ class Plugin {
|
|||
$result = \get_site_transient( self::get_quota_cache_key() );
|
||||
return is_array( $result ) ? $result : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the request to clear the stored Access Key ID.
|
||||
*
|
||||
* @since 2.1.6
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function handle_clear_access_key(): void {
|
||||
$this->handle_clear_credential(
|
||||
self::OPTION_ACCESS_KEY,
|
||||
'robotstxt_smtp_amazonses_clear_access_key',
|
||||
'access_key'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the request to clear the stored Secret Access Key.
|
||||
*
|
||||
* @since 2.1.6
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function handle_clear_secret_key(): void {
|
||||
$this->handle_clear_credential(
|
||||
self::OPTION_SECRET_KEY,
|
||||
'robotstxt_smtp_amazonses_clear_secret_key',
|
||||
'secret_key'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears a stored AWS credential from the settings option.
|
||||
*
|
||||
* Uses a priority-11 filter on `robotstxt_smtp_sanitized_options` to override
|
||||
* the keep-existing logic in sanitize_settings() (priority 10) during the direct
|
||||
* option update, matching the same pattern used by the parent plugin for the SMTP
|
||||
* password.
|
||||
*
|
||||
* @since 2.1.6
|
||||
*
|
||||
* @param string $field Settings key to clear (OPTION_ACCESS_KEY or OPTION_SECRET_KEY).
|
||||
* @param string $nonce_action Nonce action string for this specific clear request.
|
||||
* @param string $cleared_key Value used in the success redirect query parameter.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function handle_clear_credential( string $field, string $nonce_action, string $cleared_key ): void {
|
||||
$nonce_raw = \filter_input( INPUT_GET, '_wpnonce', FILTER_UNSAFE_RAW );
|
||||
$nonce = is_string( $nonce_raw ) ? (string) \wp_unslash( $nonce_raw ) : '';
|
||||
|
||||
if ( ! \wp_verify_nonce( $nonce, $nonce_action ) ) {
|
||||
\wp_die( \esc_html__( 'The link you followed has expired.', 'robotstxt-smtp-amazonses' ) );
|
||||
}
|
||||
|
||||
$scope_raw = \filter_input( INPUT_GET, 'robotstxt_smtp_scope', FILTER_UNSAFE_RAW );
|
||||
$is_network = ROBOTSTXT_SMTP_IS_MULTISITE
|
||||
&& is_string( $scope_raw )
|
||||
&& 'network' === \sanitize_key( \wp_unslash( $scope_raw ) )
|
||||
&& Settings_Page::is_network_mode_enabled();
|
||||
|
||||
$required_cap = $is_network ? 'manage_network_options' : 'manage_options';
|
||||
if ( ! \current_user_can( $required_cap ) ) {
|
||||
\wp_die( \esc_html__( 'You do not have sufficient permissions to access this page.', 'robotstxt-smtp-amazonses' ) );
|
||||
}
|
||||
|
||||
if ( $is_network ) {
|
||||
$settings = \get_site_option( Settings_Page::NETWORK_OPTION_NAME, array() );
|
||||
$settings = is_array( $settings ) ? $settings : array();
|
||||
$settings[ $field ] = '';
|
||||
\update_site_option( Settings_Page::NETWORK_OPTION_NAME, $settings );
|
||||
$redirect_base = \network_admin_url( 'admin.php' );
|
||||
$page_slug = 'robotstxt-smtp-network';
|
||||
} else {
|
||||
$settings = \get_option( Settings_Page::OPTION_NAME, array() );
|
||||
$settings = is_array( $settings ) ? $settings : array();
|
||||
$settings[ $field ] = '';
|
||||
// sanitize_settings() at priority 10 preserves the existing value when the
|
||||
// submitted field is empty. Hook at priority 11 to force the empty value after it.
|
||||
$this->clearing_field = $field;
|
||||
\add_filter( 'robotstxt_smtp_sanitized_options', array( $this, 'force_clear_credential' ), 11, 1 );
|
||||
\update_option( Settings_Page::OPTION_NAME, $settings );
|
||||
\remove_filter( 'robotstxt_smtp_sanitized_options', array( $this, 'force_clear_credential' ), 11 );
|
||||
$this->clearing_field = null;
|
||||
$redirect_base = \admin_url( 'admin.php' );
|
||||
$page_slug = 'robotstxt-smtp';
|
||||
}
|
||||
|
||||
\delete_site_transient( self::get_quota_cache_key() );
|
||||
|
||||
\wp_safe_redirect(
|
||||
\add_query_arg(
|
||||
array(
|
||||
'page' => $page_slug,
|
||||
'robotstxt_smtp_amazonses_cleared' => $cleared_key,
|
||||
),
|
||||
$redirect_base
|
||||
)
|
||||
);
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Forces a credential field to empty string during a direct option update.
|
||||
*
|
||||
* Runs at priority 11, after sanitize_settings() at priority 10, and overrides
|
||||
* its keep-existing logic. Only active during handle_clear_credential().
|
||||
*
|
||||
* @since 2.1.6
|
||||
*
|
||||
* @param array<string, mixed> $clean Sanitized option values.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function force_clear_credential( array $clean ): array {
|
||||
if ( null !== $this->clearing_field ) {
|
||||
$clean[ $this->clearing_field ] = '';
|
||||
}
|
||||
return $clean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays a success notice after an AWS credential has been cleared.
|
||||
*
|
||||
* @since 2.1.6
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function display_clear_key_notice(): void {
|
||||
$cleared_raw = \filter_input( INPUT_GET, 'robotstxt_smtp_amazonses_cleared', FILTER_SANITIZE_SPECIAL_CHARS );
|
||||
$cleared_raw = is_string( $cleared_raw ) ? \sanitize_key( $cleared_raw ) : '';
|
||||
if ( '' === $cleared_raw ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$screen = \get_current_screen();
|
||||
if ( null === $screen || false === strpos( $screen->id, 'robotstxt-smtp' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( 'access_key' === $cleared_raw ) {
|
||||
$message = \__( 'The Amazon SES Access Key ID has been cleared.', 'robotstxt-smtp-amazonses' );
|
||||
} elseif ( 'secret_key' === $cleared_raw ) {
|
||||
$message = \__( 'The Amazon SES Secret Access Key has been cleared.', 'robotstxt-smtp-amazonses' );
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
printf(
|
||||
'<div class="notice notice-success is-dismissible"><p>%s</p></div>',
|
||||
\esc_html( $message )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue