first commit

This commit is contained in:
2026-03-05 13:07:40 +01:00
commit 64ba0721ee
25709 changed files with 4691006 additions and 0 deletions

View File

@@ -0,0 +1,142 @@
<?php
namespace security\wordpress\DynamicTables;
class DataTable {
/**
* @var mixed
*/
public $post;
/**
* @var array|int[]
*/
private $paging;
private $queryBuilder;
/**
* @var array
*/
private $validateRaw;
public function __construct( $POST, QueryBuilder $queryBuilder ) {
$this->post = $POST;
$this->queryBuilder = $queryBuilder;
}
/**
* This class validates all sorting parameters
* @throws Exception
*/
public function validateSorting() {
//first we check if the sortColumn and sortDirection are set
if ( isset( $this->post['sortColumn'] ) && isset( $this->post['sortDirection'] ) ) {
//then we check if the sortColumn is a valid column
if (
! in_array( $this->post['sortColumn']['column'], $this->queryBuilder->getColumns() )
) {
//we also check if it is in the validateRaw array
if ( ! in_array( $this->post['sortColumn']['column'], $this->validateRaw ) ) {
throw new Exception( 'Invalid sort column' );
}
}
//then we check if the sortDirection is a valid direction
if ( ! in_array( $this->post['sortDirection'], array( 'asc', 'desc' ) ) ) {
throw new Exception( 'Invalid sort direction' );
}
$this->queryBuilder->orderBy( $this->post['sortColumn']['column'], $this->post['sortDirection'] );
}
return $this;
}
private function getColumns() {
return $this->queryBuilder->getColumns();
}
/**
* @throws Exception
*/
public function setSelect( array $array ) {
//we loop through the array and check if the column is valid
// and if the column starts with raw: we exclude it from the check
$rawColumns = [];
foreach ( $array as $column ) {
if ( strpos( $column, 'raw:' ) === false ) {
if ( ! in_array( $column, $this->getColumns() ) ) {
throw new Exception( 'Invalid column' );
}
} else {
//we remove the column from the array and add it to the rawColumns array
unset( $array[ array_search( $column, $array ) ] );
$rawColumns[] = str_replace( 'raw:', '', $column );
}
}
//we get the first array element and add it to the query
$this->queryBuilder->select( $array[0] );
//we loop through the rest of the array and add it to the query
for ( $i = 1; $i < count( $array ); $i ++ ) {
$this->queryBuilder->addSelect( $array[ $i ] );
}
//we add the raw columns to the query
foreach ( $rawColumns as $rawColumn ) {
$this->queryBuilder->addSelect( $rawColumn );
//we extract the column name from the raw column
$columnName = explode( ' as ', $rawColumn )[1];
//we add the column name to the columns array
$this->validateRaw[] = $columnName;
}
return $this;
}
public function getResults() {
return $this->queryBuilder->paginate( ...$this->paging );
}
/**
* @throws Exception
*/
public function validatePagination() {
$perPage = 10;
$page = 1;
//we check if the paging parameters are set
if ( isset( $this->post['page'] ) ) {
//we check if the page is a number
if ( ! is_numeric( $this->post['page'] ) ) {
throw new Exception( 'Invalid page number' );
}
$page = $this->post['page'];
}
if ( isset( $this->post['currentRowsPerPage'] ) ) {
//we check if the perPage is a number
if ( ! is_numeric( $this->post['currentRowsPerPage'] ) ) {
throw new Exception( 'Invalid per page number' );
}
$perPage = $this->post['currentRowsPerPage'];
}
$this->paging = [ $perPage, $page ];
return $this;
}
public function validateSearch() {
if ( isset( $this->post['search'] ) && count( $this->post['searchColumns'] ) > 0 ) {
//we check if the searchColumns are valid
foreach ( $this->post['searchColumns'] as $column ) {
if ( ! in_array( $column, $this->getColumns() ) ) {
throw new Exception( 'Invalid search column' );
}
}
//we add the search to the query
foreach ( $this->post['searchColumns'] as $column ) {
$this->queryBuilder->where( $column, 'like', '%' . $this->post['search'] . '%' );
}
}
return $this;
}
}

