Skip to content

Conversation

@mrrobot47
Copy link
Member

@mrrobot47 mrrobot47 commented Jan 8, 2026

Summary

Adds support for creating _wildcard.site_url htpasswd and whitelist files for WordPress multisite subdomain sites, enabling HTTP authentication and IP whitelisting to work correctly on subdomains.

Changes

New Features

  • Create _wildcard.site_url htpasswd/whitelist files for subdomain multisites (app_sub_type === 'subdom')
  • Create htpasswd/whitelist files for all alias_domains
  • Convert *.domain alias format to _wildcard.domain filename

Depends on: EasyEngine/dockerfiles#298

- Modified generate_site_auth_files() to create _wildcard.site_url file for
  subdomain multisites (app_sub_type === 'subdom')
- Handle alias_domains: create htpasswd files for each alias domain
- Convert *.domain format aliases to _wildcard.domain
- For subdomain multisites, also create wildcard versions of alias domains
- Updated all callers to pass site_data parameter
- Fetch site data from DB when regenerating auth for all sites globally

Signed-off-by: Riddhesh Sanghvi <riddhesh237@gmail.com>
Add array_unique() to deduplicate domains array before processing,
preventing duplicate htpasswd file creation when alias domains overlap
with wildcard domains (e.g., *.example.com alias on a subdomain multisite)

Signed-off-by: Riddhesh Sanghvi <riddhesh237@gmail.com>
- Modified generate_site_whitelist() to create whitelist files for
  _wildcard.site_url on subdomain multisites
- Handle alias_domains: create whitelist files for each alias domain
- Convert *.domain format aliases to _wildcard.domain
- For subdomain multisites, also create wildcard versions of alias domains
- Updated all callers to pass site_data parameter
- Fetch site data from DB when regenerating whitelist for all sites globally

Signed-off-by: Riddhesh Sanghvi <riddhesh237@gmail.com>
When alias_domains contains *.site_url (e.g., *.example.com for site
example.com), skip it ONLY if the site is a subdomain multisite since
_wildcard.site_url is already added in that case. For non-multisite
sites with *.site_url alias, create the _wildcard.site_url file.

Signed-off-by: Riddhesh Sanghvi <riddhesh237@gmail.com>
When no auths or whitelists exist for a site, explicitly remove all
related htpasswd/whitelist files (including wildcards and aliases) and
return early. This makes the cleanup behavior more explicit rather than
silently iterating over an empty array.

Signed-off-by: Riddhesh Sanghvi <riddhesh237@gmail.com>
Always remove _wildcard.site_url htpasswd and whitelist files at the
start of regeneration. This ensures orphan wildcard files are cleaned
up when a site changes from subdomain multisite to regular site type.

Signed-off-by: Riddhesh Sanghvi <riddhesh237@gmail.com>
Copilot AI review requested due to automatic review settings January 8, 2026 11:46
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds support for wildcard htpasswd and IP whitelist files for WordPress multisite subdomain installations and alias domains. The main purpose is to enable HTTP authentication and IP whitelisting to work correctly on subdomains of multisite installations (e.g., site1.example.com, site2.example.com) by creating _wildcard.example.com configuration files.

Key changes:

  • Modified generate_site_auth_files and generate_site_whitelist methods to accept optional $site_data parameter
  • Added logic to create wildcard (_wildcard.domain) htpasswd/whitelist files for subdomain multisites
  • Added support for processing alias domains, including converting *.domain format to _wildcard.domain filenames
  • Updated all call sites to pass the $site_data parameter

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +307 to +345
// Collect all domains to generate htpasswd files for
$domains = [ $site_url ];

// For subdomain multisites, add wildcard file
if ( $site_data && ! empty( $site_data->app_sub_type ) && 'subdom' === $site_data->app_sub_type ) {
$domains[] = '_wildcard.' . $site_url;
}

// Add alias domains (excluding main site_url)
if ( $site_data && ! empty( $site_data->alias_domains ) ) {
$alias_list = array_map( 'trim', explode( ',', $site_data->alias_domains ) );
foreach ( $alias_list as $alias ) {
if ( empty( $alias ) || $alias === $site_url ) {
continue;
}
// Skip *.site_url as it transforms to _wildcard.site_url (already added for subdomain multisite)
if ( ! empty( $site_data->app_sub_type ) && 'subdom' === $site_data->app_sub_type && '*.' . $site_url === $alias ) {
continue;
}
// Replace *.domain with _wildcard.domain
if ( 0 === strpos( $alias, '*.' ) ) {
$domains[] = '_wildcard.' . substr( $alias, 2 );
} else {
$domains[] = $alias;
// For subdomain multisites, also add wildcard for non-wildcard alias domains
if ( ! empty( $site_data->app_sub_type ) && 'subdom' === $site_data->app_sub_type ) {
$domains[] = '_wildcard.' . $alias;
}
}
}
}

$auths = array_merge(
Auth::get_global_auths(),
Auth::where( 'site_url', $site_url )
);

foreach ( $auths as $key => $auth ) {
$flags = 'b';
// Remove duplicates (e.g., *.example.com alias + subdomain multisite both create _wildcard.example.com)
$domains = array_unique( $domains );
Copy link

Copilot AI Jan 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The domain collection logic in this method is duplicated in generate_site_whitelist (lines 412-445). Consider extracting this logic into a shared private method like collect_site_domains($site_url, $site_data) that returns the array of domains. This would reduce code duplication and make future maintenance easier.

Copilot uses AI. Check for mistakes.
if ( $key === 0 ) {
$flags = 'bc';
}
EE::exec( sprintf( 'docker exec %s htpasswd -%s /etc/nginx/htpasswd/%s %s %s', EE_PROXY_TYPE, $flags, $domain, $auth->username, $auth->password ) );
Copy link

Copilot AI Jan 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

EE::exec builds a shell command string for docker exec htpasswd by directly interpolating untrusted username, password, and domain values without any escaping or argument separation. A user who can control --user/--pass (or stored auth entries) can include shell metacharacters in these fields so that, when this command is executed, arbitrary additional commands run on the host or in the proxy container. Replace this string-based command construction with a safe-by-default execution API that passes each argument separately or properly escapes every dynamic value before invoking the shell.

Suggested change
EE::exec( sprintf( 'docker exec %s htpasswd -%s /etc/nginx/htpasswd/%s %s %s', EE_PROXY_TYPE, $flags, $domain, $auth->username, $auth->password ) );
$container = escapeshellarg( EE_PROXY_TYPE );
$escaped_domain = escapeshellarg( $domain );
$escaped_username = escapeshellarg( $auth->username );
$escaped_password = escapeshellarg( $auth->password );
EE::exec(
sprintf(
'docker exec %s htpasswd -%s /etc/nginx/htpasswd/%s %s %s',
$container,
$flags,
$escaped_domain,
$escaped_username,
$escaped_password
)
);

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant