first commit

This commit is contained in:
Rachit Bhargava
2023-07-21 17:12:10 -04:00
parent d0fe47dde4
commit 5d0f0734d8
14003 changed files with 2829464 additions and 0 deletions

View File

@@ -0,0 +1,16 @@
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_URI} \.php$
RewriteRule .* - [F,L,NC]
</IfModule>
<IfModule !mod_rewrite.c>
<FilesMatch "\.php$">
<IfModule mod_authz_core.c>
Require all denied
</IfModule>
<IfModule !mod_authz_core.c>
Order deny,allow
Deny from all
</IfModule>
</FilesMatch>
</IfModule>

View File

@@ -0,0 +1,45 @@
<?php
if (!defined('WORDFENCE_LS_VERSION')) { exit; }
/**
* Presents a modal prompt.
*
* @var string|\WordfenceLS\Text\Model_HTML $title The title for the prompt. Required.
* @var string|\WordfenceLS\Text\Model_HTML $message The message for the prompt. Required.
* @var array $primaryButton The parameters for the primary button. The array is in the format array('id' => <element id>, 'label' => <button text>, 'link' => <href value>). Optional.
* @var array $secondaryButtons The parameters for any secondary buttons. It is an array of arrays in the format array('id' => <element id>, 'label' => <button text>, 'link' => <href value>). The ordering of entries is the right-to-left order the buttons will be displayed. Optional.
*/
$titleHTML = \WordfenceLS\Text\Model_HTML::esc_html($title);
$messageHTML = \WordfenceLS\Text\Model_HTML::esc_html($message);
$embedded = isset($embedded) ? $embedded : false;
if (!isset($secondaryButtons)) {
$secondaryButtons = array();
}
$secondaryButtons = array_reverse($secondaryButtons);
?>
<div class="wfls-modal">
<div class="wfls-modal-header">
<div class="wfls-modal-header-content">
<div class="wfls-modal-title">
<strong><?php echo $titleHTML; ?></strong>
</div>
</div>
<div class="wfls-modal-header-action">
<div class="wfls-padding-add-left-small wfls-modal-header-action-close"><a href="#" onclick="WFLS.panelClose(); return false"><i class="<?php echo (\WordfenceLS\Controller_WordfenceLS::shared()->should_use_core_font_awesome_styles() ? 'wf-fa wf-fa-times-circle' : 'wfls-fa wfls-fa-times-circle'); ?>" aria-hidden="true"></i></a></div>
</div>
</div>
<div class="wfls-modal-content">
<?php echo $messageHTML; ?>
</div>
<div class="wfls-modal-footer">
<ul class="wfls-flex-horizontal wfls-flex-align-right wfls-full-width">
<?php foreach ($secondaryButtons as $button): ?>
<li class="wfls-padding-add-left-small"><a href="<?php echo esc_url($button['link']); ?>" class="wfls-btn <?php echo isset($button['type']) ? $button['type'] : 'wfls-btn-default'; ?> wfls-btn-callout-subtle" id="<?php echo esc_attr($button['id']); ?>"><?php echo isset($button['labelHTML']) ? $button['labelHTML'] : esc_html($button['label']); ?></a></li>
<?php endforeach; ?>
<?php if (isset($primaryButton) && is_array($primaryButton)): ?>
<li class="wfls-padding-add-left-small"><a href="<?php echo esc_url($primaryButton['link']); ?>" class="wfls-btn <?php echo isset($primaryButton['type']) ? $primaryButton['type'] : 'wfls-btn-primary'; ?> wfls-btn-callout-subtle" id="<?php echo esc_attr($primaryButton['id']); ?>"><?php echo isset($primaryButton['labelHTML']) ? $primaryButton['labelHTML'] : esc_html($primaryButton['label']); ?></a></li>
<?php endif ?>
</ul>
</div>
</div>

View File

@@ -0,0 +1,89 @@
<?php
if (!defined('WORDFENCE_LS_VERSION')) { exit; }
if (!isset($defaultGracePeriod))
$defaultGracePeriod = \WordfenceLS\Controller_Settings::shared()->get_user_2fa_grace_period();
$defaultGracePeriod = max($defaultGracePeriod, 1);
$errorMessage = $gracePeriod === null ? __('Unable to Activate Grace Period', 'wordfence-2fa') : __('Unable to Reset Grace Period', 'wordfence-2fa');
?>
<div class="wfls-add-top wfls-add-bottom wfls-grace-period-container">
<div class="wfls-grace-period-input-container">
<label for="wfls-user-grace-period-override" style="display: none"><?php esc_html_e('Grace Period Override', 'wordfence-2fa') ?></label>
<input type="text" id="wfls-user-grace-period-override" maxlength="2" pattern="[0-9]+" value="<?php echo (int) $defaultGracePeriod ?>">
<label for="wfls-user-grace-period-override"><?php esc_html_e('days', 'wordfence-2fa') ?></label>
</div>
<div class="wfls-grace-period-button-container">
<button class="wfls-btn wfls-btn-default" id="wfls-reset-grace-period">
<?php echo $gracePeriod === null ? esc_html__('Activate Grace Period', 'wordfence-2fa') : esc_html__('Reset Grace Period', 'wordfence-2fa') ?>
</button>
</div>
</div>
<div>
<p id="wfls-reset-grace-period-failed" style="display: none"><strong><?php echo esc_html($errorMessage) ?></strong></p>
</div>
<script type="application/javascript">
(function($) {
$(function() {
var failureMessage = $('#wfls-reset-grace-period-failed');
var overrideInput = $('#wfls-user-grace-period-override');
var button = $('#wfls-reset-grace-period');
function reset2faGracePeriod(userId, gracePeriodOverride, success, failure) {
var ajaxContext = (typeof WFLS === 'undefined' ? GWFLS : WFLS);
ajaxContext.ajax(
'wordfence_ls_reset_2fa_grace_period',
{
user_id: userId,
grace_period_override: gracePeriodOverride
},
success,
failure
);
}
function handleError() {
if (typeof WFLS === 'object') {
WFLS.panelModal(
(WFLS.screenSize(500) ? '300px' : '400px'),
<?php echo json_encode($errorMessage) ?>,
<?php echo json_encode($gracePeriod === null ? __('An unexpected error occurred while attempting to activate the grace period.', 'wordfence-2fa') : __('An unexpected error occurred while attempting to reset the grace period.', 'wordfence-2fa')) ?>
);
}
else {
failureMessage.show();
}
button.prop('disabled', false);
overrideInput.prop('disabled', false);
}
button.on('click', function(e) {
e.preventDefault();
e.stopPropagation();
button.prop('disabled', true);
overrideInput.prop('disabled', true);
failureMessage.hide();
reset2faGracePeriod(
<?php echo json_encode($user->ID, true) ?>,
overrideInput.val(),
function(data) {
if ('error' in data) {
handleError();
return;
}
if (typeof WFLS === 'undefined')
window.location.href = '#wfls-user-settings';
window.location.reload();
},
handleError
);
});
overrideInput.on('input', function(e) {
var value = $(this).val();
value = value.replace(/[^0-9]/g, '');
value = parseInt(value);
if (isNaN(value) || value === 0)
value = '';
button.prop('disabled', value < 1);
$(this).val(value);
}).trigger('input');
});
})(jQuery);
</script>

View File

@@ -0,0 +1,67 @@
<?php
if (!defined('WORDFENCE_LS_VERSION')) { exit; }
$errorMessage = __('Unable to Revoke Grace Period', 'wordfence-2fa');
?>
<div class="wfls-add-top wfls-add-bottom wfls-grace-period-container">
<div class="wfls-grace-period-button-container">
<button class="wfls-btn wfls-btn-default" id="wfls-revoke-grace-period">
<?php esc_html_e('Revoke Grace Period', 'wordfence-2fa') ?>
</button>
</div>
</div>
<div>
<p id="wfls-revoke-grace-period-failed" style="display: none"><strong><?php echo esc_html($errorMessage) ?></strong></p>
</div>
<script type="application/javascript">
(function($) {
$(function() {
var failureMessage = $('#wfls-revoke-grace-period-failed');
var button = $('#wfls-revoke-grace-period');
function revoke2faGracePeriod(userId, success, failure) {
var ajaxContext = (typeof WFLS === 'undefined' ? GWFLS : WFLS);
ajaxContext.ajax(
'wordfence_ls_revoke_2fa_grace_period',
{
user_id: userId
},
success,
failure
);
}
function handleError() {
if (typeof WFLS === 'object') {
WFLS.panelModal(
(WFLS.screenSize(500) ? '300px' : '400px'),
<?php echo json_encode($errorMessage) ?>,
<?php echo json_encode(__('An unexpected error occurred while attempting to revoke the grace period.', 'wordfence-2fa')) ?>
);
}
else {
failureMessage.show();
}
button.prop('disabled', false);
}
button.on('click', function(e) {
e.preventDefault();
e.stopPropagation();
button.prop('disabled', true);
failureMessage.hide();
revoke2faGracePeriod(
<?php echo json_encode($user->ID, true) ?>,
function(data) {
if ('error' in data) {
handleError();
return;
}
if (typeof WFLS === 'undefined')
window.location.href = '#wfls-user-settings';
window.location.reload();
},
handleError
);
});
});
})(jQuery);
</script>

View File

@@ -0,0 +1,22 @@
<?php
if (!defined('WORDFENCE_LS_VERSION')) { exit; }
/**
* @var string $ip The requesting IP. Required.
* @var string $siteName The site name. Required.
* @var string $siteURL The site URL. Required.
* @var string $verificationURL The verification URL. Required.
* @var bool $canEnable2FA Whether or not the user this is being sent to can enable 2FA. Optional
*/
?>
<strong><?php echo wp_kses(sprintf(__('Please verify a login attempt for your account on <a href="%s"><strong>%s</strong></a>.', 'wordfence-2fa'), esc_url($siteURL), $siteName), array('a'=>array('href'=>array()), 'strong'=>array())); ?></strong>
<br><br>
<?php echo '<strong>' . esc_html__('Request Time:', 'wordfence-2fa') . '</strong> ' . esc_html(\WordfenceLS\Controller_Time::format_local_time('F j, Y h:i:s A')); ?><br>
<?php echo '<strong>' . esc_html__('IP:', 'wordfence-2fa') . '</strong> ' . esc_html($ip); ?>
<br><br>
<?php echo wp_kses(__('The request was flagged as suspicious, and we need verification that you attempted to log in to allow it to proceed. This verification link <b>will be valid for 15 minutes</b> from the time it was sent. If you did not attempt this login, please change your password immediately.', 'wordfence-2fa'), array('b'=>array())); ?>
<br><br>
<?php if (isset($canEnable2FA) && $canEnable2FA): ?>
<?php esc_html_e('You may bypass this verification step permanently by enabling two-factor authentication on your account.', 'wordfence-2fa'); ?>
<br><br>
<?php endif; ?>
<?php echo wp_kses(sprintf(__('<a href="%s"><b>Verify and Log In</b></a>', 'wordfence-2fa'), esc_url($verificationURL)), array('a'=>array('href'=>array()), 'b'=>array())); ?>

View File