View File

@@ -0,0 +1,213 @@
<?php
namespace security\wordpress\DynamicTables;
class QueryBuilder {
private $table;
private $columns = '*';
private $orderBy = '';
private $limit = '';
private $offset = '';
private $query = '';
private $where;
private $results = array();
public function __construct( $table ) {
$this->table = $table;
}
public function select( $columns ) {
$this->columns = $columns;
return $this;
}
public function addSelect( $columns ) {
$this->columns .= ", $columns";
return $this;
}
public function orderBy( $column, $direction = 'ASC' ) {
$column = str_replace( "'", "", $column );
$this->orderBy = "ORDER BY $column $direction";
return $this;
}
public function limit( $limit, $offset = 0 ) {
$this->limit = "LIMIT $limit";
$this->offset = "OFFSET $offset";
return $this;
}
public function getQuery( $skipLimit = false ) {
$query = "SELECT $this->columns FROM $this->table";
//we loop through the $this->>where array and add it to the query
if ( ! empty( $this->where ) ) {
$query .= " WHERE ";
foreach ( $this->where as $where ) {
$query .= "$where OR ";
}
//we remove the last AND
$query = substr( $query, 0, - 4 );
}
if ( ! empty( $this->orderBy ) ) {
$query .= " $this->orderBy";
}
if ( ! $skipLimit ) {
if ( ! empty( $this->limit ) ) {
$query .= " $this->limit";
}
if ( ! empty( $this->offset ) ) {
$query .= " $this->offset";
}
}
$this->query = $query;
//we validate and cleanup the query
$this->query = str_replace( ';', '', $this->query );
//we look for a double space and replace it with a single space
$this->query = str_replace( ' ', ' ', $this->query );
//we look for a double , and replace it with a single ,
$this->query = str_replace( ', ,', ',', $this->query );
return $this->query;
}
public function get() {
$this->results = $this->execute( $this->getQuery() );
return $this->results;
}
public function toSql() {
$this->getQuery();
return $this->query;
}
public function count() {
$query = $this->getQuery( true );
$countQuery = "SELECT COUNT(*) as count FROM ($query) as subquery";
return $this->execute($countQuery)[0]->count;
}
private function execute( $query ) {
global $wpdb;
return $wpdb->get_results( $query );
}
public function insert( $data ) {
$columns = array();
$values = array();
foreach ( $data as $column => $value ) {
$columns[] = $column;
$values[] = "'" . esc_sql( $value ) . "'";
}
$columns = implode( ', ', $columns );
$values = implode( ', ', $values );
$query = "INSERT INTO $this->table ($columns) VALUES ($values)";
$this->execute( $query );
}
public function update( $data ) {
$set = array();
foreach ( $data as $column => $value ) {
$set[] = "$column = '" . esc_sql( $value ) . "'";
}
$set = implode( ', ', $set );
$query = "UPDATE $this->table SET $set";
$this->execute( $query );
}
public function where( $column, $operator, $value ) {
//we add it to an array so we can build the query later
$this->where[] = "$column $operator '" . esc_sql( $value ) . "'";
return $this;
}
public function whereIn( $column, $values ) {
$column = str_replace( "'", "", $column );
$values = array_map( 'esc_sql', $values );
$values = "'" . implode( "', '", $values ) . "'";
$query = "WHERE $column IN ($values)";
return $query;
}
public function whereNotIn( $column, $values ) {
$column = str_replace( "'", "", $column );
$values = array_map( 'esc_sql', $values );
$values = "'" . implode( "', '", $values ) . "'";
$query = "WHERE $column NOT IN ($values)";
return $query;
}
public function first() {
$this->limit( 1 );
$result = $this->execute( $this->getQuery() );
return isset( $result[0] ) ? $result[0] : null;
}
public function paginate( $rows = 0, $page = 0 ) {
if ( $page > 0 ) {
$offset = ( $page - 1 ) * $rows;
} else {
$offset = 0;
}
$this->limit( $rows, $offset );
$results = $this->get();
$total = $this->count();
$lastPage = ceil( $total / $rows );
return [
'data' => $results,
'pagination' => [
'totalRows' => $total,
'perPage' => $rows,
'offset' => $offset,
'currentPage' => $page,
'lastPage' => $lastPage,
],
//if the debug option in WordPress is set to true, the query will be returned
'query' => $this->toSql(), //- uncomment this line if you want to see the query
];
}
/**
* Get all columns from the table
*
* @return array
*/
public function getColumns(): array {
//we return all columns from the table
$query = "SHOW COLUMNS FROM $this->table";
$result = $this->execute( $query );
return array_column($result, 'Field');
}
}

