diff --git a/core/lib/presentation/utils/html_transformer/dom/normalize_line_height_in_style_transformer.dart b/core/lib/presentation/utils/html_transformer/dom/normalize_line_height_in_style_transformer.dart
index cef2e672f..53eccd7c8 100644
--- a/core/lib/presentation/utils/html_transformer/dom/normalize_line_height_in_style_transformer.dart
+++ b/core/lib/presentation/utils/html_transformer/dom/normalize_line_height_in_style_transformer.dart
@@ -8,6 +8,12 @@ class NormalizeLineHeightInStyleTransformer extends DomTransformer {
static const _removableLineHeights = ['1px', '100%'];
static final _multipleSpacesRegex = RegExp(r' {2,}');
+ static final _lineHeightPattern = RegExp(
+ r'line-height\s*:\s*(?:' +
+ _removableLineHeights.map(RegExp.escape).join('|') +
+ r')\s*;?',
+ caseSensitive: false,
+ );
@override
Future process({
@@ -16,11 +22,7 @@ class NormalizeLineHeightInStyleTransformer extends DomTransformer {
Map? mapUrlDownloadCID,
}) async {
try {
- final alternation = _removableLineHeights.map(RegExp.escape).join('|');
- final pattern = RegExp(
- r'line-height\s*:\s*(?:' + alternation + r')\s*;?',
- caseSensitive: false,
- );
+
final elements = document.querySelectorAll('[style*="line-height"]');
@@ -28,7 +30,7 @@ class NormalizeLineHeightInStyleTransformer extends DomTransformer {
final originalStyle = element.attributes['style'];
if (originalStyle == null) continue;
- var updatedStyle = originalStyle.replaceAll(pattern, '').trim();
+ var updatedStyle = originalStyle.replaceAll(_lineHeightPattern, '').trim();
// Remove extra spaces (>=2 spaces → 1 space)
updatedStyle = updatedStyle.replaceAll(_multipleSpacesRegex, ' ');
diff --git a/core/lib/utils/html/html_utils.dart b/core/lib/utils/html/html_utils.dart
index baba7a2a1..794f5fb9c 100644
--- a/core/lib/utils/html/html_utils.dart
+++ b/core/lib/utils/html/html_utils.dart
@@ -34,6 +34,10 @@ class HtmlUtils {
multiLine: true,
);
static final _protocolRegex = RegExp(r'^(?:https?|ftp|mailto|file)');
+ static final _tagRemovalRegex = RegExp(
+ '?(?:${validTags.map(RegExp.escape).join('|')})(?:\\s+[^>]*)?>',
+ caseSensitive: false,
+ );
static const removeLineHeight1px = (
script: '''
@@ -861,12 +865,7 @@ class HtmlUtils {
} while (decoded != cleaned && iterations < maxIterations);
// Delete all remaining HTML tags → replace tag with space to avoid text sticking
- final String tagsPipe = validTags.map(RegExp.escape).join('|');
- final tagRegex = RegExp(
- '?(?:$tagsPipe)(?:\\s+[^>]*)?>',
- caseSensitive: false,
- );
- cleaned = cleaned.replaceAll(tagRegex, ' ');
+ cleaned = cleaned.replaceAll(_tagRemovalRegex, ' ');
// Normalize whitespace
cleaned = cleaned.replaceAll(_whitespaceNormalizationRegex, ' ').trim();
diff --git a/core/test/utils/string_convert_test.dart b/core/test/utils/string_convert_test.dart
index d3dde6e70..fba8ee1e6 100644
--- a/core/test/utils/string_convert_test.dart
+++ b/core/test/utils/string_convert_test.dart
@@ -815,6 +815,32 @@ void main() {
]),
);
});
+ test('Does not corrupt plain text that looks like base64', () {
+ // "useruser" is 8 chars (multiple of 4) and fits the base64 regex.
+ // base64.decode("useruser") produces random bytes.
+ const input = 'useruser';
+ final result = StringConvert.extractNamedAddresses(input);
+ expect(result.first.address, equals('useruser'));
+ });
+ test('Handles brackets with no name', () {
+ const input = '';
+ final result = StringConvert.extractNamedAddresses(input);
+ expect(result.first.name, isEmpty);
+ expect(result.first.address, equals('only-email@example.com'));
+ });
+ test('Handles names containing commas', () {
+ const input =
+ '"Doe, John" , "Smith, Jane" ';
+ final result = StringConvert.extractNamedAddresses(input);
+ expect(result[0].name, equals('Doe, John'));
+ expect(result[1].name, equals('Smith, Jane'));
+ });
+ test('Handles malformed input gracefully', () {
+ const input = '"Unclosed Quote ';
+ final result = StringConvert.extractNamedAddresses(input);
+ // Ensure it doesn't crash and returns at least the email
+ expect(result, isNotEmpty);
+ });
});
group('StringConvert.convertHtmlContentToTextContent', () {