10000 Feature/account security by ideadude · Pull Request #2677 · gocodebox/lifterlms · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Feature/account security #2677

New issue

Have a question about this project? Sign up for a free GitHub ac 8000 count to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 29 commits into
base: dev
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
1bd5220
adding spam settings and functions
ideadude Jun 5, 2024
5cea8ac
Wired up the spam checker.
ideadude Jun 14, 2024
d746c27
Checkout controller is always constructed, so fixed.
ideadude Jun 14, 2024
bda2763
undoing changes here
ideadude Jun 14, 2024
6eff6d1
adding captcha settings, needs js and code
ideadude Jun 19, 2024
2def872
Merge branch 'dev' into feature/account-security
ideadude Aug 3, 2024
96975bf
Merge branch 'dev' into feature/account-security
brianhogg Apr 21, 2025
07fa4bb
Merge branch 'dev' into feature/account-security
brianhogg Jun 9, 2025
93ab869
Getting test to pass with mock settings for saving test.
brianhogg Jun 9, 2025
c728d91
Formatting. Calling turnstile "secret" key vs. private to match docs.
brianhogg Jun 9, 2025
afd9630
Fixing check if spam protection is enabled, since the value is "yes" …
brianhogg Jun 9, 2025
f5ee8b5
Added turnstile and wired up the settings. Can override with a define…
brianhogg Jun 9, 2025
42914a0
Rename to secret key to match verbiage. Adding abspath check.
brianhogg Jun 9, 2025
9da28b7
WIP: reCAPTCHA v3
brianhogg Jun 9, 2025
9e43e9d
Only load if on front-end. Add textdomain.
brianhogg Jun 9, 2025
39522d7
WIP: POC for recaptcha on the checkout form.
brianhogg Jun 10, 2025
9291e97
Checks captcha on submit of a lifterlms form. Doesn't display notice …
brianhogg Jun 10, 2025
5f34852
Avoid rendering on the back-end. Adding logs via filter.
brianhogg Jun 10, 2025
37dccef
Print notices on the free enroll form so an error can be shown if cap…
brianhogg Jun 10, 2025
ecc57b0
Fix for test.
brianhogg Jun 10, 2025
15dad54
Fix warning when visiting the logs page for the first time.
brianhogg Jun 10, 2025
e575ed2
Removing log.
brianhogg Jun 10, 2025
fdd37a0
Changelogs.
brianhogg Jun 10, 2025
250a943
Merge branch 'dev' into feature/account-security
brianhogg Jun 12, 2025
b8315b7
Refactor into a base captcha class.
brianhogg Jun 12, 2025
3ab6c9e
Moving to a separate Security settings tab.
brianhogg Jun 12, 2025
0aac1ef
Conditional show/hide of the captcha settings.
brianhogg Jun 12, 2025
88a1712
Adding hint text.
brianhogg Jun 12, 2025
5b30db2
WIP: Handling when the checkout form exists, and both are trying to s…
brianhogg Jun 12, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .changelogs/feature_account-security-1.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
significance: minor
type: added
entry: Option for automatically blocking checkout spam.
3 changes: 3 additions & 0 deletions .changelogs/feature_account-security.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
significance: minor
type: added
entry: Support for Turnstile and Recaptcha v3 with checkout and registration forms.
35 changes: 26 additions & 9 deletions assets/js/llms-admin-settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,21 +80,38 @@