@@ -0,0 +1,136 @@
<?php
if (!defined('WORDFENCE_LS_VERSION')) { exit; }
/**
* @var \WordfenceLS\Model_2faInitializationData $initializationData The initialization data for setting up 2FA for a specific user. Required.
*/
$user = $initializationData->get_user();
$recovery = $initializationData->get_recovery_codes();
?>
<div class="wfls-block wfls-always-active wfls-flex-item-full-width">
<div class="wfls-block-header wfls-block-header-border-bottom">
<div class="wfls-block-header-content">
<div class="wfls-block-title">
<strong><?php esc_html_e('2. Enter Code from Authenticator App', 'wordfence-2fa'); ?></strong>
</div>
</div>
</div>
<div class="wfls-block-content wfls-padding-add-bottom">
<p><?php esc_html_e('Download Recovery Codes', 'wordfence-2fa'); ?> <em class="wfls-text-small"><?php esc_html_e('Optional', 'wordfence-2fa'); ?></em></p>
<p><?php echo esc_html(sprintf(__('Use one of these %d codes to log in if you lose access to your authenticator device. Codes are %d characters long plus optional spaces. Each one may be used only once.', 'wordfence-2fa'), count($recovery), \WordfenceLS\Model_Crypto::strlen($recovery[0]) * 2)); ?></p>
<ul class="wfls-recovery-codes">
<?php
$recoveryCodeFileContents = sprintf(__('Two-Factor Authentication Recovery Codes - %s (%s)', 'wordfence-2fa'), home_url(), $user->user_login) . "\r\n";
$recoveryCodeFileContents .= "\r\n" . sprintf(__('Each line of %d letters and numbers is a single recovery code, with optional spaces for readability. To use a recovery code, after entering your username and password, enter the code like "1234 5678 90AB CDEF" at the 2FA prompt. If your site has a custom login prompt and does not show a 2FA prompt, you can use the single-step method by entering your password and the code together in the Password field, like "mypassword1234 5678 90AB CDEF". Your recovery codes are:', 'wordfence-2fa'), \WordfenceLS\Model_Crypto::strlen($recovery[0]) * 2) . "\r\n\r\n";
foreach ($recovery as $c) {
$hex = bin2hex($c);
$blocks = str_split($hex, 4);
echo '<li>' . implode(' ', $blocks) . '</li>';
$recoveryCodeFileContents .= implode(' ', $blocks) . "\r\n";
}
?>
</ul>
<p class="wfls-center"><a href="#" class="wfls-btn wfls-btn-default" id="wfls-recovery-download" target="_blank" rel="noopener noreferrer"><i class="dashicons dashicons-download"></i> <?php esc_html_e('Download', 'wordfence-2fa'); ?></a></p>
<hr class="wfls-half">
<p><?php esc_html_e('Enter the code from your authenticator app below to verify and activate two-factor authentication for this account.', 'wordfence-2fa'); ?></p>
<p><input type="text" id="wfls-activate-field" value="" size="6" maxlength="6" placeholder="123456" autocomplete="off"></p>
</div>
<div class="wfls-block-footer">
<div class="wfls-block-footer-content">
<div class="wfls-block-title" id="wfls-activation-help-link-container">
<a href="<?php echo \WordfenceLS\Controller_Support::esc_supportURL(\WordfenceLS\Controller_Support::ITEM_MODULE_LOGIN_SECURITY_2FA); ?>" target="_blank" rel="noopener noreferrer"><?php esc_html_e('For help on setting up an app, visit our help article.', 'wordfence-2fa'); ?></a>
</div>
<div class="wfls-block-footer-action"><a href="#" id="wfls-activate" class="wfls-btn wfls-btn-default wfls-disabled"><?php esc_html_e('Activate', 'wordfence-2fa'); ?></a></div>
</div>
</div>
</div>
<script type="application/javascript">
(function($) {
$(function() {
$('#wfls-activate-field').on('keyup', function(e) {
$('#wfls-activate').toggleClass('wfls-disabled', $('#wfls-activate-field').val().length != 6);
if (e.keyCode == 13) {
$('#wfls-activate').trigger('click');
}
});
$('#wfls-recovery-download').on('click', function(e) {
e.preventDefault();
e.stopPropagation();
saveAs(new Blob(["<?php echo str_replace("\n", "\\n", str_replace("\r", "\\r", addslashes($recoveryCodeFileContents))); ?>"], {type: "text/plain;charset=" + document.characterSet}), '<?php echo \WordfenceLS\Text\Model_JavaScript::esc_js(preg_replace('~^https?://~i', '', home_url())) . '_' . \WordfenceLS\Text\Model_JavaScript::esc_js($user->user_login) . '_recoverycodes.txt'; ?>');
WFLS.savedRecoveryCodes = true;
});
$('#wfls-activate').on('click', function(e) {
e.preventDefault();
e.stopPropagation();
if (WFLS.userIsActivating) { //Likely a double-click
return;
}
WFLS.userIsActivating = true;
var payload = {
secret: '<?php echo bin2hex($initializationData->get_raw_secret()); ?>',
recovery: ['<?php echo implode('\', \'', array_map(function($c) { return bin2hex($c); }, $recovery)); ?>'],
code: $('#wfls-activate-field').val(),
user: <?php echo $user->ID; ?>,
};
WFLS.ajax(
'wordfence_ls_activate',
payload,
function(response) {
if (response.error) {
WFLS.panelModal((WFLS.screenSize(500) ? '300px' : '400px'), '<?php echo \WordfenceLS\Text\Model_JavaScript::esc_js(__('Error Activating 2FA', 'wordfence-2fa')); ?>', response.error);
}
else {
$('#wfls-activation-controls').crossfade($('#wfls-deactivation-controls'));
$('#wfls-recovery-code-count').text(response.text);
$('#wfls-activate-field').val('');
$('.wfls-notice[data-notice-type="wfls-will-be-required"]').find('.wfls-dismiss-link').trigger('click');
if (!WFLS.savedRecoveryCodes) {
var prompt = $('#wfls-tmpl-recovery-skipped-prompt').tmpl({});
var promptHTML = $("<div />").append(prompt).html();
WFLS.panelHTML((WFLS.screenSize(500) ? '300px' : '400px'), promptHTML, { fixed: true, overlayClose: false, closeButton: false, className: 'wfls-modal', onComplete: function() {
$('#wfls-recovery-skipped-download').on('click', function(e) {
e.preventDefault();
e.stopPropagation();
saveAs(new Blob(["<?php echo str_replace("\n", "\\n", str_replace("\r", "\\r", addslashes($recoveryCodeFileContents))); ?>"], {type: "text/plain;charset=" + document.characterSet}), '<?php echo \WordfenceLS\Text\Model_JavaScript::esc_js(preg_replace('~^https?://~i', '', home_url())) . '_' . \WordfenceLS\Text\Model_JavaScript::esc_js($user->user_login) . '_recoverycodes.txt'; ?>');
WFLS.panelClose();
});
$('#wfls-recovery-skipped-skip').on('click', function(e) {
e.preventDefault();
e.stopPropagation();
WFLS.panelClose();
});
}});
}
WFLS.savedRecoveryCodes = false;
WFLS.userIsActivating = false;
}
},
function(error) {
WFLS.panelModal((WFLS.screenSize(500) ? '300px' : '400px'), '<?php echo \WordfenceLS\Text\Model_JavaScript::esc_js(__('Error Activating 2FA', 'wordfence-2fa')); ?>', '<?php echo \WordfenceLS\Text\Model_JavaScript::esc_js(__('An error was encountered while trying to activate two-factor authentication. Please try again.', 'wordfence-2fa')); ?>');
WFLS.userIsActivating = false;
}
);
});
});
})(jQuery);
</script>
<script type="text/x-jquery-template" id="wfls-tmpl-recovery-skipped-prompt">
<?php
echo \WordfenceLS\Model_View::create('common/modal-prompt', array(
'title' => __('Download Recovery Codes', 'wordfence-2fa'),
'message' => __('Reminder: If you lose access to your authenticator device, you can use recovery codes to log in. If you have not saved a copy of your recovery codes, we recommend downloading them now.', 'wordfence-2fa'),
'primaryButton' => array('id' => 'wfls-recovery-skipped-download', 'label' => __('Download', 'wordfence-2fa'), 'link' => '#'),
'secondaryButtons' => array(array('id' => 'wfls-recovery-skipped-skip', 'label' => __('Skip', 'wordfence-2fa'), 'link' => '#')),
))->render();
?>
</script>

View File

@@ -0,0 +1,37 @@
<?php
if (!defined('WORDFENCE_LS_VERSION')) { exit; }
/**
* @var \WordfenceLS\Model_2faInitializationData $initializationData The initialization data for setting up 2FA for a specific user. Required.
*/
?>
<div class="wfls-block wfls-always-active wfls-flex-item-full-width">
<div class="wfls-block-header wfls-block-header-border-bottom">
<div class="wfls-block-header-content">
<div class="wfls-block-title">
<strong><?php esc_html_e('1. Scan Code or Enter Key', 'wordfence-2fa'); ?></strong>
</div>
</div>
</div>
<div class="wfls-block-content wfls-padding-add-bottom">
<p>Scan the code below with your authenticator app to add this account. Some authenticator apps also allow you to type in the text version instead.</p>
<div id="wfls-qr-code"></div>
<p class="wfls-center wfls-no-bottom"><input id="wfls-qr-code-text" class="wfls-center" type="text" value="<?php echo esc_attr($initializationData->get_base32_secret()); ?>" onclick="this.select();" size="32" readonly></p>
</div>
</div>
<script type="application/javascript">
(function($) {
$(function() {
var narrowPreviously = null;
function renderQrCode() {
var narrow = WFLS.screenSize(500);
if (narrow !== narrowPreviously) {
$('#wfls-qr-code').empty().qrcode({text: '<?php echo \WordfenceLS\Text\Model_JavaScript::esc_js($initializationData->get_otp_url()); ?>', width: (narrow ? 175 : 256), height: (narrow ? 175 : 256)});
$('#wfls-qr-code-text').css('font-family', narrow ? '' : 'monospace');
}
narrowPreviously = narrow;
}
$(window).on('resize', renderQrCode);
renderQrCode();
});
})(jQuery);
</script>

View File

@@ -0,0 +1,84 @@
<?php
if (!defined('WORDFENCE_LS_VERSION')) { exit; }
/**
* @var \WP_User $user The user being edited. Required.
*/
$ownAccount = false;
$ownUser = wp_get_current_user();
if ($ownUser->ID == $user->ID) {
$ownAccount = true;
}
?>
<div class="wfls-block wfls-always-active wfls-flex-item-full-width">
<div class="wfls-block-header wfls-block-header-border-bottom">
<div class="wfls-block-header-content">
<div class="wfls-block-title">
<strong><?php esc_html_e('Wordfence 2FA Active', 'wordfence-2fa'); ?></strong>
</div>
</div>
</div>
<div class="wfls-block-content wfls-padding-add-bottom">
<p><?php if ($ownAccount) { esc_html_e('Wordfence two-factor authentication is currently active on your account. You may deactivate it by clicking the button below.', 'wordfence-2fa'); } else { echo wp_kses(sprintf(__('Wordfence two-factor authentication is currently active on the account <strong>%s</strong>. You may deactivate it by clicking the button below.', 'wordfence-2fa'), esc_html($user->user_login)), array('strong'=>array())); } ?></p>
<p class="wfls-center wfls-add-top"><a href="#" class="wfls-btn wfls-btn-default" id="wfls-deactivate" target="_blank" rel="noopener noreferrer"><?php esc_html_e('Deactivate', 'wordfence-2fa'); ?></a></p>
</div>
</div>
<script type="text/x-jquery-template" id="wfls-tmpl-deactivate-prompt">
<?php
echo \WordfenceLS\Model_View::create('common/modal-prompt', array(
'title' => __('Deactivate 2FA', 'wordfence-2fa'),
'message' => __('Are you sure you want to deactivate two-factor authentication?', 'wordfence-2fa'),
'primaryButton' => array('id' => 'wfls-deactivate-prompt-cancel', 'label' => __('Cancel', 'wordfence-2fa'), 'link' => '#'),
'secondaryButtons' => array(array('id' => 'wfls-deactivate-prompt-confirm', 'label' => __('Deactivate', 'wordfence-2fa'), 'link' => '#')),
))->render();
?>
</script>
<script type="application/javascript">
(function($) {
$(function() {
$('#wfls-deactivate').on('click', function(e) {
e.preventDefault();
e.stopPropagation();
var prompt = $('#wfls-tmpl-deactivate-prompt').tmpl({});
var promptHTML = $("<div />").append(prompt).html();
WFLS.panelHTML((WFLS.screenSize(500) ? '300px' : '400px'), promptHTML, {overlayClose: false, closeButton: false, className: 'wfls-modal', onComplete: function() {
$('#wfls-deactivate-prompt-cancel').on('click', function(e) {
e.preventDefault();
e.stopPropagation();
WFLS.panelClose();
});
$('#wfls-deactivate-prompt-confirm').on('click', function(e) {
e.preventDefault();
e.stopPropagation();
var payload = {
user: <?php echo (int) $user->ID; ?>,
};
WFLS.ajax(
'wordfence_ls_deactivate',
payload,
function(response) {
if (response.error) {
WFLS.panelModal((WFLS.screenSize(500) ? '300px' : '400px'), '<?php echo \WordfenceLS\Text\Model_JavaScript::esc_js(__('Error Deactivating 2FA', 'wordfence-2fa')); ?>', response.error);
}
else {
$('#wfls-deactivation-controls').crossfade($('#wfls-activation-controls'));
}
WFLS.panelClose(); //The prompt
},
function(error) {
WFLS.panelModal((WFLS.screenSize(500) ? '300px' : '400px'), '<?php echo \WordfenceLS\Text\Model_JavaScript::esc_js(__('Error Deactivating 2FA', 'wordfence-2fa')); ?>', '<?php echo \WordfenceLS\Text\Model_JavaScript::esc_js(__('An error was encountered while trying to deactivate two-factor authentication. Please try again.', 'wordfence-2fa')); ?>');
WFLS.panelClose(); //The prompt
}
);
});
}});
});
});
})(jQuery);
</script>

View File

@@ -0,0 +1,56 @@
<?php
if (!defined('WORDFENCE_LS_VERSION')) { exit; }
/**
* @var \WP_User $user The user being edited. Required.
* @var bool $inGracePeriod
* @var bool $lockedOut
* @var int $requiredAt
*/
$ownAccount = false;
$ownUser = wp_get_current_user();
if ($ownUser->ID == $user->ID) {
$ownAccount = true;
}
$defaultGracePeriod = \WordfenceLS\Controller_Settings::shared()->get_user_2fa_grace_period();
$hasGracePeriod = $defaultGracePeriod > 0;
?>
<div class="wfls-block wfls-always-active wfls-flex-item-full-width">
<div class="wfls-block-header wfls-block-header-border-bottom">
<div class="wfls-block-header-content">
<div class="wfls-block-title">
<strong><?php echo $gracePeriod ? esc_html__('Grace Period', 'wordfence-2fa') : esc_html__('Locked Out', 'wordfence-2fa') ?></strong>
</div>
</div>
</div>
<div class="wfls-block-content">
<?php if ($gracePeriod): ?>
<p><?php
$requiredDateFormatted = \WordfenceLS\Controller_Time::format_local_time('F j, Y g:i A', $requiredAt);
echo $ownAccount ?
sprintf(wp_kses(__('Two-factor authentication will be required for your account beginning <strong>%s</strong>', 'wordfence-2fa'), array('strong'=>array())), $requiredDateFormatted) :
sprintf(wp_kses(__('Two-factor authentication will be required for user <strong>%s</strong> beginning <strong>%s</strong>.', 'wordfence-2fa'), array('strong'=>array())), esc_html($user->user_login), $requiredDateFormatted)
?></p>
<?php if (\WordfenceLS\Controller_Users::shared()->has_revokable_grace_period($user)): ?>
<?php echo \WordfenceLS\Model_View::create(
'common/revoke-grace-period',
array(
'user' => $user
))->render() ?>
<?php endif ?>
<?php else: ?>
<p>
<?php echo $ownAccount ?
esc_html__('Two-factor authentication is required for your account, but has not been configured.', 'wordfence-2fa') :
esc_html__('Two-factor authentication is required for this account, but has not been configured.', 'wordfence-2fa') ?>
</p>
<?php echo \WordfenceLS\Model_View::create(
'common/reset-grace-period',
array(
'user' => $user,
'gracePeriod' => $gracePeriod,
'defaultGracePeriod' => $defaultGracePeriod
))->render() ?>
<?php endif ?>
</div>
</div>

View File

@@ -0,0 +1,101 @@
<?php
if (!defined('WORDFENCE_LS_VERSION')) { exit; }
/**
* @var \WP_User $user The user being edited. Required.
* @var int $remaining The number of unused recovery codes. Required.
*/
?>
<div class="wfls-block wfls-always-active wfls-flex-item-full-width">
<div class="wfls-block-header wfls-block-header-border-bottom">
<div class="wfls-block-header-content">
<div class="wfls-block-title">
<strong><?php esc_html_e('Recovery Codes', 'wordfence-2fa'); ?></strong>
</div>
</div>
</div>
<div class="wfls-block-content wfls-padding-add-bottom">
<p id="wfls-recovery-code-count"><?php echo esc_html(sprintf($remaining == 1 ? __('%d unused recovery code remains. You may generate a new set by clicking below.', 'wordfence-2fa') : __('%d unused recovery codes remain. You may generate a new set by clicking below.', 'wordfence-2fa'), $remaining)); ?></p>
<p class="wfls-center wfls-add-top"><a href="#" class="wfls-btn wfls-btn-default" id="wfls-recovery" target="_blank" rel="noopener noreferrer"><?php esc_html_e('Generate New Codes', 'wordfence-2fa'); ?></a></p>
</div>
</div>
<script type="text/x-jquery-template" id="wfls-tmpl-recovery-prompt">
<?php
echo \WordfenceLS\Model_View::create('common/modal-prompt', array(
'title' => __('Generate New Recovery Codes', 'wordfence-2fa'),
'message' => __('Are you sure you want to generate new recovery codes? Any remaining unused codes will be disabled.', 'wordfence-2fa'),
'primaryButton' => array('id' => 'wfls-recovery-prompt-cancel', 'label' => __('Cancel', 'wordfence-2fa'), 'link' => '#'),
'secondaryButtons' => array(array('id' => 'wfls-recovery-prompt-confirm', 'label' => __('Generate', 'wordfence-2fa'), 'link' => '#')),
))->render();
?>
</script>
<script type="application/javascript">
(function($) {
$(function() {
$('#wfls-recovery').on('click', function(e) {
e.preventDefault();
e.stopPropagation();
var prompt = $('#wfls-tmpl-recovery-prompt').tmpl({});
var promptHTML = $("<div />").append(prompt).html();
WFLS.panelHTML((WFLS.screenSize(500) ? '300px' : '400px'), promptHTML, {overlayClose: false, closeButton: false, className: 'wfls-modal', onComplete: function() {
$('#wfls-recovery-prompt-cancel').on('click', function(e) {
e.preventDefault();
e.stopPropagation();
WFLS.panelClose();
});
$('#wfls-recovery-prompt-confirm').on('click', function(e) {
e.preventDefault();
e.stopPropagation();
var payload = {
user: <?php echo (int) $user->ID; ?>,
};
WFLS.ajax(
'wordfence_ls_regenerate',
payload,
function(response) {
if (response.error) {
WFLS.panelModal((WFLS.screenSize(500) ? '300px' : '400px'), '<?php echo esc_js(__('Error Generating New Codes', 'wordfence-2fa')); ?>', response.error);
}
else if (response.recovery) {
$('#wfls-recovery-code-count').text(response.text);
var message = '<p><?php echo \WordfenceLS\Text\Model_JavaScript::esc_js(sprintf(__('Use one of these %d codes to log in if you lose access to your authenticator device. Codes are %d characters long plus optional spaces. Each one may be used only once.', 'wordfence-2fa'), \WordfenceLS\Controller_Users::RECOVERY_CODE_COUNT, \WordfenceLS\Controller_Users::RECOVERY_CODE_SIZE * 2)); ?></p><ul class="wfls-recovery-codes">';
var recoveryCodeFileContents = '<?php echo \WordfenceLS\Text\Model_JavaScript::esc_js(sprintf(__('Two-Factor Authentication Recovery Codes - %s (%s)', 'wordfence-2fa'), preg_replace('~^https?://~i', '', home_url()), $user->user_login)); ?>' + "\r\n";
recoveryCodeFileContents = recoveryCodeFileContents + "\r\n" + '<?php echo \WordfenceLS\Text\Model_JavaScript::esc_js(sprintf(__('Each line of %d letters and numbers is a single recovery code, with optional spaces for readability. To use a recovery code, after entering your username and password, enter the code like "1234 5678 90AB CDEF" at the 2FA prompt. If your site has a custom login prompt and does not show a 2FA prompt, you can use the single-step method by entering your password and the code together in the Password field, like "mypassword1234 5678 90AB CDEF". Your recovery codes are:', 'wordfence-2fa'), \WordfenceLS\Controller_Users::RECOVERY_CODE_SIZE * 2)); ?>' + "\r\n\r\n";
for (var i = 0; i < response.recovery.length; i++) {
message = message + '<li>' + response.recovery[i] + '</li>';
recoveryCodeFileContents = recoveryCodeFileContents + response.recovery[i] + "\r\n";
}
message = message + "</ul>";
message = message + "<p class=\"wfls-center\"><a href=\"#\" class=\"wfls-btn wfls-btn-default\" id=\"wfls-recovery-new-download\" target=\"_blank\" rel=\"noopener noreferrer\"><i class=\"dashicons dashicons-download\"></i> <?php echo \WordfenceLS\Text\Model_JavaScript::esc_js(__('Download', 'wordfence-2fa')); ?></a></p>";
WFLS.panelModalHTML((WFLS.screenSize(500) ? '300px' : '400px'), "<?php echo \WordfenceLS\Text\Model_JavaScript::esc_js(__('New Recovery Codes', 'wordfence-2fa')); ?>", message, {onComplete: function() {
$('#wfls-recovery-new-download').on('click', function(e) {
e.preventDefault();
e.stopPropagation();
saveAs(new Blob([recoveryCodeFileContents], {type: "text/plain;charset=" + document.characterSet}), '<?php echo \WordfenceLS\Text\Model_JavaScript::esc_js(preg_replace('~^https?://~i', '', home_url()) . '_' . $user->user_login . '_recoverycodes.txt'); ?>');
});
}});
}
WFLS.panelClose(); //The prompt
},
function(error) {
WFLS.panelModal((WFLS.screenSize(500) ? '300px' : '400px'), '<?php echo \WordfenceLS\Text\Model_JavaScript::esc_js(__('Error Generating New Codes', 'wordfence-2fa')); ?>', '<?php echo \WordfenceLS\Text\Model_JavaScript::esc_js(__('An error was encountered while trying to generate new recovery codes. Please try again.', 'wordfence-2fa')); ?>');
WFLS.panelClose(); //The prompt
}
);
});
}});
});
});
})(jQuery);
</script>

View File

@@ -0,0 +1,32 @@
<?php
if (!defined('WORDFENCE_LS_VERSION')) { exit; }
/**
* Presents the fresh install plugin header for standalone installations.
*/
?>
<div id="wfls-onboarding-standalone-modal">
<div id="wfls-onboarding-standalone-modal-header">
<div id="wfls-onboarding-standalone-modal-header-title"><?php esc_html_e('Wordfence Login Security Installed', 'wordfence-2fa'); ?></div>
<div id="wfls-onboarding-standalone-modal-header-accessory"><a href="#" id="wfls-onboarding-standalone-modal-dismiss">&times;</a></div>
</div>
<div id="wfls-onboarding-standalone-modal-content">
<p><?php esc_html_e('You have just installed the Wordfence Login Security plugin. It contains a subset of the functionality found in the full Wordfence plugin: Two-factor Authentication, XML-RPC Protection and Login Page CAPTCHA.', 'wordfence-2fa'); ?></p>
<p><?php printf(__('If you\'re looking for a more comprehensive solution, the <a href="%s" target="_blank" rel="noopener noreferrer">full Wordfence plugin</a> includes all of the features in this plugin as well as a full-featured WordPress firewall, a security scanner, live traffic, and more. The standard installation includes a robust set of free features that can be upgraded via a Premium license key.', 'wordfence-2fa'), 'https://wordpress.org/plugins/wordfence/'); ?></p>
</div>
</div>
<script type="application/javascript">
(function($) {
$(function() {
$('#wfls-onboarding-standalone-modal-dismiss').on('click', function(e) {
e.preventDefault();
e.stopPropagation();
$('#wfls-onboarding-standalone-modal').slideUp(400, function() {
$('#wfls-onboarding-standalone-modal').remove();
});
WFLS.setOptions({'dismissed-fresh-install-modal': true});
});
});
})(jQuery);
</script>

View File

@@ -0,0 +1,128 @@
<?php
if (!defined('WORDFENCE_LS_VERSION')) { exit; }
$optionName = \WordfenceLS\Controller_Settings::OPTION_RECAPTCHA_THRESHOLD;
$currentValue = \WordfenceLS\Controller_Settings::shared()->get_float($optionName, 0.5);
$selectOptions = array(
array('label' => __('1.0 (definitely a human)', 'wordfence-2fa'), 'value' => 1.0),
array('label' => __('0.9', 'wordfence-2fa'), 'value' => 0.9),
array('label' => __('0.8', 'wordfence-2fa'), 'value' => 0.8),
array('label' => __('0.7', 'wordfence-2fa'), 'value' => 0.7),
array('label' => __('0.6', 'wordfence-2fa'), 'value' => 0.6),
array('label' => __('0.5 (probably a human)', 'wordfence-2fa'), 'value' => 0.5),
array('label' => __('0.4', 'wordfence-2fa'), 'value' => 0.4),
array('label' => __('0.3', 'wordfence-2fa'), 'value' => 0.3),
array('label' => __('0.2', 'wordfence-2fa'), 'value' => 0.2),
array('label' => __('0.1', 'wordfence-2fa'), 'value' => 0.1),
array('label' => __('0.0 (definitely a bot)', 'wordfence-2fa'), 'value' => 0.0),
);
?>
<ul class="wfls-flex-vertical wfls-flex-align-left">
<li>
<ul id="wfls-option-recaptcha-threshold" class="wfls-option wfls-option-select" data-select-option="<?php echo esc_attr($optionName); ?>" data-original-select-value="<?php echo esc_attr($currentValue); ?>">
<li class="wfls-option-spacer"></li>
<li class="wfls-option-content">
<ul>
<li class="wfls-option-title">
<ul class="wfls-flex-vertical wfls-flex-align-left">
<li><span id="wfls-option-recaptcha-threshold-label"><strong><?php esc_html_e('reCAPTCHA human/bot threshold score', 'wordfence-2fa'); ?></strong></span></li>
<li class="wfls-option-subtitle"><?php esc_html_e('A reCAPTCHA score equal to or higher than this value will be considered human. Anything lower will be treated as a bot and require additional verification for login and registration.', 'wordfence-2fa'); ?></li>
</ul>
</li>
<li class="wfls-option-select wfls-padding-add-top-xs-small">
<select aria-labelledby="wfls-option-recaptcha-threshold-label">
<?php foreach ($selectOptions as $o): ?>
<option class="wfls-option-select-option" value="<?php echo esc_attr($o['value']); ?>"<?php if (((int) ($o['value'] * 10)) == ((int) ($currentValue * 10))) { echo ' selected'; } ?>><?php echo esc_html($o['label']); ?></option>
<?php endforeach; ?>
</select>
</li>
</ul>
</li>
</ul>
</li>
<li>
<ul class="wfls-option">
<li class="wfls-option-spacer"></li>
<li class="wfls-recaptcha-score-history">
<div class="wfls-recaptcha-chart-container">
<canvas id="wfls-recaptcha-score-history"></canvas>
</div>
<div class="wfls-center">
<a href="#" id="wfls-reset-recaptcha-score-stats" class="wfls-text-small"><?php esc_html_e('Reset Score Statistics', 'wordfence-2fa'); ?></a>
</div>
</li>
</ul>
</li>
</ul>
<script type="application/javascript">
<?php
$stats = \WordfenceLS\Controller_Settings::shared()->get_array(\WordfenceLS\Controller_Settings::OPTION_CAPTCHA_STATS);
?>
(function($) {
$(function() {
$('#wfls-reset-recaptcha-score-stats').on('click', function(e) {
e.preventDefault();
e.stopPropagation();
WFLS.ajax('wordfence_ls_reset_recaptcha_stats', {}, function(res) {
if (res.success) {
window.location.reload(true);
}
else {
if (res.hasOwnProperty('html') && res.html) {
WFLS.panelModalHTML((WFLS.screenSize(500) ? '300px' : '400px'), 'Error Resetting reCAPTCHA Statistics', res.error);
}
else {
WFLS.panelModal((WFLS.screenSize(500) ? '300px' : '400px'), 'Error Resetting reCAPTCHA Statistics', res.error);
}
}
});
});
});
$(window).on('wfls-tab-change.recaptcha-score-history', function(e, target) {
if (target == 'settings') {
var barChartData = {
labels: ['0.0', '0.1', '0.2', '0.3', '0.4', '0.5', '0.6', '0.7', '0.8', '0.9', '1.0'],
datasets: [{
label: '<?php esc_attr_e('Requests', 'wordfence-2fa'); ?>',
backgroundColor: 'rgba(75,192,192,0.4)',
borderColor: 'rgba(75,192,192,1.0)',
borderWidth: 1,
data: <?php echo json_encode($stats['counts']) ?>
}]
};
new Chart($('#wfls-recaptcha-score-history'), {
type: 'bar',
data: barChartData,
options: {
responsive: true,
legend: {
display: false,
},
title: {
display: true,
text: '<?php esc_attr_e('reCAPTCHA Score History', 'wordfence-2fa'); ?>'
},
scales: {
yAxes: [{
display: true,
scaleLabel: {
display: true,
labelString: '<?php esc_attr_e('Count', 'wordfence-2fa'); ?>'
},
ticks: {
min: 0,
precision: 0,
stepSize: <?php echo max(10, pow(10, floor(log10(array_sum($stats['counts']) / 5)))); ?>
}
}]
}
}
});
$(window).off('wfls-tab-change.recaptcha-score-history');
}
});
})(jQuery);
</script>

View File

@@ -0,0 +1,160 @@
<?php
if (!defined('WORDFENCE_LS_VERSION')) { exit; }
$enableOptionName = \WordfenceLS\Controller_Settings::OPTION_ENABLE_AUTH_CAPTCHA;
$currentEnableValue = \WordfenceLS\Controller_Settings::shared()->get_bool($enableOptionName);
$siteKeyOptionName = \WordfenceLS\Controller_Settings::OPTION_RECAPTCHA_SITE_KEY;
$siteKeyValue = \WordfenceLS\Controller_Settings::shared()->get($siteKeyOptionName);
$secretOptionName = \WordfenceLS\Controller_Settings::OPTION_RECAPTCHA_SECRET;
$secretValue = \WordfenceLS\Controller_Settings::shared()->get($secretOptionName);
?>
<ul id="wfls-option-enable-auth-captcha" data-option="<?php echo esc_attr($enableOptionName); ?>" data-enabled-value="1" data-disabled-value="0" data-original-value="<?php echo $currentEnableValue ? '1' : '0'; ?>">
<li>
<ul class="wfls-option wfls-padding-add-bottom-small">
<li id="wfls-enable-auth-captcha" class="wfls-option-checkbox<?php echo ($currentEnableValue ? ' wfls-checked' : ''); ?>" role="checkbox" aria-checked="<?php echo ($currentEnableValue ? 'true' : 'false'); ?>" tabindex="0"><i class="wfls-ion-ios-checkmark-empty" aria-hidden="true" aria-labelledby="wfls-enable-auth-captcha-label"></i></li>
<li class="wfls-option-title">
<ul class="wfls-flex-vertical wfls-flex-align-left">
<li>
<strong id="wfls-enable-auth-captcha-label"><?php esc_html_e('Enable reCAPTCHA on the login and user registration pages', 'wordfence-2fa'); ?></strong>
</li>
<li class="wfls-option-subtitle"><?php printf(__('reCAPTCHA v3 does not make users solve puzzles or click a checkbox like previous versions. The only visible part is the reCAPTCHA logo. If a visitor\'s browser fails the CAPTCHA, Wordfence will send an email to the user\'s address with a link they can click to verify that they are a user of your site. You can read further details <a href="%s" target="_blank" rel="noopener noreferrer">in our documentation</a>.', 'wordfence-2fa'), \WordfenceLS\Controller_Support::esc_supportURL(\WordfenceLS\Controller_Support::ITEM_MODULE_LOGIN_SECURITY_CAPTCHA)); ?></li>
</ul>
</li>
</ul>
</li>
<li>
<ul class="wfls-option wfls-padding-no-top">
<li class="wfls-option-spacer"></li>
<li>
<table>
<tr class="wfls-option wfls-option-text" data-original-value="<?php echo esc_attr($siteKeyValue); ?>" data-text-option="<?php echo esc_attr($siteKeyOptionName); ?>">
<th id="wfls-enable-captcha-site-key-label" class="wfls-padding-add-bottom"><?php esc_html_e('reCAPTCHA v3 Site Key', 'wordfence-2fa'); ?></th>
<td class="wfls-option-text wfls-padding-add-bottom"><input type="text" name="recaptchaSiteKey" id="input-recaptchaSiteKey" class="wfls-form-control" value="<?php echo esc_attr($siteKeyValue); ?>"<?php if (!$currentEnableValue) { echo ' disabled'; } ?>></td>
</tr>
<tr class="wfls-option wfls-option-text" data-original-value="<?php echo esc_attr($secretValue); ?>" data-text-option="<?php echo esc_attr($secretOptionName); ?>">
<th id="wfls-enable-captcha-secret-label"><?php esc_html_e('reCAPTCHA v3 Secret', 'wordfence-2fa'); ?></th>
<td class="wfls-option-text"><input type="text" name="recaptchaSecret" id="input-recaptchaSecret" class="wfls-form-control" value="<?php echo esc_attr($secretValue); ?>"<?php if (!$currentEnableValue) { echo ' disabled'; } ?>></td>
</tr>
</table>
</li>
</ul>
<ul class="wfls-option wfls-padding-no-top">
<li class="wfls-option-spacer"></li>
<li class="wfls-option-title">
<ul class="wfls-flex-vertical wfls-flex-align-left">
<li class="wfls-option-subtitle"><?php echo wp_kses(__('Note: This feature requires a free site key and secret for the <a href="https://www.google.com/recaptcha/about/" target="_blank" rel="noopener noreferrer">Google reCAPTCHA v3 Service</a>. To set up new reCAPTCHA keys, log into your Google account and go to the <a href="https://www.google.com/recaptcha/admin" target="_blank" rel="noopener noreferrer">reCAPTCHA admin page</a>.', 'wordfence-2fa'), array('a'=>array('href'=>array(), 'target'=>array(), 'rel'=>array()))); ?></li>
</ul>
</li>
</ul>
</li>
</ul>
<script type="application/javascript">
(function($) {
$(function() {
$('#wfls-enable-auth-captcha').on('keydown', function(e) {
if (e.keyCode == 32) {
e.preventDefault();
e.stopPropagation();
$(this).trigger('click');
}
});
$('#wfls-enable-auth-captcha').on('click', function(e) {
e.preventDefault();
e.stopPropagation();
var optionElement = $('#wfls-option-enable-auth-captcha');
if (optionElement.hasClass('wfls-disabled')) {
return;
}
var option = optionElement.data('option');
var value = false;
var isActive = $(this).hasClass('wfls-checked');
if (isActive) {
$(this).removeClass('wfls-checked').attr('aria-checked', 'false');
$('#input-recaptchaSiteKey, #input-recaptchaSecret').attr('disabled', true);
value = optionElement.data('disabledValue');
}
else {
$(this).addClass('wfls-checked').attr('aria-checked', 'true');
$('#input-recaptchaSiteKey, #input-recaptchaSecret').attr('disabled', false);
value = optionElement.data('enabledValue');
}
var originalValue = optionElement.data('originalValue');
if (originalValue == value) {
delete WFLS.pendingChanges[option];
}
else {
WFLS.pendingChanges[option] = value;
}
$(optionElement).trigger('change', [false]);
WFLS.updatePendingChanges();
});
$('#wfls-enable-auth-captcha-label').on('click', function(e) {
var links = $(this).find('a');
var buffer = 10;
for (var i = 0; i < links.length; i++) {
var t = $(links[i]).offset().top;
var l = $(links[i]).offset().left;
var b = t + $(links[i]).height();
var r = l + $(links[i]).width();
if (e.pageX > l - buffer && e.pageX < r + buffer && e.pageY > t - buffer && e.pageY < b + buffer) {
return;
}
}
$(this).closest('.wfls-option').find('.wfls-option-checkbox').trigger('click');
}).css('cursor', 'pointer');
$('#input-recaptchaSiteKey, #input-recaptchaSecret').on('change paste keyup', function() {
var e = this;
setTimeout(function() {
var optionElement = $(e).closest('.wfls-option');
var option = optionElement.data('textOption');
if (typeof option !== 'undefined') {
var value = $(e).val();
var originalValue = $(optionElement).data('originalValue');
if (originalValue == value) {
delete WFLS.pendingChanges[option];
}
else {
WFLS.pendingChanges[option] = value;
}
$(optionElement).trigger('change', [false]);
WFLS.updatePendingChanges();
}
}, 4);
});
$(window).on('wflsOptionsReset', function() {
$('#wfls-enable-auth-captcha').each(function() {
var enabledValue = $(this).data('enabledValue');
var disabledValue = $(this).data('disabledValue');
var originalValue = $(this).data('originalValue');
if (enabledValue == originalValue) {
$(this).find('#wfls-enable-auth-captcha.wfls-option-checkbox').addClass('wfls-checked').attr('aria-checked', 'true');
}
else {
$(this).find('#wfls-enable-auth-captcha.wfls-option-checkbox').removeClass('wfls-checked').attr('aria-checked', 'false');
}
$(this).trigger('change', [true]);
});
$('#input-recaptchaSiteKey, #input-recaptchaSecret').each(function() {
$(this).val($(this).data('originalValue'));
$(this).attr('disabled', !$('#wfls-enable-auth-captcha.wfls-option-checkbox').hasClass('wfls-checked'));
});
});
});
})(jQuery);
</script>

View File

@@ -0,0 +1,165 @@
<?php
if (!defined('WORDFENCE_LS_VERSION')) { exit; }
/**
* Presents the global option OPTION_IP_SOURCE with a value select menu and text area (hidden by default) for trusted proxies.
*/
$selectOptions = array(
array('value' => \WordfenceLS\Model_Request::IP_SOURCE_AUTOMATIC, 'label' => esc_html__('Use the most secure method to get visitor IP addresses. Prevents spoofing and works with most sites.', 'wordfence-2fa') . ' <strong>' . esc_html__('(Recommended)', 'wordfence-2fa') . '</strong>'),
array('value' => \WordfenceLS\Model_Request::IP_SOURCE_REMOTE_ADDR, 'label' => esc_html__('Use PHP\'s built in REMOTE_ADDR and don\'t use anything else. Very secure if this is compatible with your site.', 'wordfence-2fa')),
array('value' => \WordfenceLS\Model_Request::IP_SOURCE_X_FORWARDED_FOR, 'label' => esc_html__('Use the X-Forwarded-For HTTP header. Only use if you have a front-end proxy or spoofing may result.', 'wordfence-2fa')),
array('value' => \WordfenceLS\Model_Request::IP_SOURCE_X_REAL_IP, 'label' => esc_html__('Use the X-Real-IP HTTP header. Only use if you have a front-end proxy or spoofing may result.', 'wordfence-2fa')),
);
?>
<ul class="wfls-flex-vertical wfls-flex-full-width">
<li>
<ul id="wfls-option-ip-source" class="wfls-option wfls-option-ip-source" data-option="<?php echo esc_attr(\WordfenceLS\Controller_Settings::OPTION_IP_SOURCE); ?>" data-original-value="<?php echo esc_attr(\WordfenceLS\Controller_Settings::shared()->get(\WordfenceLS\Controller_Settings::OPTION_IP_SOURCE)); ?>" data-text-area-option="<?php echo esc_attr(\WordfenceLS\Controller_Settings::OPTION_IP_TRUSTED_PROXIES); ?>" data-original-text-area-value="<?php echo esc_attr(\WordfenceLS\Controller_Settings::shared()->get(\WordfenceLS\Controller_Settings::OPTION_IP_TRUSTED_PROXIES)); ?>">
<li class="wfls-option-content wfls-no-right">
<ul class="wfls-flex-vertical wfls-flex-align-left">
<li class="wfls-option-title"><strong><?php esc_html_e('How to get IPs', 'wordfence-2fa'); ?></strong></li>
<li>
<ul class="wfls-flex-vertical wfls-flex-align-left">
<li class="wfls-padding-add-left">
<ul class="wfls-flex-vertical wfls-flex-align-left" role="radiogroup">
<?php foreach ($selectOptions as $o): ?>
<li class="wfls-padding-add-top-small"><input type="radio" class="wfls-option-radio" name="wfls-ip-source" value="<?php echo esc_attr($o['value']); ?>" id="wfls-ip-source-<?php echo esc_attr(preg_replace('/[^a-z0-9]/i', '-', $o['value'])); ?>"<?php if ($o['value'] == \WordfenceLS\Controller_Settings::shared()->get(\WordfenceLS\Controller_Settings::OPTION_IP_SOURCE)) { echo ' checked'; } ?>><label for="wfls-ip-source-<?php echo esc_attr(preg_replace('/[^a-z0-9]/i', '-', $o['value'])); ?>">&nbsp;&nbsp;</label><?php echo $o['label']; ?></li>
<?php endforeach; ?>
</ul>
</li>
<li class="wfls-option-ip-source-details wfls-padding-add-top">
<div class="wfls-left">Detected IP(s): <span id="wfls-ip-source-preview-all"><?php echo \WordfenceLS\Model_Request::current()->detected_ip_preview(); ?></span></div>
<div class="wfls-left">Your IP with this setting: <span id="wfls-ip-source-preview-single"><?php echo esc_html(\WordfenceLS\Model_Request::current()->ip()); ?></span></div>
<div class="wfls-left"><a href="#" id="wfls-ip-source-trusted-proxies-show">+ Edit trusted proxies</a></div>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li id="wfls-ip-source-trusted-proxies">
<ul id="wfls-option-ip-source-trusted-proxies" class="wfls-option wfls-option-textarea" data-text-option="<?php echo esc_attr(\WordfenceLS\Controller_Settings::OPTION_IP_TRUSTED_PROXIES); ?>" data-original-text-value="<?php echo esc_attr(\WordfenceLS\Controller_Settings::shared()->get(\WordfenceLS\Controller_Settings::OPTION_IP_TRUSTED_PROXIES)); ?>">
<li class="wfls-option-spacer"></li>
<li class="wfls-option-content wfls-no-right">
<ul>
<li class="wfls-option-title">
<ul class="wfls-flex-vertical wfls-flex-align-left">
<li><?php esc_html_e('Trusted Proxies', 'wordfence-2fa'); ?></li>
<li class="wfls-option-subtitle"><?php esc_html_e('These IPs (or CIDR ranges) will be ignored when determining the requesting IP via the X-Forwarded-For HTTP header. Enter one IP or CIDR range per line.', 'wordfence-2fa'); ?></li>
</ul>
</li>
<li class="wfls-option-textarea">
<textarea spellcheck="false" autocapitalize="none" autocomplete="off" name="howGetIPs_trusted_proxies"><?php echo esc_html(\WordfenceLS\Controller_Settings::shared()->get(\WordfenceLS\Controller_Settings::OPTION_IP_TRUSTED_PROXIES)); ?></textarea>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<script type="application/javascript">
(function($) {
$(function() {
var updateIPPreview = function() {
WFLS.updateIPPreview({ip_source: $('input[name="wfls-ip-source"]:checked').val(), ip_source_trusted_proxies: $('#wfls-ip-source-trusted-proxies textarea').val()}, function(ret) {
if (ret && ret.ip) {
$('#wfls-ip-source-preview-all').html(ret.preview);
$('#wfls-ip-source-preview-single').html(ret.ip);
}
});
};
$('input[name="wfls-ip-source"]').on('change', function() {
var optionElement = $(this).closest('.wfls-option.wfls-option-ip-source');
var option = optionElement.data('option');
var value = $('input[name="wfls-ip-source"]:checked').val();
var originalValue = optionElement.data('originalValue');
if (originalValue == value) {
delete WFLS.pendingChanges[option];
}
else {
WFLS.pendingChanges[option] = value;
}
WFLS.updatePendingChanges();
updateIPPreview();
});
var coalescingUpdateTimer;
$('#wfls-ip-source-trusted-proxies textarea').on('change paste keyup', function() {
var e = this;
setTimeout(function() {
clearTimeout(coalescingUpdateTimer);
coalescingUpdateTimer = setTimeout(updateIPPreview, 1000);
var optionElement = $(e).closest('.wfls-option.wfls-option-textarea');
var option = optionElement.data('textOption');
var value = $(e).val();
var originalValue = optionElement.data('originalTextValue');
if (originalValue == value) {
delete WFLS.pendingChanges[option];
}
else {
WFLS.pendingChanges[option] = value;
}
WFLS.updatePendingChanges();
}, 4);
});
$(window).on('wflsOptionsReset', function() {
$('input[name="wfls-ip-source"]').each(function() {
var optionElement = $(this).closest('.wfls-option.wfls-option-ip-source');
var option = optionElement.data('option');
var originalValue = optionElement.data('originalValue');
$(this).prop('checked', originalValue == $(this).attr('value'));
});
$('#wfls-ip-source-trusted-proxies textarea').each(function() {
var optionElement = $(this).closest('.wfls-option.wfls-option-textarea');
var originalValue = optionElement.data('originalTextAreaValue');
$(this).val(originalValue);
});
updateIPPreview();
});
$('#wfls-ip-source-trusted-proxies-show').each(function() {
$(this).on('keydown', function(e) {
if (e.keyCode == 32) {
e.preventDefault();
e.stopPropagation();
$(this).trigger('click');
}
});
$(this).on('click', function(e) {
e.preventDefault();
e.stopPropagation();
var isActive = $('#wfls-ip-source-trusted-proxies').hasClass('wfls-active');
if (isActive) {
$('#wfls-ip-source-trusted-proxies').slideUp({
always: function() {
$('#wfls-ip-source-trusted-proxies').removeClass('wfls-active');
}
});
}
else {
$(this).parent().slideUp();
$('#wfls-ip-source-trusted-proxies').slideDown({
always: function() {
$('#wfls-ip-source-trusted-proxies').addClass('wfls-active');
}
});
}
});
});
});
})(jQuery);
</script>

View File

@@ -0,0 +1,37 @@
<?php
if (!defined('WORDFENCE_LS_VERSION')) { exit; }
/**
* Presents an option-styled text value.
*
* Expects $title (or $titleHTML) to be defined. $helpLink may also be defined.
*
* @var string $title The title shown for the option.
* @var string $titleHTML The raw HTML title shown for the option. This supersedes $title.
* @var string $helpLink If defined, the link to the corresponding external help page.
*/
if (!isset($titleHTML)) {
$titleHTML = esc_html($title);
}
?>
<ul class="wfls-option wfls-option-label">
<?php if (!isset($noSpacer) || !$noSpacer): ?>
<li class="wfls-option-spacer"></li>
<?php endif; ?>
<li class="wfls-option-content">
<ul>
<li class="wfls-option-title">
<?php if (isset($subtitle)): ?>
<ul class="wfls-flex-vertical wfls-flex-align-left">
<li>
<?php endif; ?>
<?php echo $titleHTML; ?><?php if (isset($helpLink)) { echo ' <a href="' . esc_attr($helpLink) . '" target="_blank" rel="noopener noreferrer" class="wfls-inline-help"><i class="' . (\WordfenceLS\Controller_WordfenceLS::shared()->should_use_core_font_awesome_styles() ? 'wf-fa wf-fa-question-circle-o' : 'wfls-fa wfls-fa-question-circle-o') . '" aria-hidden="true"></i></a>'; } ?>
<?php if (isset($subtitle)): ?>
</li>
<li class="wfls-option-subtitle"><?php echo esc_html($subtitle); ?></li>
</ul>
<?php endif; ?>
</li>
</ul>
</li>
</ul>

View File

@@ -0,0 +1,88 @@
<?php
if (!defined('WORDFENCE_LS_VERSION')) { exit; }
$maxFailures = (int) \WordfenceLS\Controller_Time::FAILURE_LIMIT;
$cronDisabled = \WordfenceLS\Controller_Settings::shared()->is_ntp_cron_disabled($failureCount);
$id = 'wfls-option-ntp';
?>
<ul id="<?php echo esc_attr($id); ?>" class="wfls-option wfls-flex-vertical wfls-flex-align-left">
<li class="wfls-option-title"><strong><?php esc_html_e('NTP', 'wordfence-2fa') ?></strong></li>
<li class="wfls-option-content">
<p><?php esc_html_e('NTP is a protocol that allows for remote time synchronization. Wordfence Login Security uses this protocol to ensure that it has the most accurate time which is necessary for TOTP-based two-factor authentication.', 'wordfence-2fa') ?></p>
<?php if (\WordfenceLS\Controller_Settings::shared()->is_ntp_disabled_via_constant()): ?>
<p><?php esc_html_e('The constant WORDFENCE_LS_DISABLE_NTP is defined which disables NTP entirely. Remove this constant or set it to a falsy value to enable NTP.', 'wordfence-2fa') ?></p>
<?php elseif ($cronDisabled): ?>
<?php if ($failureCount > 0): ?>
<p><strong><?php echo sprintf(esc_html__('NTP is currently disabled as %d subsequent attempts have failed.', 'wordfence-2fa'), $maxFailures) ?></strong></p>
<?php else: ?>
<p><?php esc_html_e('NTP was manually disabled.', 'wordfence-2fa') ?></p>
<?php endif ?>
<button id="wfls-reset-ntp-failure-count" class="wfls-btn wfls-btn-sm wfls-btn-default"><?php esc_html_e('Reset', 'wordfence-2fa') ?></button>
<?php else: ?>
<p><?php echo wp_kses(__('NTP is currently <strong>enabled</strong>.', 'wordfence-2fa'), array('strong'=>array())); ?></p>
<?php if ($failureCount > 0): ?>
<?php $remainingAttempts = $maxFailures - $failureCount; ?>
<p>
<strong><?php esc_html_e('NTP updates are currently failing.', 'wordfence-2fa') ?></strong>
<?php echo $remainingAttempts > 0 ? sprintf(esc_html__('NTP will be automatically disabled after %d more attempts.', 'wordfence-2fa'), $remainingAttempts) : esc_html__('NTP will be automatically disabled after 1 more attempt.', 'wordfence-2fa') ?>
</p>
<?php endif ?>
<button id="wfls-disable-ntp" class="wfls-btn wfls-btn-sm wfls-btn-default"><?php esc_html_e('Disable', 'wordfence-2fa') ?></button>
<?php endif ?>
</li>
</ul>
<script>
(function($) {
$(function() {
$('#wfls-reset-ntp-failure-count').on('click', function(e) {
e.preventDefault();
e.stopPropagation();
function handleError(message) {
WFLS.panelModal(
(WFLS.screenSize(500) ? '300px' : '400px'),
'<?php echo \WordfenceLS\Text\Model_JavaScript::esc_js(__('Error Resetting NTP', 'wordfence-2fa')); ?>',
typeof message === 'undefined' ? '<?php echo \WordfenceLS\Text\Model_JavaScript::esc_js(__('An error was encountered while trying to reset the NTP state. Please try again.', 'wordfence-2fa')); ?>' : message
);
}
WFLS.ajax('wordfence_ls_reset_ntp_failure_count', [],
function(response) {
if (response.error) {
handleError(response.error);
}
else {
window.location.reload();
}
},
function (error) {
handleError();
});
});
$('#wfls-disable-ntp').on('click', function(e) {
e.preventDefault();
e.stopPropagation();
function handleError(message) {
WFLS.panelModal(
(WFLS.screenSize(500) ? '300px' : '400px'),
'<?php echo \WordfenceLS\Text\Model_JavaScript::esc_js(__('Error Disabling NTP', 'wordfence-2fa')); ?>',
typeof message === 'undefined' ? '<?php echo \WordfenceLS\Text\Model_JavaScript::esc_js(__('An error was encountered while trying to disable NTP. Please try again.', 'wordfence-2fa')); ?>' : message
);
}
WFLS.ajax('wordfence_ls_disable_ntp', [],
function(response) {
if (response.error) {
handleError(response.error);
}
else {
window.location.reload();
}
},
function (error) {
handleError();
});
});
});
})(jQuery);
</script>

View File

@@ -0,0 +1,183 @@
<?php
if (!defined('WORDFENCE_LS_VERSION')) { exit; }
use WordfenceLS\Controller_Settings;
use WordfenceLS\Text\Model_JavaScript;
$states = array(
Controller_Settings::STATE_2FA_DISABLED => __('Disabled', 'wordfence-2fa'),
Controller_Settings::STATE_2FA_OPTIONAL => __('Optional', 'wordfence-2fa'),
Controller_Settings::STATE_2FA_REQUIRED => __('Required', 'wordfence-2fa')
);
$gracePeriod = Controller_Settings::shared()->get_int(Controller_Settings::OPTION_REQUIRE_2FA_USER_GRACE_PERIOD, Controller_Settings::DEFAULT_REQUIRE_2FA_USER_GRACE_PERIOD);
$woocommerceIntegrationEnabled = Controller_Settings::shared()->get_bool(\WordfenceLS\Controller_Settings::OPTION_ENABLE_WOOCOMMERCE_INTEGRATION);
$requiredRoles = array();
foreach ($options as $option) {
if ($option['state'] === Controller_Settings::STATE_2FA_REQUIRED) {
$requiredRoles[$option['role']] = $option['title'];
}
}
$customerRoleWarning = __('Requiring 2FA for customers is not recommended as some customers may experience difficulties setting up or using two-factor authentication. Instead, using the "Optional" mode for users with the customer role is recommended which will allow customers to enable 2FA, but will not require them to do so.', 'wordfence-2fa');
?>
<ul class="wfls-option wfls-option-2fa-roles">
<li class="wfls-option-title">
<label><?php esc_html_e('2FA Roles', 'wordfence-2fa') ?></label>
</li>
<li class="wfls-option-content">
<ul>
<?php foreach ($options as $option): ?>
<?php $selectId = 'wfls-2fa-role-' . $option['name']; ?>
<li>
<label for="<?php echo esc_attr($selectId) ?>"><?php echo esc_html($option['title']) ?></label>
<select id="<?php echo esc_attr($selectId) ?>" name="<?php echo esc_attr($option['name']) ?>" class="wfls-option-select">
<?php foreach ($states as $key => $label): ?>
<?php if (!$option['allow_disabling'] && $key === Controller_Settings::STATE_2FA_DISABLED) continue; ?>
<option
value="<?php echo esc_attr($key); ?>"
<?php if($option['state'] === $key): ?> selected<?php endif ?>
<?php if(!$option['editable']): ?> disabled<?php endif ?>
>
<?php echo esc_html($label) ?>
</option>
<?php endforeach ?>
</select>
</li>
<?php endforeach ?>
</ul>
<p id="wfls-customer-2fa-required-warning" class="wfls-notice" style="display: none;"><?php echo esc_html($customerRoleWarning) ?></p>
<?php if ($hasWoocommerce && !$woocommerceIntegrationEnabled): ?>
<p class="wfls-woocommerce-customer-integration-message"><small><?php esc_html_e('In order to use 2FA with the WooCommerce customer role, you must either enable the "WooCommerce integration" option or use the "wordfence_2fa_management" shortcode to provide customers with access to the 2FA management interface. The default interface is only available through WordPress admin pages which are not accessible to users in the customer role.', 'wordfence-2fa') ?></small></p>
<?php endif ?>
</li>
<li class="wfls-2fa-grace-period-container">
<label for="wfls-2fa-grace-period" class="wfls-primary-label"><?php esc_html_e('Grace Period', 'wordfence-2fa') ?></label>
<input id="wfls-2fa-grace-period" type="text" pattern="[0-9]+" value="<?php echo (int)$gracePeriod; ?>" class="wfls-option-input wfls-option-input-required" name="<?php echo esc_html(Controller_Settings::OPTION_REQUIRE_2FA_USER_GRACE_PERIOD) ?>" maxlength="2">
<label for="wfls-2fa-grace-period"><?php esc_html_e('days', 'wordfence-2fa') ?></label>
<div id="wfls-grace-period-zero-warning" style="display: none;">
<strong><?php esc_html_e('Setting the grace period to 0 will prevent users in roles where 2FA is required, including newly created users, from logging in if they have not already enabled two-factor authentication.', 'wordfence-2fa') ?></strong>
<a href="<?php echo esc_attr(\WordfenceLS\Controller_Support::esc_supportURL(\WordfenceLS\Controller_Support::ITEM_MODULE_LOGIN_SECURITY_ROLES)) ?>" target="_blank" rel="noopener noreferrer"><?php esc_html_e('Learn More', 'wordfence-2fa') ?></a>
</div>
<small><?php esc_html_e('For roles that require 2FA, users will have this many days to set up 2FA. Failure to set up 2FA during this period will result in the user losing account access. This grace period will apply to new users from the time of account creation. For existing users, this grace period will apply relative to the time at which the requirement is implemented. This grace period will not automatically apply to admins and must be manually enabled for each admin user.', 'wordfence-2fa') ?></small>
</li>
<?php if (!empty($requiredRoles)): ?>
<li class="wfls-2fa-notification-action">
<h4><?php esc_html_e('2FA Notifications', 'wordfence-2fa') ?></h4>
<p>
<small><?php esc_html_e('Send an email to users with the selected role to notify them of the grace period for enabling 2FA. Select the desired role and optionally specify the URL to be sent in the email to setup 2FA. If left blank, the URL defaults to the standard wordpress login and Wordfences Two-Factor Authentication plugin page. For example, if using WooCommerce, input the relative URL of the account page.', 'wordfence-2fa') ?></small>
<a href="<?php echo \WordfenceLS\Controller_Support::esc_supportURL(\WordfenceLS\Controller_Support::ITEM_MODULE_LOGIN_SECURITY_2FA_NOTIFICATIONS) ?>" target="_blank" rel="noopener noreferrer" class="wfls-inline-help"><i class="<?php echo \WordfenceLS\Controller_WordfenceLS::shared()->should_use_core_font_awesome_styles() ? 'wf-fa wf-fa-question-circle-o' : 'wfls-fa wfls-fa-question-circle-o'; ?>" aria-hidden="true"></i></a>
</p>
<div>
<label><?php esc_html_e('2FA Role', 'wordfence-2fa') ?></label>
<select id="wfls-grace-period-notification-role">
<?php foreach ($requiredRoles as $role => $label): ?>
<option value="<?php echo esc_attr($role) ?>"><?php echo esc_html($label) ?></option>
<?php endforeach ?>
</select>
</div>
<div>
<label><?php esc_html_e('2FA Relative URL (optional)', 'wordfence-2fa') ?></label>
<input id="wfls-grace-period-notification-url" type="text" placeholder="ex: /my-account/">
</div>
<button class="wfls-btn wfls-btn-default wfls-btn-sm" id="wfls-send-grace-period-notification"><?php esc_html_e('Notify', 'wordfence-2fa') ?></button>
</li>
<?php endif ?>
</ul>
<script>
(function($) {
function sendGracePeriodNotification(notifyAll) {
var request = {
role: $('#wfls-grace-period-notification-role').val(),
url: $('#wfls-grace-period-notification-url').val(),
};
if (typeof notifyAll !== "undefined" && notifyAll)
request.notify_all = true;
WFLS.ajax('wordfence_ls_send_grace_period_notification', request,
function(response) {
if (response.error) {
var settings = {
additional_buttons: []
};
if (response.limit_exceeded) {
settings.additional_buttons.push({
label: '<?php echo \WordfenceLS\Text\Model_JavaScript::esc_js(__('Send Anyway', 'wordfence-2fa')); ?>',
id: 'wfls-send-grace-period-notification-over-limit'
});
}
WFLS.panelModal((WFLS.screenSize(500) ? '300px' : '400px'), '<?php echo \WordfenceLS\Text\Model_JavaScript::esc_js(__('Error Sending Notification', 'wordfence-2fa')); ?>', response.error, settings);
}
else {
WFLS.panelModal((WFLS.screenSize(500) ? '300px' : '400px'), '<?php echo \WordfenceLS\Text\Model_JavaScript::esc_js(__('Notification Sent', 'wordfence-2fa')); ?>', response.confirmation);
}
if (request.notify_all) {
WFLS.panelClose();
}
},
function (error) {
WFLS.panelModal((WFLS.screenSize(500) ? '300px' : '400px'), '<?php echo \WordfenceLS\Text\Model_JavaScript::esc_js(__('Error Sending Notification', 'wordfence-2fa')); ?>', '<?php echo \WordfenceLS\Text\Model_JavaScript::esc_js(__('An error was encountered while trying to send the notification. Please try again.', 'wordfence-2fa')); ?>');
if (request.notify_all) {
WFLS.panelClose();
}
});
}
$('#wfls-send-grace-period-notification').on('click', function(e) {
e.preventDefault();
e.stopPropagation();
sendGracePeriodNotification();
});
$(document).on('click', '#wfls-send-grace-period-notification-over-limit', function() {
sendGracePeriodNotification(true);
$(this).prop("disabled", true);
});
$('#wfls-2fa-grace-period').on('input', function(e) {
var value = $(this).val();
value = value.replace(/[^0-9]/g, '');
value = parseInt(value);
if (isNaN(value))
value = '';
if (value === 0) {
$("#wfls-grace-period-zero-warning").show();
}
else {
$("#wfls-grace-period-zero-warning").hide();
}
$(this).val(value);
}).trigger('input');
var customerRoleInput = $('#wfls-2fa-role-enabled-roles\\.customer');
function isCustomerRoleRequired() {
return customerRoleInput.val() === 'required';
}
function toggleCustomerRoleWarning() {
$("#wfls-customer-2fa-required-warning").toggle(isCustomerRoleRequired());
}
toggleCustomerRoleWarning();
customerRoleInput.on('change', function(e) {
toggleCustomerRoleWarning();
if (isCustomerRoleRequired()) {
WFLS.displayModalMessage(
<?php Model_JavaScript::echo_string_literal(__('Not Recommended', 'wordfence-2fa')) ?>,
<?php Model_JavaScript::echo_string_literal($customerRoleWarning) ?>,
[
{
label: <?php Model_JavaScript::echo_string_literal(__('Make Optional', 'wordfence-2fa')) ?>,
id: 'wfls-customer-role-warning-revert',
type: 'primary'
},
{
label: <?php Model_JavaScript::echo_string_literal(__('Proceed', 'wordfence-2fa')) ?>,
id: 'wfls-generic-modal-close',
type: 'danger'
}
]
);
}
});
$('body').on('click', '#wfls-customer-role-warning-revert', function() {
customerRoleInput.val('optional').trigger('change');
$('#wfls-generic-modal-close').trigger('click');
});
})(jQuery);
</script>

View File

@@ -0,0 +1,32 @@
<?php
if (!defined('WORDFENCE_LS_VERSION')) { exit; }
/**
* Presents an option with a popup menu for detailed value selection.
*
* Expects $selectOptionName, $selectOptions, $selectValue, and $title to be defined. $helpLink may also be defined.
*
* @var string $selectOptionName The option name for the select portion.
* @var array $selectOptions An array of the possible values for $selectOptionName. The array is of the format array(array('value' => <the internal value>, 'label' => <a display label>), ...)
* @var string $selectValue The current value of $selectOptionName.
* @var string $title The title shown for the option.
* @var string $helpLink If defined, the link to the corresponding external help page.
* @var bool $premium If defined, the option will be tagged as premium only and not allow its value to change for free users.
*/
$id = 'wfls-option-' . preg_replace('/[^a-z0-9]/i', '-', $selectOptionName);
?>
<ul id="<?php echo esc_attr($id); ?>" class="wfls-option wfls-option-select<?php if (!wfConfig::p() && isset($premium) && $premium) { echo ' wfls-option-premium'; } ?>" data-select-option="<?php echo esc_attr($selectOptionName); ?>" data-original-select-value="<?php echo esc_attr($selectValue); ?>">
<li class="wfls-option-spacer"></li>
<li class="wfls-option-content">
<ul>
<li class="wfls-option-title"><span id="<?php echo esc_attr($id); ?>-label"><?php echo esc_html($title); ?></span><?php if (!wfConfig::p() && isset($premium) && $premium) { echo ' <a href="https://www.wordfence.com/gnl1optionUpgrade/wordfence-signup/" target="_blank" rel="noopener noreferrer" class="wfls-premium-link">' . esc_html__('Premium Feature', 'wordfence-2fa') . '</a>'; } ?><?php if (isset($helpLink)) { echo ' <a href="' . esc_attr($helpLink) . '" target="_blank" rel="noopener noreferrer" class="wfls-inline-help"><i class="' . (\WordfenceLS\Controller_WordfenceLS::shared()->should_use_core_font_awesome_styles() ? 'wf-fa wf-fa-question-circle-o' : 'wfls-fa wfls-fa-question-circle-o') . '" aria-hidden="true"></i></a>'; } ?></li>
<li class="wfls-option-select wfls-padding-add-top-xs-small">
<select<?php echo (!(!wfConfig::p() && isset($premium) && $premium) ? '' : ' disabled'); ?> aria-labelledby="<?php echo esc_attr($id); ?>-label">
<?php foreach ($selectOptions as $o): ?>
<option class="wfls-option-select-option" value="<?php echo esc_attr($o['value']); ?>"<?php if ($o['value'] == $selectValue) { echo ' selected'; } ?>><?php echo esc_html($o['label']); ?></option>
<?php endforeach; ?>
</select>
</li>
</ul>
</li>
</ul>

View File

@@ -0,0 +1,43 @@
<?php
if (!defined('WORDFENCE_LS_VERSION')) { exit; }
/**
* Presents a switch option.
*
* @var string $optionName The option name for the switch. Required.
* @var string $value The current value of $optionName. Required.
* @var string|\WordfenceLS\Text\Model_HTML $title The title shown for the option. Required.
* @var array $states An array of the possible states for the switch. The array matches the format array('value' => <value>, 'label' => <label>) Required.
* @var string $helpLink If defined, the link to the corresponding external help page. Optional.
* @var string $alignment If defined, controls the alignment of the switch control. Optional.
*/
$id = 'wfls-option-' . preg_replace('/[^a-z0-9]/i', '-', $optionName);
?>
<ul id="<?php echo esc_attr($id); ?>" class="wfls-option wfls-option-switch" data-option-name="<?php echo esc_attr($optionName); ?>" data-original-value="<?php echo esc_attr($value); ?>">
<?php if (!isset($noSpacer) || !$noSpacer): ?>
<li class="wfls-option-spacer"></li>
<?php endif; ?>
<li class="wfls-option-content wfls-no-right">
<ul>
<li class="wfls-option-title">
<?php if (isset($subtitle)): ?>
<ul class="wfls-flex-vertical wfls-flex-align-left">
<li>
<?php endif; ?>
<span id="<?php echo esc_attr($id); ?>-label"><?php echo \WordfenceLS\Text\Model_HTML::esc_html($title); ?></span><?php if (isset($helpLink)) { echo ' <a href="' . esc_attr($helpLink) . '" target="_blank" rel="noopener noreferrer" class="wfls-inline-help"><i class="' . (\WordfenceLS\Controller_WordfenceLS::shared()->should_use_core_font_awesome_styles() ? 'wf-fa wf-fa-question-circle-o' : 'wfls-fa wfls-fa-question-circle-o') . '" aria-hidden="true"></i></a>'; } ?>
<?php if (isset($subtitle)): ?>
</li>
<li class="wfls-option-subtitle"><?php echo \WordfenceLS\Text\Model_HTML::esc_html($subtitle); ?></li>
</ul>
<?php endif; ?>
</li>
<li class="wfls-option-switch<?php if (isset($alignment)) { echo ' ' . $alignment; } ?> wfls-padding-add-top-xs-small">
<ul class="wfls-switch" role="radiogroup" aria-labelledby="<?php echo esc_attr($id); ?>-label">
<?php foreach ($states as $s): ?>
<li<?php if ($s['value'] == $value) { echo ' class="wfls-active"'; } ?> data-option-value="<?php echo esc_attr($s['value']); ?>" role="radio" aria-checked="<?php echo ($s['value'] == $value ? 'true' : 'false'); ?>" tabindex="0"><?php echo \WordfenceLS\Text\Model_HTML::esc_html($s['label']); ?></li>
<?php endforeach; ?>
</ul>
</li>
</ul>
</li>
</ul>

View File

@@ -0,0 +1,42 @@
<?php
if (!defined('WORDFENCE_LS_VERSION')) { exit; }
/**
* Presents a text field option.
*
* Expects $textOptionName, $textValue, and $title to be defined. $placeholder and $helpLink may also be defined.
*
* @var string $textOptionName The option name for the text field.
* @var string $textValue The current value of $textOptionName.
* @var string $title The title shown for the option.
* @var string $placeholder If defined, the placeholder for the text field.
* @var string $helpLink If defined, the link to the corresponding external help page.
* @var bool $premium If defined, the option will be tagged as premium only and not allow its value to change for free users.
*/
if (!isset($placeholder)) {
$placeholder = '';
}
$id = 'wfls-option-' . preg_replace('/[^a-z0-9]/i', '-', $textOptionName);
?>
<ul id="<?php echo esc_attr($id); ?>" class="wfls-option wfls-option-text<?php if (!wfConfig::p() && isset($premium) && $premium) { echo ' wfls-option-premium'; } ?>" data-text-option="<?php echo esc_attr($textOptionName); ?>" data-original-text-value="<?php echo esc_attr($textValue); ?>">
<li class="wfls-option-spacer"></li>
<li class="wfls-option-content">
<ul>
<li class="wfls-option-title">
<?php if (isset($subtitle)): ?>
<ul class="wfls-flex-vertical wfls-flex-align-left">
<li>
<?php endif; ?>
<span id="<?php echo esc_attr($id); ?>-label"><?php echo esc_html($title); ?></span><?php if (!wfConfig::p() && isset($premium) && $premium) { echo ' <a href="https://www.wordfence.com/gnl1optionUpgrade/wordfence-signup/" target="_blank" rel="noopener noreferrer" class="wfls-premium-link">' . esc_html__('Premium Feature', 'wordfence-2fa') . '</a>'; } ?><?php if (isset($helpLink)) { echo ' <a href="' . esc_attr($helpLink) . '" target="_blank" rel="noopener noreferrer" class="wfls-inline-help"><i class="' . (\WordfenceLS\Controller_WordfenceLS::shared()->should_use_core_font_awesome_styles() ? 'wf-fa wf-fa-question-circle-o' : 'wfls-fa wfls-fa-question-circle-o') . '" aria-hidden="true"></i></a>'; } ?>
<?php if (isset($subtitle)): ?>
</li>
<li class="wfls-option-subtitle"><?php echo esc_html($subtitle); ?></li>
</ul>
<?php endif; ?>
</li>
<li class="wfls-option-text">
<input type="text" value="<?php echo esc_attr($textValue); ?>" placeholder="<?php echo esc_attr($placeholder); ?>"<?php echo (!(!wfConfig::p() && isset($premium) && $premium) ? '' : ' disabled'); ?> aria-labelledby="<?php echo esc_attr($id); ?>-label">
</li>
</ul>
</li>
</ul>

View File

@@ -0,0 +1,55 @@
<?php
if (!defined('WORDFENCE_LS_VERSION')) { exit; }
/**
* Presents a text area option.
*
* Expects $textOptionName, $textValue, and $title to be defined. $helpLink, $premium, and $noSpacer may also be defined.
*
* @var string $textOptionName The option name for the text field. Required.
* @var string $textValue The current value of $textOptionName. Required.
* @var string|\WordfenceLS\Text\Model_HTML $title The title shown for the option. Required.
* @var string|\WordfenceLS\Text\Model_HTML $subtitle The title shown for the option. Optional.
* @var string $subtitlePosition The position for the subtitle: 'value' for below the value, 'title' for below the title. Optional.
* @var string $helpLink If defined, the link to the corresponding external help page. Optional.
* @var bool $noSpacer If defined and truthy, the spacer will be omitted. Optional.
*/
if (!isset($subtitlePosition)) { //May be 'title' to appear below the title or 'value' to appear below the field
$subtitlePosition = 'title';
}
$id = 'wfls-option-' . preg_replace('/[^a-z0-9]/i', '-', $textOptionName);
?>
<ul id="<?php echo esc_attr($id); ?>" class="wfls-option wfls-option-textarea" data-text-option="<?php echo esc_attr($textOptionName); ?>" data-original-text-value="<?php echo esc_attr($textValue); ?>">
<?php if (!isset($noSpacer) || !$noSpacer): ?>
<li class="wfls-option-spacer"></li>
<?php endif; ?>
<li class="wfls-option-content wfls-no-right">
<ul>
<li class="wfls-option-title<?php if (isset($alignTitle)) { echo $alignTitle == 'top' ? ' wfls-option-title-top' : ($alignTitle == 'bottom' ? 'wfls-option-title-bottom' : ''); } ?>">
<?php if (isset($subtitleHTML) && $subtitlePosition == 'title'): ?>
<ul class="wfls-flex-vertical wfls-flex-align-left">
<li>
<?php endif; ?>
<span id="<?php echo esc_attr($id); ?>-label"><?php echo \WordfenceLS\Text\Model_HTML::esc_html($title); ?></span><?php if (isset($helpLink)) { echo ' <a href="' . esc_attr($helpLink) . '" target="_blank" rel="noopener noreferrer" class="wfls-inline-help"><i class="' . (\WordfenceLS\Controller_WordfenceLS::shared()->should_use_core_font_awesome_styles() ? 'wf-fa wf-fa-question-circle-o' : 'wfls-fa wfls-fa-question-circle-o') . '" aria-hidden="true"></i></a>'; } ?>
<?php if (isset($subtitle) && $subtitlePosition == 'title'): ?>
</li>
<li class="wfls-option-subtitle"><?php echo \WordfenceLS\Text\Model_HTML::esc_html($subtitle); ?></li>
</ul>
<?php endif; ?>
</li>
<li class="wfls-option-textarea">
<?php if (isset($subtitle) && $subtitlePosition == 'value'): ?>
<ul class="wfls-flex-vertical wfls-flex-align-left wfls-flex-full-width">
<li>
<?php endif; ?>
<textarea aria-labelledby="<?php echo esc_attr($id); ?>-label"><?php echo esc_html($textValue); ?></textarea>
<?php if (isset($subtitle) && $subtitlePosition == 'value'): ?>
</li>
<li class="wfls-option-subtitle"><?php echo \WordfenceLS\Text\Model_HTML::esc_html($subtitle); ?></li>
</ul>
<?php endif; ?>
</li>
</ul>
</li>
</ul>

View File

@@ -0,0 +1,39 @@
<?php
if (!defined('WORDFENCE_LS_VERSION')) { exit; }
/**
* Presents a boolean option with a switch toggle control.
*
* Expects $optionName, $enabledValue, $disabledValue, $value, and $title to be defined. $helpLink may also be defined.
*
* @var string $optionName The option name.
* @var string $enabledValue The value to save in $option if the toggle is enabled.
* @var string $disabledValue The value to save in $option if the toggle is disabled.
* @var string $value The current value of $optionName.
* @var string $title The title shown for the option.
* @var string $htmlTitle The unescaped title shown for the option.
* @var string $helpLink If defined, the link to the corresponding external help page.
* @var bool $premium If defined, the option will be tagged as premium only and not allow its value to change for free users.
* @var bool $disabled If defined and truthy, the option will start out disabled.
*/
if (isset($subtitle) && !isset($subtitleHTML)) {
$subtitleHTML = esc_html($subtitle);
}
$id = 'wfls-option-' . preg_replace('/[^a-z0-9]/i', '-', $optionName);
?>
<ul id="<?php echo esc_attr($id); ?>" class="wfls-option wfls-option-toggled-boolean-switch<?php if (!wfConfig::p() && isset($premium) && $premium) { echo ' wfls-option-premium'; } ?><?php if (isset($disabled) && $disabled) { echo ' wfls-disabled'; } ?>" data-option="<?php echo esc_attr($optionName); ?>" data-enabled-value="<?php echo esc_attr($enabledValue); ?>" data-disabled-value="<?php echo esc_attr($disabledValue); ?>" data-original-value="<?php echo esc_attr($value == $enabledValue ? $enabledValue : $disabledValue); ?>">
<li class="wfls-boolean-switch<?php echo ($value == $enabledValue ? ' wfls-active' : ''); ?>" role="checkbox" aria-checked="<?php echo ($value == $enabledValue ? 'true' : 'false'); ?>" tabindex="0" aria-labelledby="<?php echo esc_attr($id); ?>-label"><a href="#" class="wfls-boolean-switch-handle"></a></li>
<li class="wfls-option-title">
<?php if (isset($subtitleHTML)): ?>
<ul class="wfls-flex-vertical wfls-flex-align-left">
<li>
<?php endif; ?>
<span id="<?php echo esc_attr($id); ?>-label"><?php echo (!empty($title)) ? esc_html($title) : ''; echo (!empty($htmlTitle)) ? wp_kses($htmlTitle, 'post') : ''; ?></span><?php if (!wfConfig::p() && isset($premium) && $premium) { echo ' <a href="https://www.wordfence.com/gnl1optionUpgrade/wordfence-signup/" target="_blank" rel="noopener noreferrer" class="wfls-premium-link">' . esc_html__('Premium Feature', 'wordfence-2fa') . '</a>'; } ?><?php if (isset($helpLink)) { echo ' <a href="' . esc_attr($helpLink) . '" target="_blank" rel="noopener noreferrer" class="wfls-inline-help"><i class="' . (\WordfenceLS\Controller_WordfenceLS::shared()->should_use_core_font_awesome_styles() ? 'wf-fa wf-fa-question-circle-o' : 'wfls-fa wfls-fa-question-circle-o') . '" aria-hidden="true"></i></a>'; } ?>
<?php if (isset($subtitleHTML)): ?>
</li>
<li class="wfls-option-subtitle"><?php echo $subtitleHTML; ?></li>
</ul>
<?php endif; ?>
</li>
</ul>

View File

@@ -0,0 +1,35 @@
<?php
if (!defined('WORDFENCE_LS_VERSION')) { exit; }
/**
* Presents multiple boolean options under a single heading with a checkbox toggle control for each.
*
* @var array $options The options shown. The structure is defined below. Required.
* @var string|\WordfenceLS\Text\Model_HTML $title The overall title shown for the options. Required.
* @var string $helpLink The link to the corresponding external help page. Optional.
* @var bool $wrap Whether or not the options should be allowed to wrap. Optional, defaults to false.
*
* $options is an array of
* array(
* 'name' => string <option name>,
* 'enabledValue' => string <value saved if the toggle is enabled>,
* 'disabledValue' => string <value saved if the toggle is disabled>,
* 'value' => string <current value of the option>,
* 'title' => string|\Wordfence2FA\Text\Model_HTML <title displayed to label the checkbox>,
* 'editable' => bool Whether or not the option can be edited, defaults to true.
* )
*/
?>
<ul class="wfls-option wfls-option-toggled-multiple">
<li class="wfls-option-title"><?php echo \WordfenceLS\Text\Model_HTML::esc_html($title); ?><?php if (isset($helpLink)) { echo ' <a href="' . esc_attr($helpLink) . '" target="_blank" rel="noopener noreferrer" class="wfls-inline-help"><i class="' . (\WordfenceLS\Controller_WordfenceLS::shared()->should_use_core_font_awesome_styles() ? 'wf-fa wf-fa-question-circle-o' : 'wfls-fa wfls-fa-question-circle-o') . '" aria-hidden="true"></i></a>'; } ?></li>
<li class="wfls-option-checkboxes<?php if (isset($wrap) && $wrap) { echo ' wfls-option-checkboxes-wrap'; } ?>">
<?php
foreach ($options as $o):
$id = 'wfls-option-' . preg_replace('/[^a-z0-9]/i', '-', $o['name']);
?>
<ul id="<?php echo esc_attr($id); ?>" data-option="<?php echo esc_attr($o['name']); ?>" data-enabled-value="<?php echo esc_attr($o['enabledValue']); ?>" data-disabled-value="<?php echo esc_attr($o['disabledValue']); ?>" data-original-value="<?php echo esc_attr($o['value'] == $o['enabledValue'] ? $o['enabledValue'] : $o['disabledValue']); ?>">
<li class="wfls-option-checkbox<?php echo ($o['value'] == $o['enabledValue'] ? ' wfls-checked' : ''); ?><?php echo (isset($o['editable']) && !$o['editable'] ? ' wfls-disabled' : ''); ?>" role="checkbox" aria-checked="<?php echo ($o['value'] == $o['enabledValue'] ? 'true' : 'false'); ?>" tabindex="0" aria-labelledby="<?php echo esc_attr($id); ?>-label"><i class="wfls-ion-ios-checkmark-empty" aria-hidden="true"></i></li>
<li id="<?php echo esc_attr($id); ?>-label" class="wfls-option-title"><?php echo esc_html($o['title']); ?></li>
</ul>
<?php endforeach; ?>
</li>
</ul>

View File

@@ -0,0 +1,33 @@
<?php
if (!defined('WORDFENCE_LS_VERSION')) { exit; }
/**
* Presents a boolean option with a checkbox toggle control.
*
* Expects $optionName, $enabledValue, $disabledValue, $value, and $title to be defined. $helpLink may also be defined.
*
* @var string $optionName The option name.
* @var string $enabledValue The value to save in $option if the toggle is enabled.
* @var string $disabledValue The value to save in $option if the toggle is disabled.
* @var string $value The current value of $optionName.
* @var string $title The title shown for the option.
* @var string $htmlTitle The unescaped title shown for the option.
* @var string $helpLink If defined, the link to the corresponding external help page.
* @var bool $premium If defined, the option will be tagged as premium only and not allow its value to change for free users.
*/
$id = 'wfls-option-' . preg_replace('/[^a-z0-9]/i', '-', $optionName);
?>
<ul id="<?php echo esc_attr($id); ?>" class="wfls-option wfls-option-toggled-segmented<?php if (!wfConfig::p() && isset($premium) && $premium) { echo ' wfls-option-premium'; } ?>" data-option="<?php echo esc_attr($optionName); ?>" data-enabled-value="<?php echo esc_attr($enabledValue); ?>" data-disabled-value="<?php echo esc_attr($disabledValue); ?>" data-original-value="<?php echo esc_attr($value == $enabledValue ? $enabledValue : $disabledValue); ?>">
<li class="wfls-option-title"><?php echo (!empty($title)) ? esc_html($title) : ''; echo (!empty($htmlTitle)) ? wp_kses($htmlTitle, 'post') : ''; ?><?php if (!wfConfig::p() && isset($premium) && $premium) { echo ' <a href="https://www.wordfence.com/gnl1optionUpgrade/wordfence-signup/" target="_blank" rel="noopener noreferrer" class="wfls-premium-link">' . esc_html__('Premium Feature', 'wordfence-2fa') . '</a>'; } ?><?php if (isset($helpLink)) { echo ' <a href="' . esc_attr($helpLink) . '" target="_blank" rel="noopener noreferrer" class="wfls-inline-help"><i class="' . (\WordfenceLS\Controller_WordfenceLS::shared()->should_use_core_font_awesome_styles() ? 'wf-fa wf-fa-question-circle-o' : 'wfls-fa wfls-fa-question-circle-o') . '" aria-hidden="true"></i></a>'; } ?></li>
<li class="wfls-option-segments">
<?php
$onId = sanitize_key('wfls-segment-' . $optionName . '-on');
$offId = sanitize_key('wfls-segment-' . $optionName . '-off');
?>
<input id="<?php echo esc_attr($onId) ?>" type="radio" name="<?php echo esc_attr($optionName) ?>" value="<?php echo esc_attr($enabledValue) ?>"<?php echo ($value == $enabledValue ? ' checked' : ''); ?><?php echo (!(!wfConfig::p() && isset($premium) && $premium) ? '' : ' disabled'); ?>>
<label class="wfls-segment-first" for="<?php echo esc_attr($onId) ?>">On</label>
<input id="<?php echo esc_attr($offId) ?>" type="radio" name="<?php echo esc_attr($optionName) ?>" value="<?php echo esc_attr($disabledValue) ?>"<?php echo ($value == $disabledValue ? ' checked' : ''); ?><?php echo (!(!wfConfig::p() && isset($premium) && $premium) ? '' : ' disabled'); ?>>
<label class="wfls-segment-last" for="<?php echo esc_attr($offId) ?>">Off</label>
</li>
</ul>

View File

@@ -0,0 +1,37 @@
<?php
if (!defined('WORDFENCE_LS_VERSION')) { exit; }
/**
* Presents an option with a boolean on/off toggle checkbox and popup menu for detailed value selection.
*
* Expects $toggleOptionName, $enabledToggleValue, $disabledToggleValue, $toggleValue, $selectOptionName, $selectOptions, $selectValue, and $title to be defined. $helpLink may also be defined.
*
* @var string $toggleOptionName The option name for the toggle portion.
* @var string $enabledToggleValue The value to save in $toggleOption if the toggle is enabled.
* @var string $disabledToggleValue The value to save in $toggleOption if the toggle is disabled.
* @var string $toggleValue The current value of $toggleOptionName.
* @var string $selectOptionName The option name for the select portion.
* @var array $selectOptions An array of the possible values for $selectOptionName. The array is of the format array(array('value' => <the internal value>, 'label' => <a display label>), ...)
* @var string $selectValue The current value of $selectOptionName.
* @var string $title The title shown for the option.
* @var string $helpLink If defined, the link to the corresponding external help page.
* @var bool $premium If defined, the option will be tagged as premium only and not allow its value to change for free users.
*/
$toggleID = 'wfls-option-' . preg_replace('/[^a-z0-9]/i', '-', $toggleOptionName);
$selectID = 'wfls-option-' . preg_replace('/[^a-z0-9]/i', '-', $selectOptionName);
?>
<ul class="wfls-option wfls-option-toggled-select<?php if (!wfConfig::p() && isset($premium) && $premium) { echo ' wfls-option-premium'; } ?>" data-toggle-option="<?php echo esc_attr($toggleOptionName); ?>" data-enabled-toggle-value="<?php echo esc_attr($enabledToggleValue); ?>" data-disabled-toggle-value="<?php echo esc_attr($disabledToggleValue); ?>" data-original-toggle-value="<?php echo esc_attr($toggleValue == $enabledToggleValue ? $enabledToggleValue : $disabledToggleValue); ?>" data-select-option="<?php echo esc_attr($selectOptionName); ?>" data-original-select-value="<?php echo esc_attr($selectValue); ?>">
<li id="<?php echo esc_attr($toggleID); ?>" class="wfls-option-checkbox<?php echo ($toggleValue == $enabledToggleValue ? ' wfls-checked' : ''); ?>" role="checkbox" aria-checked="<?php echo ($toggleValue == $enabledToggleValue ? 'true' : 'false'); ?>" tabindex="0"><i class="wfls-ion-ios-checkmark-empty" aria-hidden="true"></i></li>
<li class="wfls-option-content">
<ul id="<?php echo esc_attr($selectID); ?>">
<li class="wfls-option-title"><span id="<?php echo esc_attr($selectID); ?>-label"><?php echo esc_html($title); ?></span><?php if (!wfConfig::p() && isset($premium) && $premium) { echo ' <a href="https://www.wordfence.com/gnl1optionUpgrade/wordfence-signup/" target="_blank" rel="noopener noreferrer" class="wfls-premium-link">' . esc_html__('Premium Feature', 'wordfence-2fa') . '</a>'; } ?><?php if (isset($helpLink)) { echo ' <a href="' . esc_attr($helpLink) . '" target="_blank" rel="noopener noreferrer" class="wfls-inline-help"><i class="' . (\WordfenceLS\Controller_WordfenceLS::shared()->should_use_core_font_awesome_styles() ? 'wf-fa wf-fa-question-circle-o' : 'wfls-fa wfls-fa-question-circle-o') . '" aria-hidden="true"></i></a>'; } ?></li>
<li class="wfls-option-select wfls-padding-add-top-xs-small">
<select<?php echo ($toggleValue == $enabledToggleValue && !(!wfConfig::p() && isset($premium) && $premium) ? '' : ' disabled'); ?> aria-labelledby="<?php echo esc_attr($selectID); ?>-label">
<?php foreach ($selectOptions as $o): ?>
<option class="wfls-option-select-option" value="<?php echo esc_attr($o['value']); ?>"<?php if ($o['value'] == $selectValue) { echo ' selected'; } ?>><?php echo esc_html($o['label']); ?></option>
<?php endforeach; ?>
</select>
</li>
</ul>
</li>
</ul>

View File

@@ -0,0 +1,56 @@
<?php
if (!defined('WORDFENCE_LS_VERSION')) { exit; }
/**
* Presents a boolean option with a checkbox toggle control and a sub-option toggle.
*
* Expects $optionName, $enabledValue, $disabledValue, $value, and $title to be defined for the primary option. $helpLink may also be defined.
* Expects $subOptionName, $subEnabledValue, $subDisabledValue, $subValue, and $subTitle to be defined for the sub-option. $subHelpLink may also be defined.
*
* @var string $optionName The option name.
* @var string $enabledValue The value to save in $optionName if the toggle is enabled.
* @var string $disabledValue The value to save in $optionName if the toggle is disabled.
* @var string $value The current value of $optionName.
* @var string $title The title shown for the option.
* @var string $htmlTitle The unescaped title shown for the option.
* @var string $helpLink If defined, the link to the corresponding external help page.
* @var bool $premium If defined, the option will be tagged as premium only and not allow its value to change for free users.
*
* @var string $subOptionName The sub-option name.
* @var string $subEnabledValue The value to save in $subOptionName if the toggle is enabled.
* @var string $subDisabledValue The value to save in $subOptionName if the toggle is disabled.
* @var string $subValue The current value of $subOptionName.
* @var string $subTitle The title shown for the sub-option.
* @var string $subHtmlTitle The unescaped title shown for the sub-option.
* @var string $subHelpLink If defined, the link to the corresponding external help page for the sub-option.
* @var bool $subPremium If defined, the sub-option will be tagged as premium only and not allow its value to change for free users.
*/
if (isset($title) && !isset($htmlTitle)) {
$htmlTitle = esc_html($title);
}
if (isset($subTitle) && !isset($subHtmlTitle)) {
$subHtmlTitle = esc_html($subTitle);
}
$id = 'wfls-option-' . preg_replace('/[^a-z0-9]/i', '-', $optionName);
$subID = 'wfls-option-' . preg_replace('/[^a-z0-9]/i', '-', $subOptionName);
?>
<ul class="wfls-flex-vertical wfls-flex-full-width">
<li>
<ul id="<?php echo esc_attr($id); ?>" class="wfls-option wfls-option-toggled<?php if (!wfConfig::p() && isset($premium) && $premium) { echo ' wfls-option-premium'; } ?>" data-option="<?php echo esc_attr($optionName); ?>" data-enabled-value="<?php echo esc_attr($enabledValue); ?>" data-disabled-value="<?php echo esc_attr($disabledValue); ?>" data-original-value="<?php echo esc_attr($value == $enabledValue ? $enabledValue : $disabledValue); ?>">
<li class="wfls-option-checkbox<?php echo ($value == $enabledValue ? ' wfls-checked' : ''); ?>" role="checkbox" aria-checked="<?php echo ($value == $enabledValue ? 'true' : 'false'); ?>" tabindex="0" aria-labelledby="<?php echo esc_attr($id); ?>-label"><i class="wfls-ion-ios-checkmark-empty" aria-hidden="true"></i></li>
<li class="wfls-option-title">
<span id="<?php echo esc_attr($id); ?>-label"><?php echo $htmlTitle; ?></span><?php if (!wfConfig::p() && isset($premium) && $premium) { echo ' <a href="https://www.wordfence.com/gnl1optionUpgrade/wordfence-signup/" target="_blank" rel="noopener noreferrer" class="wfls-premium-link">' . esc_html__('Premium Feature', 'wordfence-2fa') . '</a>'; } ?><?php if (isset($helpLink)) { echo ' <a href="' . esc_attr($helpLink) . '" target="_blank" rel="noopener noreferrer" class="wfls-inline-help"><i class="' . (\WordfenceLS\Controller_WordfenceLS::shared()->should_use_core_font_awesome_styles() ? 'wf-fa wf-fa-question-circle-o' : 'wfls-fa wfls-fa-question-circle-o') . '" aria-hidden="true"></i></a>'; } ?>
</li>
</ul>
</li>
<li class="wfls-option-sub">
<ul id="<?php echo esc_attr($subID); ?>" class="wfls-option wfls-option-toggled<?php if (!wfConfig::p() && isset($subPremium) && $subPremium) { echo ' wfls-option-premium'; } ?>" data-option="<?php echo esc_attr($subOptionName); ?>" data-enabled-value="<?php echo esc_attr($subEnabledValue); ?>" data-disabled-value="<?php echo esc_attr($subDisabledValue); ?>" data-original-value="<?php echo esc_attr($subValue == $subEnabledValue ? $subEnabledValue : $subDisabledValue); ?>">
<li class="wfls-option-checkbox<?php echo ($subValue == $subEnabledValue ? ' wfls-checked' : ''); ?>" role="checkbox" aria-checked="<?php echo ($subValue == $subEnabledValue ? 'true' : 'false'); ?>" tabindex="0" aria-labelledby="<?php echo esc_attr($subID); ?>-label"><i class="wfls-ion-ios-checkmark-empty" aria-hidden="true"></i></li>
<li class="wfls-option-title">
<span id="<?php echo esc_attr($subID); ?>-label"><?php echo $subHtmlTitle; ?></span><?php if (!wfConfig::p() && isset($subPremium) && $subPremium) { echo ' <a href="https://www.wordfence.com/gnl1optionUpgrade/wordfence-signup/" target="_blank" rel="noopener noreferrer" class="wfls-premium-link">' . esc_html__('Premium Feature', 'wordfence-2fa') . '</a>'; } ?><?php if (isset($subHelpLink)) { echo ' <a href="' . esc_attr($subHelpLink) . '" target="_blank" rel="noopener noreferrer" class="wfls-inline-help"><i class="' . (\WordfenceLS\Controller_WordfenceLS::shared()->should_use_core_font_awesome_styles() ? 'wf-fa wf-fa-question-circle-o' : 'wfls-fa wfls-fa-question-circle-o') . '" aria-hidden="true"></i></a>'; } ?>
</li>
</ul>
</li>
</ul>

View File

@@ -0,0 +1,30 @@
<?php
if (!defined('WORDFENCE_LS_VERSION')) { exit; }
/**
* Presents an option with a boolean on/off toggle checkbox and text area for detailed value entry.
*
* Expects $toggleOptionName, $enabledToggleValue, $disabledToggleValue, $toggleValue, $textAreaOptionName, $textAreaValue, and $title to be defined. $helpLink may also be defined.
*
* @var string $toggleOptionName The option name for the toggle portion.
* @var string $enabledToggleValue The value to save in $toggleOption if the toggle is enabled.
* @var string $disabledToggleValue The value to save in $toggleOption if the toggle is disabled.
* @var string $toggleValue The current value of $toggleOptionName.
* @var string $textAreaOptionName The option name for the text area portion.
* @var string $textAreaValue The current value of $textAreaOptionName.
* @var string $title The title shown for the option.
* @var string $helpLink If defined, the link to the corresponding external help page.
* @var bool $premium If defined, the option will be tagged as premium only and not allow its value to change for free users.
*/
$toggleID = 'wfls-option-' . preg_replace('/[^a-z0-9]/i', '-', $toggleOptionName);
$textAreaID = 'wfls-option-' . preg_replace('/[^a-z0-9]/i', '-', $textAreaOptionName);
?>
<ul class="wfls-option wfls-option-toggled-textarea<?php if (!wfConfig::p() && isset($premium) && $premium) { echo ' wfls-option-premium'; } ?>" data-toggle-option="<?php echo esc_attr($toggleOptionName); ?>" data-enabled-toggle-value="<?php echo esc_attr($enabledToggleValue); ?>" data-disabled-toggle-value="<?php echo esc_attr($disabledToggleValue); ?>" data-original-toggle-value="<?php echo esc_attr($toggleValue == $enabledToggleValue ? $enabledToggleValue : $disabledToggleValue); ?>" data-text-area-option="<?php echo esc_attr($textAreaOptionName); ?>" data-original-text-area-value="<?php echo esc_attr($textAreaValue); ?>">
<li id="<?php echo esc_attr($toggleID); ?>" class="wfls-option-checkbox<?php echo ($toggleValue == $enabledToggleValue ? ' wfls-checked' : ''); ?>" role="checkbox" aria-checked="<?php echo ($toggleValue == $enabledToggleValue ? 'true' : 'false'); ?>" tabindex="0"><i class="wfls-ion-ios-checkmark-empty" aria-hidden="true" aria-labelledby="<?php echo esc_attr($toggleID); ?>-label"></i></li>
<li class="wfls-option-title"><span id="<?php echo esc_attr($toggleID); ?>-label"><?php echo esc_html($title); ?></span><?php if (!wfConfig::p() && isset($premium) && $premium) { echo ' <a href="https://www.wordfence.com/gnl1optionUpgrade/wordfence-signup/" target="_blank" rel="noopener noreferrer" class="wfls-premium-link">' . esc_html__('Premium Feature', 'wordfence-2fa') . '</a>'; } ?><?php if (isset($helpLink)) { echo ' <a href="' . esc_attr($helpLink) . '" target="_blank" rel="noopener noreferrer" class="wfls-inline-help"><i class="' . (\WordfenceLS\Controller_WordfenceLS::shared()->should_use_core_font_awesome_styles() ? 'wf-fa wf-fa-question-circle-o' : 'wfls-fa wfls-fa-question-circle-o') . '" aria-hidden="true"></i></a>'; } ?></li>
<li id="<?php echo esc_attr($textAreaID); ?>" class="wfls-option-textarea">
<select<?php echo ($toggleValue == $enabledToggleValue && !(!wfConfig::p() && isset($premium) && $premium) ? '' : ' disabled'); ?> aria-labelledby="<?php echo esc_attr($toggleID); ?>-label">
<textarea<?php echo (!(!wfConfig::p() && isset($premium) && $premium) ? '' : ' disabled'); ?>><?php echo esc_html($textAreaValue); ?></textarea>
</select>
</li>
</ul>

View File

@@ -0,0 +1,33 @@
<?php
if (!defined('WORDFENCE_LS_VERSION')) { exit; }
/**
* Presents a boolean option with a checkbox toggle control.
*
* @var string $optionName The option name. Required.
* @var string $enabledValue The value to save in $option if the toggle is enabled. Required.
* @var string $disabledValue The value to save in $option if the toggle is disabled. Required.
* @var string $value The current value of $optionName. Required.
* @var string|\WordfenceLS\Text\Model_HTML $title The title shown for the option. Required.
* @var string|\WordfenceLS\Text\Model_HTML $subtitle The title shown for the option. Optional.
* @var string $helpLink If defined, the link to the corresponding external help page. Optional.
* @var bool $disabled If defined and truthy, the option will start out disabled. Optional.
* @var bool $child If true, this option will be rendered ar a child option. Optional.
*/
$id = 'wfls-option-' . preg_replace('/[^a-z0-9]/i', '-', $optionName);
?>
<ul id="<?php echo esc_attr($id); ?>" class="wfls-option wfls-option-toggled<?php if (isset($disabled) && $disabled) { echo ' wfls-disabled'; } if (isset($child) && $child) { echo ' wfls-child-option'; }?>" data-option="<?php echo esc_attr($optionName); ?>" data-enabled-value="<?php echo esc_attr($enabledValue); ?>" data-disabled-value="<?php echo esc_attr($disabledValue); ?>" data-original-value="<?php echo esc_attr($value == $enabledValue ? $enabledValue : $disabledValue); ?>">
<li class="wfls-option-checkbox<?php echo ($value == $enabledValue ? ' wfls-checked' : ''); ?>" role="checkbox" aria-checked="<?php echo ($value == $enabledValue ? 'true' : 'false'); ?>" tabindex="0" aria-labelledby="<?php echo esc_attr($id); ?>-label"><i class="wfls-ion-ios-checkmark-empty" aria-hidden="true"></i></li>
<li class="wfls-option-title">
<?php if (isset($subtitle)): ?>
<ul class="wfls-flex-vertical wfls-flex-align-left">
<li>
<?php endif; ?>
<span id="<?php echo esc_attr($id); ?>-label"><?php echo \WordfenceLS\Text\Model_HTML::esc_html($title); ?></span><?php if (isset($helpLink)) { echo ' <a href="' . esc_attr($helpLink) . '" target="_blank" rel="noopener noreferrer" class="wfls-inline-help"><i class="' . (\WordfenceLS\Controller_WordfenceLS::shared()->should_use_core_font_awesome_styles() ? 'wf-fa wf-fa-question-circle-o' : 'wfls-fa wfls-fa-question-circle-o') . '" aria-hidden="true"></i></a>'; } ?>
<?php if (isset($subtitle)): ?>
</li>
<li class="wfls-option-subtitle"><?php echo \WordfenceLS\Text\Model_HTML::esc_html($subtitle); ?></li>
</ul>
<?php endif; ?>
</li>
</ul>

View File

@@ -0,0 +1,39 @@
<?php
if (!defined('WORDFENCE_LS_VERSION')) { exit; }
/**
* Presents an option with a token field for value entry.
*
* Expects $tokenOptionName, $tokenValue, and $title to be defined. $helpLink may also be defined.
*
* @var string $tokenOptionName The option name.
* @var array $tokenValue The current value of $tokenOptionName. It will be JSON-encoded as an array of strings.
* @var string $title The title shown for the option.
* @var string $helpLink If defined, the link to the corresponding external help page.
* @var bool $premium If defined, the option will be tagged as premium only and not allow its value to change for free users.
*/
$id = 'wfls-option-' . preg_replace('/[^a-z0-9]/i', '-', $tokenOptionName);
?>
<ul id="<?php echo esc_attr($id); ?>" class="wfls-option wfls-option-token<?php if (!wfConfig::p() && isset($premium) && $premium) { echo ' wfls-option-premium'; } ?>" data-token-option="<?php echo esc_attr($tokenOptionName); ?>" data-original-token-value="<?php echo esc_attr(json_encode($tokenValue)); ?>">
<li class="wfls-option-spacer"></li>
<li class="wfls-flex-vertical wfls-flex-align-left">
<div class="wfls-option-title">
<?php if (isset($subtitle)): ?>
<ul class="wfls-flex-vertical wfls-flex-align-left">
<li>
<?php endif; ?>
<span id="<?php echo esc_attr($id); ?>-label"><?php echo esc_html($title); ?></span><?php if (!wfConfig::p() && isset($premium) && $premium) { echo ' <a href="https://www.wordfence.com/gnl1optionUpgrade/wordfence-signup/" target="_blank" rel="noopener noreferrer" class="wfls-premium-link">' . esc_html__('Premium Feature', 'wordfence-2fa') . '</a>'; } ?><?php if (isset($helpLink)) { echo ' <a href="' . esc_attr($helpLink) . '" target="_blank" rel="noopener noreferrer" class="wfls-inline-help"><i class="' . (\WordfenceLS\Controller_WordfenceLS::shared()->should_use_core_font_awesome_styles() ? 'wf-fa wf-fa-question-circle-o' : 'wfls-fa wfls-fa-question-circle-o') . '" aria-hidden="true"></i></a>'; } ?>
<?php if (isset($subtitle)): ?>
</li>
<li class="wfls-option-subtitle"><?php echo esc_html($subtitle); ?></li>
</ul>
<?php endif; ?>
</div>
<select multiple<?php echo (!(!wfConfig::p() && isset($premium) && $premium) ? '' : ' disabled'); ?> aria-labelledby="<?php echo esc_attr($id); ?>-label">
<?php foreach ($tokenValue as $o): ?>
<option value="<?php echo esc_attr($o); ?>" selected><?php echo esc_html($o); ?></option>
<?php endforeach; ?>
</select>
<div class="wfls-option-token-tags"></div>
</li>
</ul>

View File

@@ -0,0 +1,89 @@
<?php
if (!defined('WORDFENCE_LS_VERSION')) { exit; }
$assets = isset($assets) ? $assets : array();
$scriptData = isset($scriptData) ? $scriptData : array();
$enabled = \WordfenceLS\Controller_Users::shared()->has_2fa_active($user);
$requires2fa = \WordfenceLS\Controller_Users::shared()->requires_2fa($user, $inGracePeriod, $requiredAt);
$lockedOut = $requires2fa && !$enabled;
$containerClasses = 'wfls-flex-row ' . ($stacked ? 'wfls-flex-row-wrapped' : 'wfls-flex-row-wrappable wfls-flex-row-equal-heights');
$columnClasses = 'wfls-flex-row wfls-flex-item-xs-100 ' . ($stacked ? '' : 'wfls-flex-row-equal-heights');
?>
<?php if (!empty($scriptData)): ?>
<script type="text/javascript">
<?php foreach ($scriptData as $key => $data): ?>
var <?php echo $key ?> = <?php echo wp_json_encode($data); ?>;
<?php endforeach ?>
</script>
<?php endif ?>
<?php foreach ($assets as $asset): ?>
<?php $asset->renderInlineIfNotEnqueued(); ?>
<?php endforeach ?>
<div id="wfls-management-embedded"<?php if ($stacked): ?> class="stacked" <?php endif ?>>
<p><?php echo wp_kses(sprintf(__('Two-Factor Authentication, or 2FA, significantly improves login security for your account. Wordfence 2FA works with a number of TOTP-based apps like Google Authenticator, FreeOTP, and Authy. For a full list of tested TOTP-based apps, <a href="%s" target="_blank" rel="noopener noreferrer">click here</a>.', 'wordfence-2fa'), \WordfenceLS\Controller_Support::esc_supportURL(\WordfenceLS\Controller_Support::ITEM_MODULE_LOGIN_SECURITY_2FA)), array('a'=>array('href'=>array(), 'target'=>array(), 'rel'=>array()))); ?></p>
<div id="wfls-deactivation-controls" class="<?php echo $containerClasses ?>"<?php if (!$enabled) { echo ' style="display: none;"'; } ?>>
<!-- begin status content -->
<div class="<?php echo $columnClasses ?>">
<?php
echo \WordfenceLS\Model_View::create('manage/deactivate', array(
'user' => $user,
))->render();
?>
</div>
<!-- end status content -->
<!-- begin regenerate codes -->
<div class="<?php echo $columnClasses ?>">
<?php
echo \WordfenceLS\Model_View::create('manage/regenerate', array(
'user' => $user,
'remaining' => \WordfenceLS\Controller_Users::shared()->recovery_code_count($user),
))->render();
?>
</div>
<!-- end regenerate codes -->
</div>
<div id="wfls-activation-controls" class="<?php echo $containerClasses ?><?php if (!$stacked): ?> wfls-no-bottom-column-margin<?php endif ?>"<?php if ($enabled) { echo ' style="display: none;"'; } ?>>
<?php
$initializationData = new \WordfenceLS\Model_2faInitializationData($user);
?>
<!-- begin qr code -->
<div class="<?php echo $columnClasses ?><?php if (!$stacked): ?> wfls-col-sm-half-padding-right wfls-flex-item-sm-50<?php endif ?>">
<?php
echo \WordfenceLS\Model_View::create('manage/code', array(
'initializationData' => $initializationData
))->render();
?>
</div>
<!-- end qr code -->
<!-- begin activation -->
<div class="<?php echo $columnClasses ?><?php if (!$stacked): ?> wfls-col-sm-half-padding-left wfls-flex-item-sm-50<?php endif ?>">
<?php
echo \WordfenceLS\Model_View::create('manage/activate', array(
'initializationData' => $initializationData
))->render();
?>
</div>
<!-- end activation -->
</div>
<div id="wfls-grace-period-controls" class="<?php echo $containerClasses ?>"<?php if ($enabled || !($lockedOut || $inGracePeriod)) { echo ' style="display: none;"'; } ?>>
<div class="<?php echo $columnClasses ?> wfls-add-top">
<?php
echo \WordfenceLS\Model_View::create('manage/grace-period', array(
'user' => $user,
'lockedOut' => $lockedOut,
'gracePeriod' => $inGracePeriod,
'requiredAt' => $requiredAt
))->render();
?>
</div>
</div>
<?php
/**
* Fires after the main content of the activation page has been output.
*/
do_action('wfls_activation_page_footer');
?>
</div>

View File

@@ -0,0 +1,119 @@
<?php
if (!defined('WORDFENCE_LS_VERSION')) { exit; }
/**
* @var \WP_User $user The user being edited. Required.
* @var bool $canEditUsers Whether or not the viewer of the page can edit other users. Optional, defaults to false.
*/
if (!isset($canEditUsers)) {
$canEditUsers = false;
}
$ownAccount = false;
$ownUser = wp_get_current_user();
if ($ownUser->ID == $user->ID) {
$ownAccount = true;
}
$enabled = \WordfenceLS\Controller_Users::shared()->has_2fa_active($user);
$requires2fa = \WordfenceLS\Controller_Users::shared()->requires_2fa($user, $inGracePeriod, $requiredAt);
$lockedOut = $requires2fa && !$enabled;
?>
<p><?php echo wp_kses(sprintf(__('Two-Factor Authentication, or 2FA, significantly improves login security for your website. Wordfence 2FA works with a number of TOTP-based apps like Google Authenticator, FreeOTP, and Authy. For a full list of tested TOTP-based apps, <a href="%s" target="_blank" rel="noopener noreferrer">click here</a>.', 'wordfence-2fa'), \WordfenceLS\Controller_Support::esc_supportURL(\WordfenceLS\Controller_Support::ITEM_MODULE_LOGIN_SECURITY_2FA)), array('a'=>array('href'=>array(), 'target'=>array(), 'rel'=>array()))); ?></p>
<?php if ($canEditUsers): ?>
<div id="wfls-editing-display" class="wfls-flex-row wfls-flex-row-xs-wrappable wfls-flex-row-equal-heights">
<div class="wfls-block wfls-always-active wfls-flex-item-full-width wfls-add-bottom">
<div class="wfls-block-header wfls-block-header-border-bottom">
<div class="wfls-block-header-content">
<div class="wfls-block-title">
<strong><?php echo wp_kses(sprintf(__('Editing User:&nbsp;&nbsp;%s <span class="wfls-text-plain">%s</span>', 'wordfence-2fa'), get_avatar($user->ID, 16, '', $user->user_login), \WordfenceLS\Text\Model_HTML::esc_html($user->user_login) . ($ownAccount ? ' ' . __('(you)', 'wordfence-2fa') : '')), array('span'=>array('class'=>array()))); ?></strong>
</div>
</div>
</div>
</div>
</div>
<?php endif; ?>
<div id="wfls-deactivation-controls" class="wfls-flex-row wfls-flex-row-wrappable wfls-flex-row-equal-heights"<?php if (!$enabled) { echo ' style="display: none;"'; } ?>>
<!-- begin status content -->
<div class="wfls-flex-row wfls-flex-row-equal-heights wfls-flex-item-xs-100">
<?php
echo \WordfenceLS\Model_View::create('manage/deactivate', array(
'user' => $user,
))->render();
?>
</div>
<!-- end status content -->
<!-- begin regenerate codes -->
<div class="wfls-flex-row wfls-flex-row-equal-heights wfls-flex-item-xs-100">
<?php
echo \WordfenceLS\Model_View::create('manage/regenerate', array(
'user' => $user,
'remaining' => \WordfenceLS\Controller_Users::shared()->recovery_code_count($user),
))->render();
?>
</div>
<!-- end regenerate codes -->
</div>
<div id="wfls-activation-controls" class="wfls-flex-row wfls-flex-row-xs-wrappable wfls-flex-row-equal-heights"<?php if ($enabled) { echo ' style="display: none;"'; } ?>>
<?php
$initializationData = new \WordfenceLS\Model_2faInitializationData($user);
?>
<!-- begin qr code -->
<div class="wfls-flex-row wfls-flex-row-equal-heights wfls-col-sm-half-padding-right wfls-flex-item-xs-100 wfls-flex-item-sm-50">
<?php
echo \WordfenceLS\Model_View::create('manage/code', array(
'initializationData' => $initializationData
))->render();
?>
</div>
<!-- end qr code -->
<!-- begin activation -->
<div class="wfls-flex-row wfls-flex-row-equal-heights wfls-col-sm-half-padding-left wfls-flex-item-xs-100 wfls-flex-item-sm-50">
<?php
echo \WordfenceLS\Model_View::create('manage/activate', array(
'initializationData' => $initializationData
))->render();
?>
</div>
<!-- end activation -->
</div>
<div id="wfls-grace-period-controls" class="wfls-flex-row wfls-flex-row-xs-wrappable wfls-flex-row-equal-heights"<?php if ($enabled || !($lockedOut || $inGracePeriod)) { echo ' style="display: none;"'; } ?>>
<div class="wfls-flex-row wfls-flex-row-equal-heights wfls-flex-item-xs-100 wfls-add-top">
<?php
echo \WordfenceLS\Model_View::create('manage/grace-period', array(
'user' => $user,
'lockedOut' => $lockedOut,
'gracePeriod' => $inGracePeriod,
'requiredAt' => $requiredAt
))->render();
?>
</div>
</div>
<?php
/**
* Fires after the main content of the activation page has been output.
*/
do_action('wfls_activation_page_footer');
$time = time();
$correctedTime = \WordfenceLS\Controller_Time::time($time);
$tz = get_option('timezone_string');
if (empty($tz)) {
$offset = get_option('gmt_offset');
$tz = 'UTC' . ($offset >= 0 ? '+' . $offset : $offset);
}
?>
<?php if (\WordfenceLS\Controller_Permissions::shared()->can_manage_settings()): ?>
<p><?php esc_html_e('Server Time:', 'wordfence-2fa'); ?> <?php echo date('Y-m-d H:i:s', $time); ?> UTC (<?php echo \WordfenceLS\Controller_Time::format_local_time('Y-m-d H:i:s', $time) . ' ' . $tz; ?>)<br>
<?php esc_html_e('Browser Time:', 'wordfence-2fa'); ?> <script type="application/javascript">var date = new Date(); document.write(date.toUTCString() + ' (' + date.toString() + ')');</script><br>
<?php
if (\WordfenceLS\Controller_Settings::shared()->is_ntp_enabled()) {
echo esc_html__('Corrected Time (NTP):', 'wordfence-2fa') . ' ' . date('Y-m-d H:i:s', $correctedTime) . ' UTC (' . \WordfenceLS\Controller_Time::format_local_time('Y-m-d H:i:s', $correctedTime) . ' ' . $tz . ')<br>';
}
else if (WORDFENCE_LS_FROM_CORE && $correctedTime != $time) {
echo esc_html__('Corrected Time (WF):', 'wordfence-2fa') . ' ' . date('Y-m-d H:i:s', $correctedTime) . ' UTC (' . \WordfenceLS\Controller_Time::format_local_time('Y-m-d H:i:s', $correctedTime) . ' ' . $tz . ')<br>';
}
?>
<?php esc_html_e('Detected IP:', 'wordfence-2fa'); ?> <?php echo \WordfenceLS\Text\Model_HTML::esc_html(\WordfenceLS\Model_Request::current()->ip()); if (\WordfenceLS\Controller_Whitelist::shared()->is_whitelisted(\WordfenceLS\Model_Request::current()->ip())) { echo ' (' . esc_html__('allowlisted', 'wordfence-2fa') . ')'; } ?></p>
<?php endif; ?>

View File

@@ -0,0 +1,37 @@
<?php
if (!defined('WORDFENCE_LS_VERSION')) { exit; }
/**
* @var array $sections The content tabs, each element is an array of the syntax array('tab' => Model_Tab instance, 'title' => Title instance, 'content' => HTML content). Required.
*/
?>
<?php do_action('wfls_activation_page_header'); ?>
<div class="wrap wordfence-ls">
<?php
if (\WordfenceLS\Controller_Permissions::shared()->can_manage_settings() && !\WordfenceLS\Controller_Settings::shared()->get_bool(\WordfenceLS\Controller_Settings::OPTION_DISMISSED_FRESH_INSTALL_MODAL) && !WORDFENCE_LS_FROM_CORE) {
echo \WordfenceLS\Model_View::create('onboarding/standalone-header')->render();
}
?>
<div class="wfls-container-fluid">
<?php
$tabs = array_map(function($t) { return $t['tab']; }, $sections);
echo \WordfenceLS\Model_View::create('page/tabbar', array(
'tabs' => $tabs,
))->render();
?>
<div class="wfls-row">
<div class="wfls-col-xs-12">
<?php foreach ($sections as $s): ?>
<div id="<?php echo esc_attr($s['tab']->id); ?>" class="wfls-tab-content" data-title="<?php echo esc_attr($s['tab']->pageTitle); ?>">
<?php
echo \WordfenceLS\Model_View::create('page/section-title', array(
'title' => $s['title'],
))->render();
echo $s['content'];
?>
</div> <!-- end <?php echo \WordfenceLS\Text\Model_HTML::esc_html($s['tab']->id); ?> block -->
<?php endforeach; ?>
</div> <!-- end content block -->
</div> <!-- end row -->
</div> <!-- end container -->
</div>

View File

@@ -0,0 +1,8 @@
<?php
if (!defined('WORDFENCE_LS_VERSION')) { exit; }
?>
<div>
<h2><?php esc_html_e('Permission Denied', 'wordfence-2fa') ?></h2>
<p><?php esc_html_e('You do not have permission to manage 2FA settings for your account.', 'wordfence-2fa') ?></p>
</div>

View File

@@ -0,0 +1,55 @@
<?php
if (!defined('WORDFENCE_LS_VERSION')) { exit; }
?>
<?php if (is_multisite()): ?>
<p><em>(<?php esc_html_e('This page only shows users and roles on the main site of this network', 'wordfence-2fa') ?>)</em></p>
<?php endif ?>
<div class="wfls-block wfls-always-active wfls-flex-item-full-width wfls-add-bottom">
<?php if ($requiredAt === false): ?>
<div class="wfls-block-content">
<p><?php echo esc_html(sprintf(__('2FA is not required for the %s role', 'wordfence-2fa'), $roleTitle)) ?></p>
</div>
<?php elseif (empty($users)): ?>
<div class="wfls-block-content">
<p>
<?php if ($page == 1): ?>
<?php echo esc_html(sprintf(__('No users found in the %s state for the %s role', 'wordfence-2fa'), $stateTitle, $roleTitle)) ?>
<?php else: ?>
<?php echo esc_html(sprintf(__('Page %d is out of range', 'wordfence-2fa'), $page)) ?>
<?php endif ?>
</p>
</div>
<?php else: ?>
<table class="wfls-table wfls-table-striped wfls-table-header-separators wfls-table-expanded wfls-no-bottom">
<tr>
<th>User</th>
<th>Required Date</th>
</tr>
<?php foreach ($users as $user): ?>
<tr>
<th scope="row"><a href="<?php echo esc_attr(get_edit_user_link($user->user_id)) ?>#wfls-user-settings"><?php echo esc_html($user->user_login) ?></a></td>
<td>
<?php if ($user->required_at): ?>
<?php echo esc_html(\WordfenceLS\Controller_Time::format_local_time('F j, Y g:i A', $user->required_at)) ?>
<?php else: ?>
<?php esc_html_e('N/A', 'wordfence-2fa'); ?>
<?php endif ?>
</td>
</tr>
<?php endforeach ?>
<?php if ($page != 1 || !$lastPage): ?>
<tr>
<td colspan="2" class="wfls-center">
<?php if ($page > 1): ?>
<a href="<?php echo esc_attr(add_query_arg($pageKey, $page-1) . "#$stateKey") ?>"><span class="dashicons dashicons-arrow-left-alt2"></span></a>
<?php endif ?>
<strong class="wfls-page-indicator"><?php esc_html_e('Page ', 'wordfence-2fa') ?><?php echo (int) $page ?></strong>
<?php if (!$lastPage): ?>
<a href="<?php echo esc_attr(add_query_arg($pageKey, $page+1) . "#$stateKey") ?>"><span class="dashicons dashicons-arrow-right-alt2"></span></a>
<?php endif ?>
</td>
</tr>
<?php endif ?>
</table>
<?php endif ?>
</div>

View File

@@ -0,0 +1,16 @@
<?php
if (!defined('WORDFENCE_LS_VERSION')) { exit; }
/**
* @var \WordfenceLS\Page\Model_Title $title The page title parameters.
* @var bool $showIcon Whether or not to show the header icon. Optional, defaults to false.
*/
?>
<div class="wfls-section-title">
<?php if (isset($showIcon) && $showIcon): ?>
<div class="wfls-header-icon wfls-hidden-xs"></div>
<?php endif; ?>
<h2 class="wfls-center-xs" id="section-title-<?php echo esc_attr($title->id); ?>"><?php echo \WordfenceLS\Text\Model_HTML::esc_html($title->title); ?></h2>
<?php if ($title->helpURL !== null && $title->helpLink !== null): ?>
<span class="wfls-hidden-xs"><a href="<?php echo esc_url($title->helpURL); ?>" target="_blank" rel="noopener noreferrer" class="wfls-help-link"><?php echo \WordfenceLS\Text\Model_HTML::esc_html($title->helpLink); ?> <i class="<?php echo (\WordfenceLS\Controller_WordfenceLS::shared()->should_use_core_font_awesome_styles() ? 'wf-fa wf-fa-external-link' : 'wfls-fa wfls-fa-external-link'); ?>" aria-hidden="true"></i></a></span>
<?php endif; ?>
</div>

View File

@@ -0,0 +1,26 @@
<?php
if (!defined('WORDFENCE_LS_VERSION')) { exit; }
?>
<div class="wfls-save-banner wfls-nowrap wfls-padding-add-right-responsive">
<a href="#" id="wfls-cancel-changes" class="wfls-btn wfls-btn-sm wfls-btn-default wfls-disabled"><?php echo wp_kses(__('Cancel<span class="wfls-visible-sm-inline"> Changes</span>', 'wordfence-2fa'), array('span'=>array('class'=>array()))); ?></a>&nbsp;&nbsp;<a href="#" id="wfls-save-changes" class="wfls-btn wfls-btn-sm wfls-btn-primary wfls-disabled"><?php echo wp_kses(__('Save<span class="wfls-visible-sm-inline"> Changes</span>', 'wordfence-2fa'), array('span'=>array('class'=>array()))); ?></a>
</div>
<div id="wfls-settings" class="wfls-flex-row wfls-flex-row-wrappable wfls-flex-row-equal-heights">
<!-- begin status content -->
<div id="wfls-user-stats" class="wfls-flex-row wfls-flex-row-equal-heights wfls-flex-item-xs-100">
<?php
echo \WordfenceLS\Model_View::create('settings/user-stats', array(
'counts' => \WordfenceLS\Controller_Users::shared()->get_detailed_user_counts_if_enabled(),
))->render();
?>
</div>
<!-- end status content -->
<!-- begin options content -->
<div id="wfls-options">
<?php
echo \WordfenceLS\Model_View::create('settings/options', array(
'hasWoocommerce' => $hasWoocommerce
))->render();
?>
</div>
<!-- end options content -->
</div>

View File

@@ -0,0 +1,23 @@
<?php
if (!defined('WORDFENCE_LS_VERSION')) { exit; }
/**
* @var array $tabs An array of Tab instances. Required.
*/
?>
<div class="wfls-row wfls-tab-container">
<div class="wfls-col-xs-12">
<div class="wp-header-end"></div>
<ul class="wfls-page-tabs">
<li class="wfls-header-icon"></li>
<?php foreach ($tabs as $t): ?>
<?php
$a = $t->a;
if (!preg_match('/^https?:\/\//i', $a)) {
$a = '#top#' . urlencode($a);
}
?>
<li class="wfls-tab" id="wfls-tab-<?php echo esc_attr($t->id); ?>" data-target="<?php echo esc_attr($t->id); ?>" data-page-title="<?php echo esc_attr($t->pageTitle); ?>"><a href="<?php echo esc_url($a); ?>"><?php echo esc_html($t->tabTitle); ?></a></li>
<?php endforeach; ?>
</ul>
</div>
</div>

View File

@@ -0,0 +1,270 @@
<?php
if (!defined('WORDFENCE_LS_VERSION')) { exit; }
?>
<div class="wfls-flex-row wfls-flex-row-equal-heights wfls-flex-item-xs-100">
<div class="wfls-block wfls-always-active wfls-flex-item-full-width">
<div class="wfls-block-header wfls-block-header-border-bottom">
<div class="wfls-block-header-content">
<div class="wfls-block-title">
<h3><?php esc_html_e('2FA', 'wordfence-2fa'); ?></h3>
</div>
</div>
</div>
<div class="wfls-block-content">
<ul class="wfls-block-list">
<li>
<?php
$roles = new \WP_Roles();
$options = array();
if (is_multisite()) {
$options[] = array(
'role' => 'super-admin',
'name' => 'enabled-roles.super-admin',
'title' => __('Super Administrator', 'wordfence-2fa'),
'editable' => true,
'allow_disabling' => false,
'state' => \WordfenceLS\Controller_Settings::shared()->get_required_2fa_role_activation_time('super-admin') !== false ? 'required' : 'optional'
);
}
foreach ($roles->role_objects as $name => $r) {
/** @var \WP_Role $r */
$options[] = array(
'role' => $name,
'name' => 'enabled-roles.' . $name,
'title' => $roles->role_names[$name],
'editable' => true,
'allow_disabling' => (!is_multisite() && $name == 'administrator' ? false : true),
'state' => \WordfenceLS\Controller_Settings::shared()->get_required_2fa_role_activation_time($name) !== false ? 'required' : ($r->has_cap(\WordfenceLS\Controller_Permissions::CAP_ACTIVATE_2FA_SELF) ? 'optional' : 'disabled')
);
}
echo \WordfenceLS\Model_View::create('options/option-roles', array('options' => $options, 'hasWoocommerce' => $hasWoocommerce))->render();
?>
</li>
<li>
<?php
echo \WordfenceLS\Model_View::create('options/option-toggled', array(
'optionName' => \WordfenceLS\Controller_Settings::OPTION_REMEMBER_DEVICE_ENABLED,
'enabledValue' => '1',
'disabledValue' => '0',
'value' => \WordfenceLS\Controller_Settings::shared()->get_bool(\WordfenceLS\Controller_Settings::OPTION_REMEMBER_DEVICE_ENABLED) ? '1': '0',
'title' => new \WordfenceLS\Text\Model_HTML('<strong>' . esc_html__('Allow remembering device for 30 days', 'wordfence-2fa') . '</strong>'),
'subtitle' => __('If enabled, users with 2FA enabled may choose to be prompted for a code only once every 30 days per device.', 'wordfence-2fa'),
))->render();
?>
</li>
<li>
<?php
echo \WordfenceLS\Model_View::create('options/option-switch', array(
'optionName' => \WordfenceLS\Controller_Settings::OPTION_XMLRPC_ENABLED,
'value' => \WordfenceLS\Controller_Settings::shared()->get_bool(\WordfenceLS\Controller_Settings::OPTION_XMLRPC_ENABLED) ? '1': '0',
'title' => new \WordfenceLS\Text\Model_HTML('<strong>' . esc_html__('Require 2FA for XML-RPC call authentication', 'wordfence-2fa') . '</strong>'),
'subtitle' => __('If enabled, XML-RPC calls that require authentication will also require a valid 2FA code to be appended to the password. You must choose the "Skipped" option if you use the WordPress app, the Jetpack plugin, or other services that require XML-RPC.', 'wordfence-2fa'),
'states' => array(
array('value' => '0', 'label' => __('Skipped', 'wordfence-2fa')),
array('value' => '1', 'label' => __('Required', 'wordfence-2fa')),
),
'noSpacer' => true,
'alignment' => 'wfls-right',
))->render();
?>
</li>
<li>
<?php
echo \WordfenceLS\Model_View::create('options/option-toggled', array(
'optionName' => \WordfenceLS\Controller_Settings::OPTION_ALLOW_XML_RPC,
'enabledValue' => '0',
'disabledValue' => '1',
'value' => \WordfenceLS\Controller_Settings::shared()->get_bool(\WordfenceLS\Controller_Settings::OPTION_ALLOW_XML_RPC) ? '1': '0',
'title' => new \WordfenceLS\Text\Model_HTML('<strong>' . esc_html__('Disable XML-RPC authentication', 'wordfence-2fa') . '</strong>'),
'subtitle' => __('If disabled, XML-RPC requests that attempt authentication will be rejected, whether the user has 2FA enabled or not.', 'wordfence-2fa'),
))->render();
?>
</li>
</ul>
</div>
</div>
</div>
<div class="wfls-flex-row wfls-flex-row-equal-heights wfls-flex-item-xs-100">
<div class="wfls-block wfls-always-active wfls-flex-item-full-width">
<div class="wfls-block-header wfls-block-header-border-bottom">
<div class="wfls-block-header-content">
<div class="wfls-block-title">
<h3><?php esc_html_e('WooCommerce & Custom Integrations', 'wordfence-2fa'); ?></h3>
</div>
</div>
</div>
<div class="wfls-block-content">
<ul class="wfls-block-list">
<li>
<?php
echo \WordfenceLS\Model_View::create('options/option-toggled', array(
'optionName' => \WordfenceLS\Controller_Settings::OPTION_ENABLE_WOOCOMMERCE_INTEGRATION,
'enabledValue' => '1',
'disabledValue' => '0',
'value' => \WordfenceLS\Controller_Settings::shared()->get_bool(\WordfenceLS\Controller_Settings::OPTION_ENABLE_WOOCOMMERCE_INTEGRATION) ? '1': '0',
'title' => new \WordfenceLS\Text\Model_HTML('<strong>' . esc_html__('WooCommerce integration', 'wordfence-2fa') . '</strong>'),
'subtitle' => __('When enabled, reCAPTCHA and 2FA prompt support will be added to WooCommerce login and registration forms in addition to the default WordPress forms. Testing WooCommerce forms after enabling this feature is recommended to ensure plugin compatibility.', 'wordfence-2fa'),
))->render();
?>
</li>
<li>
<?php
echo \WordfenceLS\Model_View::create('options/option-toggled', array(
'optionName' => \WordfenceLS\Controller_Settings::OPTION_ENABLE_WOOCOMMERCE_ACCOUNT_INTEGRATION,
'enabledValue' => '1',
'disabledValue' => '0',
'value' => \WordfenceLS\Controller_Settings::shared()->get_bool(\WordfenceLS\Controller_Settings::OPTION_ENABLE_WOOCOMMERCE_ACCOUNT_INTEGRATION) ? '1': '0',
'title' => new \WordfenceLS\Text\Model_HTML('<strong>' . esc_html__('Show Wordfence 2FA menu on WooCommerce Account page', 'wordfence-2fa') . '</strong>'),
'subtitle' => __('When enabled, a Wordfence 2FA tab will be added to the WooCommerce account menu which will provide access for users to manage 2FA settings outside of the WordPress admin area. Testing the WooCommerce account interface after enabling this feature is recommended to ensure theme compatibility.', 'wordfence-2fa'),
'helpLink' => \WordfenceLS\Controller_Support::supportURL(\WordfenceLS\Controller_Support::ITEM_MODULE_LOGIN_SECURITY_OPTION_WOOCOMMERCE_ACCOUNT_INTEGRATION),
'disabled' => !\WordfenceLS\Controller_Settings::shared()->get_bool(\WordfenceLS\Controller_Settings::OPTION_ENABLE_WOOCOMMERCE_INTEGRATION),
'child' => true
))->render();
?>
</li>
<li>
<?php
echo \WordfenceLS\Model_View::create('options/option-toggled', array(
'optionName' => \WordfenceLS\Controller_Settings::OPTION_ENABLE_SHORTCODE,
'enabledValue' => '1',
'disabledValue' => '0',
'value' => \WordfenceLS\Controller_Settings::shared()->get_bool(\WordfenceLS\Controller_Settings::OPTION_ENABLE_SHORTCODE) ? '1': '0',
'title' => new \WordfenceLS\Text\Model_HTML('<strong>' . esc_html__('2FA management shortcode', 'wordfence-2fa') . '</strong>'),
'subtitle' => __('When enabled, the "wordfence_2fa_management" shortcode may be used to provide access for users to manage 2FA settings on custom pages.', 'wordfence-2fa'),
'helpLink' => \WordfenceLS\Controller_Support::supportURL(\WordfenceLS\Controller_Support::ITEM_MODULE_LOGIN_SECURITY_OPTION_SHORTCODE)
))->render();
?>
</li>
<li>
<?php
echo \WordfenceLS\Model_View::create('options/option-toggled', array(
'optionName' => \WordfenceLS\Controller_Settings::OPTION_STACK_UI_COLUMNS,
'enabledValue' => '1',
'disabledValue' => '0',
'value' => \WordfenceLS\Controller_Settings::shared()->should_stack_ui_columns() ? '1': '0',
'title' => new \WordfenceLS\Text\Model_HTML('<strong>' . esc_html__('Use single-column layout for WooCommerce/shortcode 2FA management interface', 'wordfence-2fa') . '</strong>'),
'subtitle' => __('When enabled, the 2FA management interface embedded through the WooCommerce integration or via a shortcode will use a vertical stacked layout as opposed to horizontal columns. Adjust this setting as appropriate to match your theme. This may be overridden using the "stacked" attribute for individual shortcodes.', 'wordfence-2fa'),
'helpLink' => \WordfenceLS\Controller_Support::supportURL(\WordfenceLS\Controller_Support::ITEM_MODULE_LOGIN_SECURITY_OPTION_STACK_UI_COLUMNS)
))->render();
?>
</li>
</ul>
</div>
</div>
</div>
<div class="wfls-flex-row wfls-flex-row-equal-heights wfls-flex-item-xs-100">
<div class="wfls-block wfls-always-active wfls-flex-item-full-width">
<div class="wfls-block-header wfls-block-header-border-bottom">
<div class="wfls-block-header-content">
<div class="wfls-block-title">
<h3><?php esc_html_e('reCAPTCHA', 'wordfence-2fa'); ?></h3>
</div>
</div>
</div>
<div class="wfls-block-content">
<ul class="wfls-block-list">
<li>
<?php
echo \WordfenceLS\Model_View::create('options/option-captcha', array(
))->render();
?>
</li>
<li>
<?php
echo \WordfenceLS\Model_View::create('options/option-captcha-threshold', array(
))->render();
?>
</li>
<li>
<?php
echo \WordfenceLS\Model_View::create('options/option-toggled', array(
'optionName' => \WordfenceLS\Controller_Settings::OPTION_CAPTCHA_TEST_MODE,
'enabledValue' => '1',
'disabledValue' => '0',
'value' => \WordfenceLS\Controller_Settings::shared()->get_bool(\WordfenceLS\Controller_Settings::OPTION_CAPTCHA_TEST_MODE) ? '1': '0',
'title' => new \WordfenceLS\Text\Model_HTML('<strong>' . esc_html__('Run reCAPTCHA in test mode', 'wordfence-2fa') . '</strong>'),
'subtitle' => __('While in test mode, reCAPTCHA will score login and registration requests but not actually block them. The scores will be recorded and can be used to select a human/bot threshold value.', 'wordfence-2fa'),
))->render();
?>
</li>
</ul>
</div>
</div>
</div>
<div class="wfls-flex-row wfls-flex-row-equal-heights wfls-flex-item-xs-100">
<div class="wfls-block wfls-always-active wfls-flex-item-full-width">
<div class="wfls-block-header wfls-block-header-border-bottom">
<div class="wfls-block-header-content">
<div class="wfls-block-title">
<h3><?php esc_html_e('General', 'wordfence-2fa'); ?></h3>
</div>
</div>
</div>
<div class="wfls-block-content">
<ul class="wfls-block-list">
<li>
<?php
echo \WordfenceLS\Model_View::create('options/option-textarea', array(
'textOptionName' => \WordfenceLS\Controller_Settings::OPTION_2FA_WHITELISTED,
'textValue' => implode("\n", \WordfenceLS\Controller_Settings::shared()->whitelisted_ips()),
'title' => new \WordfenceLS\Text\Model_HTML('<strong>' . esc_html__('Allowlisted IP addresses that bypass 2FA and reCAPTCHA', 'wordfence-2fa') . '</strong>'),
'alignTitle' => 'top',
'subtitle' => __('Allowlisted IPs must be placed on separate lines. You can specify ranges using the following formats: 127.0.0.1/24, 127.0.0.[1-100], or 127.0.0.1-127.0.1.100.', 'wordfence-2fa'),
'subtitlePosition' => 'value',
'noSpacer' => true,
))->render();
?>
</li>
<?php if (!WORDFENCE_LS_FROM_CORE): ?>
<li>
<?php
echo \WordfenceLS\Model_View::create('options/option-ip-source', array())->render();
?>
</li>
<?php endif; ?>
<li>
<?php
echo \WordfenceLS\Model_View::create('options/option-ntp', array(
))->render();
?>
</li>
<li>
<?php
echo \WordfenceLS\Model_View::create('options/option-toggled', array(
'optionName' => \WordfenceLS\Controller_Settings::OPTION_ENABLE_LOGIN_HISTORY_COLUMNS,
'enabledValue' => '1',
'disabledValue' => '0',
'value' => \WordfenceLS\Controller_Settings::shared()->are_login_history_columns_enabled() ? '1': '0',
'title' => new \WordfenceLS\Text\Model_HTML('<strong>' . esc_html__('Show last login column on WP Users page', 'wordfence-2fa') . '</strong>'),
'subtitle' => __('When enabled, the last login timestamp will be displayed for each user on the WP Users page. When used in conjunction with reCAPTCHA, the most recent score will also be displayed for each user.', 'wordfence-2fa'),
))->render();
?>
</li>
<li>
<?php
echo \WordfenceLS\Model_View::create('options/option-toggled', array(
'optionName' => \WordfenceLS\Controller_Settings::OPTION_DELETE_ON_DEACTIVATION,
'enabledValue' => '1',
'disabledValue' => '0',
'value' => \WordfenceLS\Controller_Settings::shared()->get_bool(\WordfenceLS\Controller_Settings::OPTION_DELETE_ON_DEACTIVATION) ? '1': '0',
'title' => new \WordfenceLS\Text\Model_HTML('<strong>' . esc_html__('Delete Login Security tables and data on deactivation', 'wordfence-2fa') . '</strong>'),
'subtitle' => __('If enabled, all settings and 2FA records will be deleted on deactivation. If later reactivated, all users that previously had 2FA active will need to set it up again.', 'wordfence-2fa'),
))->render();
?>
</li>
</ul>
</div>
</div>
</div>
<script type="text/javascript">
(function($) {
$('#wfls-option-enable-woocommerce-integration').on('change', function() {
$('#wfls-option-enable-woocommerce-account-integration').toggleClass('wfls-disabled', !$(this).find('.wfls-option-checkbox').hasClass('wfls-checked'));
});
})(jQuery);
</script>

View File

@@ -0,0 +1,78 @@
<?php
if (!defined('WORDFENCE_LS_VERSION')) { exit; }
/**
* @var ?array $counts The counts to display or null to hide user counts.
*/
?>
<div class="wfls-block wfls-always-active wfls-flex-item-full-width">
<div class="wfls-block-header wfls-block-header-border-bottom">
<div class="wfls-block-header-content">
<div class="wfls-block-title">
<h3><?php esc_html_e('User Summary', 'wordfence-2fa'); ?></h3>
</div>
</div>
<div class="wfls-block-header-action wfls-block-header-action-text wfls-nowrap wfls-padding-add-right-responsive">
<a href="users.php"><?php esc_html_e('Manage Users', 'wordfence-2fa'); ?></a>
</div>
</div>
<?php if (is_array($counts)) : ?>
<div class="wfls-block-content wfls-padding-no-left wfls-padding-no-right">
<table class="wfls-table wfls-table-striped wfls-table-header-separators wfls-table-expanded wfls-no-bottom">
<thead>
<tr>
<th><?php esc_html_e('Role', 'wordfence-2fa'); ?></th>
<th class="wfls-center"><?php esc_html_e('Total Users', 'wordfence-2fa'); ?></th>
<th class="wfls-center"><?php esc_html_e('2FA Active', 'wordfence-2fa'); ?></th>
<th class="wfls-center"><?php esc_html_e('2FA Inactive', 'wordfence-2fa'); ?></th>
</tr>
</thead>
<tbody>
<?php
$roles = new WP_Roles();
$roleNames = $roles->get_names();
$roleNames['super-admin'] = __('Super Administrator', 'wordfence-2fa');
$roleNames[\WordfenceLS\Controller_Users::TRUNCATED_ROLE_KEY] = __('Custom Capabilities / Multiple Roles', 'wordfence-2fa');
foreach ($counts['avail_roles'] as $roleTag => $count):
$activeCount = (isset($counts['active_avail_roles'][$roleTag]) ? $counts['active_avail_roles'][$roleTag] : 0);
$inactiveCount = $count - $activeCount;
if ($activeCount === 0 && $inactiveCount === 0)
continue;
$roleName = $roleNames[$roleTag];
$requiredAt = \WordfenceLS\Controller_Settings::shared()->get_required_2fa_role_activation_time($roleTag);
$inactive = $inactiveCount > 0 && $requiredAt !== false;
$viewUsersBaseUrl = 'admin.php?' . http_build_query(array('page' => 'WFLS', 'role'=> $roleTag));
?>
<tr>
<td><?php echo \WordfenceLS\Text\Model_HTML::esc_html(translate_user_role($roleName)); ?></td>
<td class="wfls-center"><?php echo number_format($count); ?></td>
<td class="wfls-center"><?php echo number_format($activeCount); ?></td>
<td class="wfls-center">
<?php if ($inactive): ?><a href="<?php echo esc_attr(is_multisite() ? network_admin_url($viewUsersBaseUrl) : admin_url($viewUsersBaseUrl)); ?>"><?php endif ?>
<?php echo number_format($inactiveCount); ?>
<?php if ($inactive): ?> (<?php esc_html_e('View users', 'wordfence-2fa') ?>)</a><?php endif ?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
<tfoot>
<tr>
<th><?php esc_html_e('Total', 'wordfence-2fa'); ?></th>
<th class="wfls-center"><?php echo number_format($counts['total_users']); ?></th>
<th class="wfls-center"><?php echo number_format($counts['active_total_users']); ?></th>
<th class="wfls-center"><?php echo number_format($counts['total_users'] - $counts['active_total_users']); ?></th>
</tr>
<?php if (is_multisite()): ?>
<tr>
<td colspan="4" class="wfls-text-small"><?php esc_html_e('* User counts currently only reflect the main site on multisite installations.', 'wordfence-2fa'); ?></td>
</tr>
<?php endif; ?>
</tfoot>
</table>
</div>
<?php else: ?>
<div class="wfls-block-content wfls-padding-add-bottom">
<p><?php $counts === null ? esc_html_e('User counts are hidden by default on sites with large numbers of users in order to improve performance.', 'wordfence-2fa') : esc_html_e('User counts are currently disabled as the most recent attempt to count users failed to complete successfully.', 'wordfence-2fa') ?></p>
<a href="<?php echo esc_attr(add_query_arg('wfls-show-user-counts', 'true') . '#top#settings') ?>" class="wfls-btn wfls-btn-sm wfls-btn-primary"<?php if (\WordfenceLS\Controller_Users::shared()->should_force_user_counts()): ?> onclick="window.location.reload()"<?php endif ?>><?php $counts === null ? esc_html_e('Show User Counts', 'wordfence-2fa') : esc_html_e('Try Again', 'wordfence-2fa') ?></a>
</div>
<?php endif ?>
</div>

View File

@@ -0,0 +1,13 @@
<?php
if (!defined('WORDFENCE_LS_VERSION')) { exit; }
?>
<table id="wfls-grace-period-toggle-container" style="display: none">
<tr>
<th scope="row"><label for="wfls-grace-period-toggle"><?php esc_html_e('2FA Grace Period', 'wordfence-2fa') ?></label></th>
<td>
<input id="wfls-grace-period-toggle" name="wfls-grace-period-toggle" type="checkbox">
<label for="wfls-grace-period-toggle"><?php esc_html_e('Allow a grace period for this user prior to requiring Wordfence 2FA', 'wordfence-2fa') ?></label>
</td>
</tr>
</table>