Repair: copy legacy joinDate into new user's created_at when creating users from legacy wallz

This commit is contained in:
2026-03-22 09:13:39 +01:00
parent e8b5edf5d2
commit 2608be7420
80 changed files with 3991 additions and 723 deletions

View File

@@ -72,6 +72,20 @@ class ContentSanitizer
return $html;
}
/**
* Normalize previously rendered HTML for display-time policy changes.
* This is useful when stored HTML predates current link attributes or
* when display rules depend on the author rather than the raw content.
*/
public static function sanitizeRenderedHtml(?string $html, bool $allowLinks = true): string
{
if ($html === null || trim($html) === '') {
return '';
}
return static::sanitizeHtml($html, $allowLinks);
}
/**
* Strip ALL HTML from input, returning plain text with newlines preserved.
*/
@@ -190,7 +204,7 @@ class ContentSanitizer
* Whitelist-based HTML sanitizer.
* Removes all tags not in ALLOWED_TAGS, and strips disallowed attributes.
*/
private static function sanitizeHtml(string $html): string
private static function sanitizeHtml(string $html, bool $allowLinks = true): string
{
// Parse with DOMDocument
$doc = new \DOMDocument('1.0', 'UTF-8');
@@ -202,7 +216,7 @@ class ContentSanitizer
);
libxml_clear_errors();
static::cleanNode($doc->getElementsByTagName('body')->item(0));
static::cleanNode($doc->getElementsByTagName('body')->item(0), $allowLinks);
// Serialize back, removing the wrapping html/body
$body = $doc->getElementsByTagName('body')->item(0);
@@ -218,13 +232,17 @@ class ContentSanitizer
/**
* Recursively clean a DOMNode strip forbidden tags/attributes.
*/
private static function cleanNode(\DOMNode $node): void
private static function cleanNode(\DOMNode $node, bool $allowLinks = true): void
{
$toRemove = [];
$toUnwrap = [];
foreach ($node->childNodes as $child) {
if ($child->nodeType === XML_ELEMENT_NODE) {
if (! $child instanceof \DOMElement) {
continue;
}
$tag = strtolower($child->nodeName);
if (! in_array($tag, self::ALLOWED_TAGS, true)) {
@@ -245,17 +263,22 @@ class ContentSanitizer
// Force external links to be safe
if ($tag === 'a') {
if (! $allowLinks) {
$toUnwrap[] = $child;
continue;
}
$href = $child->getAttribute('href');
if ($href && ! static::isSafeUrl($href)) {
$toUnwrap[] = $child;
continue;
}
$child->setAttribute('rel', 'noopener noreferrer nofollow');
$child->setAttribute('rel', 'noopener noreferrer nofollow ugc');
$child->setAttribute('target', '_blank');
}
// Recurse
static::cleanNode($child);
static::cleanNode($child, $allowLinks);
}
}
}