$( '.llms-conditional-controller' ).each( function() {

var $controls = $( $( this ).attr( 'data-controls' ) ).closest( 'tr' );

$( this ).on( 'change', function() {

var val;

if ( 'checkbox' === $( this ).attr( 'type' ) ) {
val = $( this ).is( ':checked' );
}
var $controls = $( $( this ).attr( 'data-controls' ) ).closest( 'tr' );

Check warning

Code scanning / CodeQL

DOM text reinterpreted as HTML Medium

DOM text
is reinterpreted as HTML without escaping meta-characters.

Copilot Autofix

AI about 21 hours ago

To fix the issue, the value retrieved from the data-controls attribute should be sanitized or escaped before being passed to the $() function. Specifically, jQuery's $.escapeSelector method can be used to escape any special characters in the selector string. This ensures that the input is treated strictly as a CSS selector and not as HTML or JavaScript.

The fix involves wrapping the $( this ).attr( 'data-controls' ) call with $.escapeSelector before passing it to $(). This change should be made on line 87.

Suggested changeset 1
assets/js/llms-admin-settings.js

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/assets/js/llms-admin-settings.js b/assets/js/llms-admin-settings.js
--- a/assets/js/llms-admin-settings.js
+++ b/assets/js/llms-admin-settings.js
@@ -86,3 +86,3 @@
 					if ( 'checkbox' === $( this ).attr( 'type' ) ) {
-						var $controls = $( $( this ).attr( 'data-controls' ) ).closest( 'tr' );
+						var $controls = $( '#' + $.escapeSelector($( this ).attr( 'data-controls' )) ).closest( 'tr' );
 
EOF
@@ -86,3 +86,3 @@
if ( 'checkbox' === $( this ).attr( 'type' ) ) {
var $controls = $( $( this ).attr( 'data-controls' ) ).closest( 'tr' );
var $controls = $( '#' + $.escapeSelector($( this ).attr( 'data-controls' )) ).closest( 'tr' );

Copilot is powered by AI and may make mistakes. Always verify output.

if ( val ) {
$controls.show();
} else {
$controls.hide();
if ( $( this ).is( ':checked' ) ) {
$controls.show();
} else {
$controls.hide();
}

return;
}
if ( 'select' !== $( this ).prop( 'tagName' ).toLowerCase() ) {
return;
}
$( this ).find( 'option' ).each( function() {
var val = $( this ).val();
if ( ! val ) {
return true;
}

var $controls_for_option = $( $( this ).parent().attr( 'data-controls-' + $.escapeSelector( val ) ) ).closest( 'tr' );

if ( $( this ).is( ':selected' ) ) {
$controls_for_option.show();
} else {
$controls_for_option.hide();
}
} );


} ).trigger( 'change' );

Expand Down
8 changes: 5 additions & 3 deletions includes/admin/class.llms.admin.settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ public static function get_settings_tabs() {
$settings[] = include 'settings/class.llms.settings.general.php';
$settings[] = include 'settings/class.llms.settings.courses.php';
$settings[] = include 'settings/class.llms.settings.memberships.php';
$settings[] = include 'settings/class.llms.settings.security.php';
$settings[] = include 'settings/class.llms.settings.accounts.php';
$settings[] = include 'settings/class.llms.settings.checkout.php';
$settings[] = include 'settings/class.llms.settings.engagements.php';
Expand Down Expand Up @@ -709,12 +710,13 @@ class="<?php echo esc_attr( $field['class'] ); ?>"

?>
<tr valign="top" class="single_select_page">
<th><?php echo esc_html( $field['title'] ); ?> <?php echo $tooltip; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Escaped in set_field_descriptions.?></th>
<th><?php echo esc_html( $field['title'] ); ?> <?php echo $tooltip; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Escaped in set_field_descriptions. ?></th>
<td class="forminp">
<?php
<?php
// PHPCS ignore reason: This is a dropdown and the output is escaped in wp_dropdown_pages.
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
echo str_replace( ' id=', " data-placeholder='" . esc_html__( 'Select a page&hellip;', 'lifterlms' ) . "' style='" . esc_attr( $field['css'] ) . "' class='" . esc_attr( $field['class'] ) . "' id=", wp_dropdown_pages( $args ) ); ?>
echo str_replace( ' id=', " data-placeholder='" . esc_html__( 'Select a page&hellip;', 'lifterlms' ) . "' style='" . esc_attr( $field['css'] ) . "' class='" . esc_attr( $field['class'] ) . "' id=", wp_dropdown_pages( $args ) );
?>
<?php echo wp_kses_post( $description ); ?>
</td>
</tr>
Expand Down
150 changes: 150 additions & 0 deletions includes/admin/settings/class.llms.settings.security.php
F438
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
<?php
/**
* Admin Settings Page, Security Tab
*
* @package LifterLMS/Admin/Settings/Classes
*
* @since 1.0.0
* @version 7.5.0
*/

defined( 'ABSPATH' ) || exit;

/**
* Admin Settings Page, Security Tab class
*
* @since [version]
*/
class LLMS_Settings_Security extends LLMS_Settings_Page {

/**
* Settings identifier
*
* @var string
*/
public $id = 'security';

/**
* Get settings array
*
* @since [version]
*
* @return array
*/
public function get_settings() {
$account_settings = array(
array(
'class' => 'top',
'id' => 'course_account_options',
'type' => 'sectionstart',
),
array(
'title' => __( 'Website Security & Spam Prevention', 'lifterlms' ),
'type' => 'title',
'id' => 'security_and_spam_options_title',
),
array(
'autoload' => false,
'default' => '',
'id' => 'lifterlms_captcha',
'desc' => __( 'Choose a captcha service to require at checkout.', 'lifterlms' ),
'title' => __( 'Captcha', 'lifterlms' ),
'type' => 'select',
'options' => array(
'' => __( 'None', 'lifterlms' ),
'recaptcha' => __( 'reCAPTCHA', 'lifterlms' ),
'turnstile' => __( 'Turnstile', 'lifterlms' ),
),
'class' => 'llms-conditional-controller',
'custom_attributes' => array(
'data-controls-recaptcha' => '#lifterlms_recaptcha_site_key,#lifterlms_recaptcha_secret_key',
'data-controls-turnstile' => '#lifterlms_turnstile_site_key,#lifterlms_turnstile_secret_key',
),
),
array(
'autoload' => false,
'default' => '',
'id' => 'lifterlms_recaptcha_site_key',
'desc' => 'Requires reCAPTCHA v3 keys. <a href="https://lifterlms.com/docs/recaptcha" target="_blank">Learn More</a>.',
'title' => __( 'reCAPTCHA v3 Site Key', 'lifterlms' ),
'type' => 'text',
'custom_attributes' => array(
'data-controller' => 'captcha',
'data-value-is' => 'recaptcha',
),
),
array(
'autoload' => false,
'default' => '',
'id' => 'lifterlms_recaptcha_secret_key',
'desc' => '',
'title' => __( 'reCAPTCHA v3 Secret Key', 'lifterlms' ),
'type' => 'text',
'custom_attributes' => array(
'data-controller' => 'captcha',
'data-value-is' => 'recaptcha',
),
),
array(
'autoload' => false,
'default' => '',
'id' => 'lifterlms_turnstile_site_key',
'desc' => 'Requires Cloudflare Turnstile keys. <a href="https://lifterlms.com/docs/turnstile" target="_blank">Learn More</a>.',
'title' => __( 'Turnstile Site Key', 'lifterlms' ),
'type' => 'text',
'custom_attributes' => array(
'data-controller' => 'captcha',
'data-value-is' => 'turnstile',
),
),
array(
'autoload' => false,
'default' => '',
'id' => 'lifterlms_turnstile_secret_key',
'desc' => '',
'title' => __( 'Turnstile Secret Key', 'lifterlms' ),
'type' => 'text',
'custom_attributes' => array(
'data-controller' => 'captcha',
'data-value-is' => 'turnstile',
),
),
array(
'autoload' => false,
'default' => 'no',
'id' => 'lifterlms_spam_protection',
'desc' => __( 'Block IPs from checkout if there are more than 10 failures within 15 minutes.', 'lifterlms' ),
'title' => __( 'Spam Protection', 'lifterlms' ),
'type' => 'checkbox',
),
array(
'id' => 'security_and_spam_options_end',
'type' => 'sectionend',
),
);

/**
* Filters the account settings.
*
* The dynamic portion of this filter `{$this->id}` refers to the unique ID for the settings page.
*
* @since [version]
*
* @param array $account_settings The account page settings.
*/
return apply_filters( "lifterlms_{$this->id}_settings", $account_settings );
}

/**
* Retrieve the page label.
*
* @since [version]
*
* @return string
*/
protected function set_label() {
return __( 'Security', 'lifterlms' );
}
}

return new LLMS_Settings_Security();
6 changes: 6 additions & 0 deletions includes/class-llms-loader.php
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,12 @@ public function includes() {
// Privacy components.
require_once LLMS_PLUGIN_DIR . 'includes/privacy/class-llms-privacy.php';

// Spam stuff.
require_once LLMS_PLUGIN_DIR . 'includes/llms.spam.functions.php';
require_once LLMS_PLUGIN_DIR . 'includes/spam/class-llms-captcha.php';
require_once LLMS_PLUGIN_DIR . 'includes/spam/class-llms-turnstile.php';
require_once LLMS_PLUGIN_DIR . 'includes/spam/class-llms-recaptcha.php';

// Theme support.
require_once LLMS_PLUGIN_DIR . 'includes/theme-support/class-llms-theme-support.php';

Expand Down
Loading
Loading
0