View File

@@ -0,0 +1,87 @@
<?php defined( 'ABSPATH' ) or die();
/**
* @param $notices
* @return mixed
* Notice function
*/
function rsssl_code_execution_errors_notice( $notices ) {
$notices['code-execution-uploads'] = array(
'callback' => 'rsssl_code_execution_allowed',
'score' => 5,
'output' => array(
'file-not-found' => array(
'msg' => __("Could not find code execution test file.", "really-simple-ssl"),
'icon' => 'open',
'dismissible' => true,
),
'uploads-folder-not-writable' => array(
'msg' => __("Uploads folder not writable.", "really-simple-ssl"),
'icon' => 'open',
'dismissible' => true,
),
'could-not-create-test-file' => array(
'msg' => __("Could not copy code execution test file.", "really-simple-ssl"),
'icon' => 'open',
'dismissible' => true,
),
),
);
if ( rsssl_get_server() === 'nginx') {
$notices['code-execution-uploads-nginx'] = array(
'callback' => 'rsssl_code_execution_allowed',
'score' => 5,
'output' => array(
'true' => array(
'msg' => __("The code to block code execution in the uploads folder cannot be added automatically on nginx. Add the following code to your nginx.conf file:", "really-simple-ssl")
. "<br>" . rsssl_get_nginx_code_code_execution_uploads(),
'icon' => 'open',
'dismissible' => true,
),
),
);
}
return $notices;
}
add_filter('rsssl_notices', 'rsssl_code_execution_errors_notice');
/**
* Block code execution
* @param array $rules
*
* @return []
*
*/
function rsssl_disable_code_execution_rules($rules)
{
if ( !rsssl_get_option('block_code_execution_uploads')) {
return $rules;
}
if ( RSSSL()->server->apache_version_min_24() ) {
$rule = "\n" ."<Files *.php>";
$rule .= "\n" . "Require all denied";
$rule .= "\n" . "</Files>";
} else {
$rule = "\n" ."<Files *.php>";
$rule .= "\n" . "deny from all";
$rule .= "\n" . "</Files>";
}
$rules[] = ['rules' => $rule, 'identifier' => 'deny from all'];
return $rules;
}
add_filter('rsssl_htaccess_security_rules_uploads', 'rsssl_disable_code_execution_rules');
function rsssl_get_nginx_code_code_execution_uploads() {
$code = '<code>location ~* /uploads/.*\.php$ {' . "<br>";
$code .= '&nbsp;&nbsp;&nbsp;&nbsp;return 503;' . "<br>";
$code .= '}</code>' . "<br>";
return $code;
}

View File

@@ -0,0 +1,23 @@
<?php
defined( 'ABSPATH' ) or die( "you do not have access to this page!" );
/**
* Disable XMLRPC when this integration is activated
*/
add_filter('xmlrpc_enabled', '__return_false');
/**
* Remove html link
*/
remove_action( 'wp_head', 'rsd_link' );
/**
* stop all requests to xmlrpc.php for RSD per XML-RPC:
*/
if ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST )
exit;

