fix(audit L1): Schleifen in module.advanced.loop brauchen list_users (Benutzer) bzw. read_private_posts (any, attachment, leere subTypes), auch beim Kopieren

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
Jan-Niclas Loosen
2026-10-20 00:00:59 +02:00
co-authored by Claude Sonnet 5.5
parent 9c1d5fad22
commit 4a8a889f93
10 changed files with 299 additions and 9 deletions
@@ -27,13 +27,16 @@ final class StoredNodeGuardTest extends TestCase
private const PROBE_HTML = '<iframe data-probe="1"></iframe>';
private const PROBE_SCRIPT = '<script data-probe="1">/* probe */</script>';
private static function guard(bool $unfiltered = false): StoredNodeGuard
{
private static function guard(
bool $unfiltered = false,
bool $listUsers = true,
bool $readPrivate = true
): StoredNodeGuard {
$references = new VariableRef(
DiviFixtures::designSystem(),
DynamicContentMap::fromOptions(DiviFixtures::dynamicContentRegistry())
);
$sanitizer = ComposeFixture::sanitizer($unfiltered);
$sanitizer = ComposeFixture::sanitizer($unfiltered, $listUsers, $readPrivate);
$cleaner = new ValueCleaner(DiviFixtures::catalog(), $references, $sanitizer);
@@ -411,6 +414,21 @@ final class StoredNodeGuardTest extends TestCase
return false;
}
public function canListUsers(): bool
{
return $this->inner->canListUsers();
}
public function canReadPrivatePosts(): bool
{
return $this->inner->canReadPrivatePosts();
}
public function postTypeExists(string $type): bool
{
return $this->inner->postTypeExists($type);
}
public function canReadPost(int $id): bool
{
return $this->inner->canReadPost($id);
@@ -472,4 +490,28 @@ final class StoredNodeGuardTest extends TestCase
self::assertSame([], self::wpLikeGuard()->problems(self::link('//evil.example')));
self::assertNotSame([], self::wpLikeGuard(false)->problems(self::link('//evil.example')));
}
/** Audit L1: copied loops need the same rights as written ones – also for accounts with unfiltered_html. */
public function testACopiedLoopNeedsTheRightsItsSettingsNeed(): void
{
$user = self::block(self::node('divi/text', ['module' => ['advanced' => ['loop' => self::desktop(
['enable' => 'on', 'queryType' => 'user_roles']
)]]]));
$private = self::block(self::node('divi/text', ['module' => ['advanced' => ['loop' => self::desktop(
['enable' => 'on', 'queryType' => 'post_types', 'subTypes' => []]
)]]]));
foreach ([false, true] as $unfiltered) {
self::assertStringContainsString(
'list_users',
implode(' ', self::guard($unfiltered, false, true)->problems($user))
);
self::assertStringContainsString(
'read_private_posts',
implode(' ', self::guard($unfiltered, true, false)->problems($private))
);
}
self::assertSame([], self::guard(true, true, true)->problems($user));
self::assertSame([], self::guard(true, true, true)->problems($private));
}
}