Compare commits

...

2 Commits

Author SHA1 Message Date
Andy Miller
9d9247a32f fix false positives in Security with on_events
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-12-03 14:17:17 -07:00
Andy Miller
94d85cd873 add support for environment in grav scheduler
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-12-03 10:41:29 -07:00
4 changed files with 33 additions and 6 deletions

View File

@@ -122,4 +122,13 @@ form:
default: '* 3 * * *'
validate:
required: true
.schedule_environment:
type: select
label: PLUGIN_ADMIN.BACKUPS_PROFILE_ENVIRONMENT
help: PLUGIN_ADMIN.BACKUPS_PROFILE_ENVIRONMENT_HELP
default: ''
options:
'': 'Default (cli)'
localhost: 'Localhost'
cli: 'CLI'

View File

@@ -10,6 +10,7 @@ profiles:
root: '/'
schedule: false
schedule_at: '0 3 * * *'
schedule_environment: ''
exclude_paths: "/backup\r\n/cache\r\n/images\r\n/logs\r\n/tmp"
exclude_files: ".DS_Store\r\n.git\r\n.svn\r\n.hg\r\n.idea\r\n.vscode\r\nnode_modules"

View File

@@ -89,8 +89,9 @@ class Backups
$at = $profile['schedule_at'];
$name = $inflector::hyphenize($profile['name']);
$logs = 'logs/backup-' . $name . '.out';
$environment = $profile['schedule_environment'] ?? null;
/** @var Job $job */
$job = $scheduler->addFunction('Grav\Common\Backup\Backups::backup', [$id], $name);
$job = $scheduler->addFunction('Grav\Common\Backup\Backups::backup', [$id, null, $environment], $name);
$job->at($at);
$job->output($logs);
$job->backlink('/tools/backups');
@@ -192,12 +193,19 @@ class Backups
*
* @param int $id
* @param callable|null $status
* @param string|null $environment Optional environment to load config from
* @return string|null
*/
public static function backup($id = 0, ?callable $status = null)
public static function backup($id = 0, ?callable $status = null, ?string $environment = null)
{
$grav = Grav::instance();
// If environment is specified and different from current, reload config
if ($environment && $environment !== $grav['config']->get('setup.environment')) {
$grav->setup($environment);
$grav['config']->reload();
}
$profiles = static::getBackupProfiles();
/** @var UniformResourceLocator $locator */
$locator = $grav['locator'];

View File

@@ -224,8 +224,9 @@ class Security
// Set the patterns we'll test against
$patterns = [
// Match any attribute starting with "on" or xmlns
'on_events' => '#(<[^>]+[a-z\x00-\x20\"\'\/])(on[a-z]+|xmlns)\s*=[\s|\'\"].*[\s|\'\"]>#iUu',
// Match any attribute starting with "on" or xmlns (must be preceded by whitespace/special chars)
// Allow optional whitespace between 'on' and event name to catch obfuscation attempts
'on_events' => '#(<[^>]+[\s\x00-\x20\"\'\/])(on\s*[a-z]+|xmlns)\s*=[\s|\'\"].*[\s|\'\"]>#iUu',
// Match javascript:, livescript:, vbscript:, mocha:, feed: and data: protocols
'invalid_protocols' => '#(' . implode('|', array_map('preg_quote', $invalid_protocols, ['#'])) . ')(:|\&\#58)\S.*?#iUu',
@@ -243,8 +244,16 @@ class Security
// Iterate over rules and return label if fail
foreach ($patterns as $name => $regex) {
if (!empty($enabled_rules[$name])) {
if (preg_match($regex, (string) $string) || preg_match($regex, (string) $stripped) || preg_match($regex, $orig)) {
return $name;
// Skip testing 'on_events' against stripped version to avoid false positives
// with tags like <caption>, <button>, <section> that end with 'on' or contain 'on'
if ($name === 'on_events') {
if (preg_match($regex, (string) $string) || preg_match($regex, $orig)) {
return $name;
}
} else {
if (preg_match($regex, (string) $string) || preg_match($regex, (string) $stripped) || preg_match($regex, $orig)) {
return $name;
}
}
}
}