View File

@@ -0,0 +1,43 @@
<?php
defined( 'ABSPATH' ) or die();
/**
* Add javascript to make first and last name fields required
*/
function rsssl_disable_registration_js() {
if ( !isset($_SERVER['REQUEST_URI']) || (strpos($_SERVER['REQUEST_URI'], 'user-new.php')===false && strpos($_SERVER['REQUEST_URI'], 'profile.php')===false) ) {
return;
}
?>
<script>
window.addEventListener('load', () => {
document.getElementById('first_name').closest('tr').classList.add("form-required");
document.getElementById('last_name').closest('tr').classList.add("form-required");
});
</script>
<?php
}
add_action( 'admin_print_footer_scripts', 'rsssl_disable_registration_js' );
/**
* Add javascript to make first and last name fields required
*/
function rsssl_strip_userlogin() {
if ( !isset($_SERVER['REQUEST_URI']) || strpos($_SERVER['REQUEST_URI'], 'profile.php')===false ) {
return;
}
?>
<script>
let rsssl_user_login = document.querySelector('input[name=user_login]');
let rsssl_display_name = document.querySelector('select[name=display_name]');
if ( rsssl_display_name.options.length>1) {
for (let i = rsssl_display_name.options.length-1; i >= 0; i--) {
if ( rsssl_user_login.value.toLowerCase() === rsssl_display_name.options[i].value.toLowerCase() ) {
rsssl_display_name.removeChild(rsssl_display_name.options[i])
}
}
}
</script>
<?php
}
add_action( 'admin_print_footer_scripts', 'rsssl_strip_userlogin' );

View File

@@ -0,0 +1,45 @@
<?php
defined( 'ABSPATH' ) or die();
/**
* @return void
*
* Disable file editing
*/
function rsssl_disable_file_editing() {
if ( ! defined('DISALLOW_FILE_EDIT' ) ) {
define('DISALLOW_FILE_EDIT', true );
}
}
add_action("init", "rsssl_disable_file_editing");
/**
* Username 'admin' changed notice
* @return array
*/
function rsssl_disable_file_editing_notice( $notices ) {
$notices['disallow_file_edit_false'] = array(
'condition' => ['rsssl_file_editing_defined_but_disabled'],
'callback' => '_true_',
'score' => 5,
'output' => array(
'true' => array(
'msg' => __("The DISALLOW_FILE_EDIT constant is defined and set to false. You can remove it from your wp-config.php.", "really-simple-ssl"),
'icon' => 'open',
'dismissible' => true,
'url' => 'https://really-simple-ssl.com/disallow_file_edit-defined-set-to-false'
),
),
);
return $notices;
}
add_filter('rsssl_notices', 'rsssl_disable_file_editing_notice');
/**
* Check if the constant is defined, AND set to false. In that case the plugin cannot override it anymore
* @return bool
*/
function rsssl_file_editing_defined_but_disabled(){
return defined( 'DISALLOW_FILE_EDIT' ) && ! DISALLOW_FILE_EDIT;
}

View File

@@ -0,0 +1,41 @@
<?php
defined( 'ABSPATH' ) or die();
/**
* @return void
* Remove WordPress version info from page source
*/
function rsssl_remove_wp_version() {
// remove <meta name="generator" content="WordPress VERSION" />
add_filter( 'the_generator', function() { return '';} );
// remove WP ?ver=5.X.X from css/js
add_filter( 'style_loader_src', 'rsssl_remove_css_js_version', 9999 );
add_filter( 'script_loader_src', 'rsssl_remove_css_js_version', 9999 );
remove_action('wp_head', 'wp_generator'); // remove wordpress version
remove_action('wp_head', 'index_rel_link'); // remove link to index page
remove_action('wp_head', 'wlwmanifest_link'); // remove wlwmanifest.xml (needed to support windows live writer)
remove_action('wp_head', 'wp_shortlink_wp_head', 10 ); // Remove shortlink
}
add_action('init', 'rsssl_remove_wp_version');
function rsssl_replace_wp_version($html){
$wp_version = get_bloginfo( 'version' );
$new_version = hash('md5', get_bloginfo( 'version' ) );
return str_replace('?ver='.$wp_version, '?ver='.$new_version, $html);
}
add_filter('rsssl_fixer_output', 'rsssl_replace_wp_version');
/**
* @param $src
* @return mixed|string
* Remove WordPress version from css and js strings
*/
function rsssl_remove_css_js_version( $src ) {
if ( strpos( $src, '?ver=' ) && strpos( $src, 'wp-includes') ) {
$wp_version = get_bloginfo( 'version' );
$new_version = hash('md5', get_bloginfo( 'version' ) );
$src = str_replace('?ver='.$wp_version, '?ver='.$new_version, $src);
}
return $src;
}

View File

@@ -0,0 +1 @@
<?php // You don't belong here. ?>

View File

@@ -0,0 +1,45 @@
<?php
defined('ABSPATH') or die();
/**
* Override default login error message
* @return string|void
**/
function rsssl_no_wp_login_errors()
{
return __("Invalid login details.", "really-simple-ssl");
}
add_filter( 'login_errors', 'rsssl_no_wp_login_errors' );
/**
* Hide feedback entirely on password reset (no filter available).
*
* @return void
*
*/
function rsssl_hide_pw_reset_error() {
?>
<style>
.login-action-lostpassword #login_error{
display: none;
}
</style>
<?php
}
add_action( 'login_enqueue_scripts', 'rsssl_hide_pw_reset_error' );
/**
*
* Clear username when username is valid but password is incorrect
*
* @return void
*/
function rsssl_clear_username_on_correct_username() {
?>
<script>
if ( document.getElementById('login_error') ) {
document.getElementById('user_login').value = '';
}
</script>
<?php
}
add_action( 'login_footer', 'rsssl_clear_username_on_correct_username' );

View File

@@ -0,0 +1,174 @@
<?php
defined('ABSPATH') or die();
/**
* Username 'admin' changed notice
* @return array
*/
function rsssl_admin_username_changed( $notices ) {
$notices['username_admin_changed'] = array(
'condition' => ['rsssl_username_admin_changed'],
'callback' => '_true_',
'score' => 5,
'output' => array(
'true' => array(
'msg' => sprintf(__("Username 'admin' has been changed to %s", "really-simple-ssl"),esc_html(get_site_transient('rsssl_username_admin_changed')) ),
'icon' => 'open',
'dismissible' => true,
),
),
);
return $notices;
}
add_filter('rsssl_notices', 'rsssl_admin_username_changed');
/**
* Add admin as not allowed username
* @param array $illegal_user_logins
*
* @return array
*/
function rsssl_prevent_admin_user_add(array $illegal_user_logins){
$illegal_user_logins[] = 'admin';
$illegal_user_logins[] = 'administrator';
return $illegal_user_logins;
}
add_filter( 'illegal_user_logins', 'rsssl_prevent_admin_user_add' );
/**
* Rename admin user
* @return bool
*/
function rsssl_rename_admin_user() {
if ( !rsssl_user_can_manage() ) {
return false;
}
//to be able to update the admin user email, we need to disable this filter temporarily
remove_filter( 'illegal_user_logins', 'rsssl_prevent_admin_user_add' );
// Get user data for login admin
$admin_user = get_user_by('login','admin');
if ( $admin_user ) {
// Get the new user login
$new_user_login = trim(sanitize_user(rsssl_get_option('new_admin_user_login')));
if ( rsssl_new_username_valid() ) {
$admin_user_id = $admin_user->data->ID;
$admin_userdata = get_userdata( $admin_user_id );
$admin_email = $admin_userdata->data->user_email;
global $wpdb;
//get current user hash
$user_hash = $wpdb->get_var($wpdb->prepare("select user_pass from {$wpdb->base_prefix}users where ID = %s", $admin_user_id) );
//create temp email address
$domain = site_url();
$parse = parse_url( $domain );
$host = $parse['host'] ?? 'example.com';
$email = "$new_user_login@$host";
// Do not send an e-mail with this temporary e-mail address
add_filter('send_email_change_email', '__return_false');
// update e-mail for existing user. Cannot have two accounts connected to the same e-mail address
$success = wp_update_user( array(
'ID' => $admin_user_id,
'user_email' => $email,
) );
if ( ! $success ) {
return false;
}
// Populate the new user data. Use current 'admin' userdata wherever available
$new_userdata = array(
'user_pass' => rsssl_generate_random_string( 12 ), //temp, overwrite with actual hash later.
//(string) The plain-text user password.
'user_login' => $new_user_login,
//(string) The user's login username.
'user_nicename' => isset( $admin_user->data->user_nicename ) ? $admin_user->data->user_nicename : '',
//(string) The URL-friendly user name.
'user_url' => isset( $admin_user->data->user_url ) ? $admin_user->data->user_url : '',
//(string) The user URL.
'user_email' => isset( $admin_email ) ? $admin_email : '',
//(string) The user email address.
'display_name' => isset( $admin_user->data->display_name ) ? $admin_user->data->display_name : '',
//(string) The user's display name. Default is the user's username.
'nickname' => isset( $admin_user->data->nickname ) ? $admin_user->data->nickname : '',
//(string) The user's nickname. Default is the user's username.
'first_name' => isset( $admin_user->data->user_firstname ) ? $admin_user->data->user_firstname : '',
//(string) The user's first name. For new users, will be used to build the first part of the user's display name if $display_name is not specified.
'last_name' => isset( $admin_user->data->user_lastname ) ? $admin_user->data->user_lastname : '',
//(string) The user's last name. For new users, will be used to build the second part of the user's display name if $display_name is not specified.
'description' => isset( $admin_user->data->description ) ? $admin_user->data->description : '',
//(string) The user's biographical description.
'rich_editing' => isset( $admin_user->data->rich_editing ) ? $admin_user->data->rich_editing : '',
//(string|bool) Whether to enable the rich-editor for the user. False if not empty.
'syntax_highlighting' => isset( $admin_user->data->syntax_highlighting ) ? $admin_user->data->syntax_highlighting : '',
//(string|bool) Whether to enable the rich code editor for the user. False if not empty.
'comment_shortcuts' => isset( $admin_user->data->comment_shortcuts ) ? $admin_user->data->comment_shortcuts : '',
//(string|bool) Whether to enable comment moderation keyboard shortcuts for the user. Default false.
'admin_color' => isset( $admin_user->data->admin_color ) ? $admin_user->data->admin_color : '',
//(string) Admin color scheme for the user. Default 'fresh'.
'use_ssl' => isset( $admin_user->data->use_ssl ) ? $admin_user->data->use_ssl : '',
//(bool) Whether the user should always access the admin over https. Default false.
'user_registered' => isset( $admin_user->data->user_registered ) ? $admin_user->data->user_registered : '',
//(string) Date the user registered. Format is 'Y-m-d H:i:s'.
'show_admin_bar_front' => isset( $admin_user->data->show_admin_bar_front ) ? $admin_user->data->show_admin_bar_front : '',
//(string|bool) Whether to display the Admin Bar for the user on the site's front end. Default true.
'role' => isset( $admin_user->roles[0] ) ? $admin_user->roles[0] : '',
//(string) User's role.
'locale' => isset( $admin_user->data->locale ) ? $admin_user->data->locale : '',
//(string) User's locale. Default empty.
);
// Create new admin user
$new_user_id = wp_insert_user( $new_userdata );
if ( ! $new_user_id || is_wp_error($new_user_id) ) {
return false;
}
//store original user hash in this user.
$wpdb->update(
$wpdb->base_prefix.'users',
['user_pass' => $user_hash ],
['ID' => $new_user_id]
);
require_once( ABSPATH . 'wp-admin/includes/user.php' );
wp_delete_user( $admin_user_id, $new_user_id );
// On multisite we have to update the $wpdb->prefix . sitemeta -> meta_key -> site_admins -> meta_value to the new username
if ( is_multisite() ) {
global $wpdb;
$site_admins = $wpdb->get_var( "SELECT meta_value FROM {$wpdb->base_prefix}sitemeta WHERE meta_key = 'site_admins'" );
if ( is_serialized( $site_admins ) ) {
$unserialized = unserialize( $site_admins );
foreach ( $unserialized as $index => $site_admin ) {
if ( $site_admin === 'admin' ) {
$unserialized[ $index ] = $new_user_login;
}
}
$site_admins = serialize( $unserialized );
}
$wpdb->query( $wpdb->prepare( "UPDATE {$wpdb->base_prefix}sitemeta SET meta_value = %s WHERE meta_key = 'site_admins'", $site_admins ) );
}
set_site_transient( 'rsssl_username_admin_changed', $new_user_login, DAY_IN_SECONDS );
}
return true;
}
return true;
}
add_action('rsssl_after_saved_fields','rsssl_rename_admin_user', 30);
/**
* @return bool
*
* Notice condition
*/
function rsssl_username_admin_changed() {
if ( get_site_transient('rsssl_username_admin_changed') ) {
return true;
}
return false;
}

View File

@@ -0,0 +1,54 @@
<?php
defined('ABSPATH') or die();
/**
* @param $response
* @param $handler
* @param WP_REST_Request $request
* @return mixed|WP_Error
*
* Hook into REST API requests
*/
function authorize_rest_api_requests( $response, $handler, WP_REST_Request $request ) {
// allowed routes, whitelist option?
// $routes = array(
// '/wp/v2/csp etc',
// );
// Check if authorization header is set
if ( ! $request->get_header( 'authorization' ) ) {
return new WP_Error( 'authorization', 'Unauthorized access.', array( 'status' => 401 ) );
}
// if ( rsssl_get_networkwide_option('rsssl_restrict_rest_api') === 'restrict-roles' ) {
// Check for certain role and allowed route
if ( ! in_array( 'administrator', wp_get_current_user()->roles ) ) {
return new WP_Error( 'forbidden', 'Access forbidden.', array( 'status' => 403 ) );
}
// }
// if ( rsssl_get_networkwide_option('rsssl_restrict_rest_api') === 'logged-in-users' ) {
if ( ! is_user_logged_in() ) {
return new WP_Error( 'forbidden', 'Access forbidden to non-logged in users.', array( 'status' => 403 ) );
}
// }
// if ( rsssl_get_networkwide_option('rsssl_restrict_rest_api') === 'application-passwords' ) {
if ( ! is_user_logged_in() ) {
return new WP_Error( 'forbidden', 'Access forbidden to non-logged in users.', array( 'status' => 403 ) );
}
// }
return $response;
}
/**
* @return void
* Disable REST API
*/
function rsssl_disable_rest_api() {
add_filter('json_enabled', '__return_false');
add_filter('json_jsonp_enabled', '__return_false');
}
add_filter( 'rest_request_before_callbacks', 'authorize_rest_api_requests', 10, 3 );

View File

@@ -0,0 +1,54 @@
<?php
defined('ABSPATH') or die();
/**
* Prevent User Enumeration
* @return void
*/
function rsssl_check_user_enumeration() {
if ( ! is_user_logged_in() && isset( $_REQUEST['author'] ) ) {
if ( preg_match( '/\\d/', $_REQUEST['author'] ) > 0 ) {
wp_die( sprintf(__( 'forbidden - number in author name not allowed = %s', 'really-simple-ssl' ), esc_html( $_REQUEST['author'] ) ) );
}
}
}
add_action('init', 'rsssl_check_user_enumeration');
/**
* @return bool
* Remove author from Yoast sitemap
*/
function rsssl_remove_author_from_yoast_sitemap( $users ) {
return false;
}
add_filter('wpseo_sitemap_exclude_author', 'rsssl_remove_author_from_yoast_sitemap', 10, 1 );
/**
* Prevent WP JSON API User Enumeration
* Do not disable in when logged in, preventing issues in the Gutenberg Editor
*/
if ( !is_user_logged_in() || !current_user_can('edit_posts') ) {
add_filter( 'rest_endpoints', function ( $endpoints ) {
if ( isset( $endpoints['/wp/v2/users'] ) ) {
unset( $endpoints['/wp/v2/users'] );
}
if ( isset( $endpoints['/wp/v2/users/(?P[\d]+)'] ) ) {
unset( $endpoints['/wp/v2/users/(?P[\d]+)'] );
}
return $endpoints;
} );
}
//prevent xml site map user enumeration
add_filter(
'wp_sitemaps_add_provider',
function( $provider, $name ) {
if ( 'users' === $name ) {
return false;
}
return $provider;
},
10,
2
);

View File

@@ -0,0 +1,11 @@
<?php
defined('ABSPATH') or die();
/**
* Action to disable user registration
*
* @return bool
*/
function rsssl_users_can_register($value, $option) {
return false;
}
add_filter( "option_users_can_register", 'rsssl_users_can_register', 999, 2 );

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,116 @@
<?php
namespace security\wordpress\vulnerabilities;
defined('ABSPATH') or die();
class FileStorage
{
private $hash;
/**
* FileStorage constructor.
*/
public function __construct()
{
//Fetching the key from the database
$this->generateHashKey();
}
public Static function StoreFile($file, $data)
{
$storage = new FileStorage();
$storage->set($data, $file);
}
public Static function GetFile($file)
{
$storage = new FileStorage();
return $storage->get($file);
}
/** Get the data from the file
* @param $file
* @return bool|mixed
*/
public function get($file)
{
if (file_exists($file)) {
$data = file_get_contents($file);
$data = $this->Decode64WithHash($data);
return json_decode($data);
}
return false;
}
/** Save the data to the file
* @param $data
* @param $file
*/
public function set($data, $file)
{
$data = $this->Encode64WithHash(json_encode($data));
file_put_contents($file, $data);
}
/** encode the data with a hash
* @param $data
* @return string
*/
private function Encode64WithHash($data): string
{
//we create a simple encoding, using the hashkey as a salt
$data = base64_encode($data);
return base64_encode($data . $this->hash);
}
/** decode the data with a hash
* @param $data
* @return string
*/
private function Decode64WithHash($data): string
{
//we create a simple decoding, using the hashkey as a salt
$data = base64_decode($data);
$data = substr($data, 0, -strlen($this->hash));
return base64_decode($data);
}
/** Generate a hashkey and store it in the database
* @return void
*/
private function generateHashKey(): void
{
if (get_option('rsssl_hashkey') && get_option('rsssl_hashkey') !== "") {
$this->hash = get_option('rsssl_hashkey');
} else {
$this->hash = md5(uniqid(rand(), true));
update_option('rsssl_hashkey', $this->hash, false);
}
}
public static function GetDate(string $file)
{
if (file_exists($file)) {
return filemtime($file);
}
return false;
}
public static function DeleteAll()
{
//we get the upload folder
$upload_dir = wp_upload_dir();
//we get the really-simple-ssl folder
$rsssl_dir = $upload_dir['basedir'] . '/really-simple-ssl';
//then we delete the following files from that folder: manifest.json, components.json and core.json
$files = array('manifest.json', 'components.json', 'core.json');
foreach ($files as $file) {
//we delete the file
$file = $rsssl_dir . '/' . $file;
if (file_exists($file)) {
unlink($file);
}
}
}
}