From 9190b6bd900eab0b387a3fce573dfc87b89216e6 Mon Sep 17 00:00:00 2001 From: mym0404 Date: Tue, 19 Mar 2024 00:14:43 +0900 Subject: [PATCH 1/9] chore(ide): ignore intellij ide settings in vcs --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 6ff0be3d..6e9d99d9 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ .pub pubspec.lock doc/ +.idea/ From 368db1c1e527cec439ecfd45c1c0ae1e1d1cd965 Mon Sep 17 00:00:00 2001 From: mym0404 Date: Tue, 19 Mar 2024 01:41:51 +0900 Subject: [PATCH 2/9] fix: uRL-escaping should be left alone inside the destination By the Rule "URL-escaping should be left alone inside the destination", Reimplement `normalizeLinkDestination` util function with splitting by URL escapings and concat them --- lib/src/util.dart | 28 +++++++++++++++++++++------- test/original/inline_images.unit | 6 +++++- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/lib/src/util.dart b/lib/src/util.dart index ddeb22fe..33b048c7 100644 --- a/lib/src/util.dart +++ b/lib/src/util.dart @@ -41,17 +41,31 @@ String normalizeLinkLabel(String label) { } /// Normalizes a link destination, including the process of HTML characters -/// decoding and percent encoding. +/// decoding and percent encoding. // See the description of these examples: // https://spec.commonmark.org/0.30/#example-501 // https://spec.commonmark.org/0.30/#example-502 String normalizeLinkDestination(String destination) { - // Decode first, because the destination might have been partly encoded. - // For example https://spec.commonmark.org/0.30/#example-502. - // With this function, `foo%20bä` will be parsed in the following steps: - // 1. foo bä - // 2. foo bä - // 3. foo%20b%C3%A4 + // Split by url escaping characters + // Concat them with unmodified URL-escaping. + // URL-escaping should be left alone inside the destination + // Refer: https://spec.commonmark.org/0.30/#example-502. + + final regex = RegExp('%[0-9A-Fa-f]{2}'); + final matches = regex.allMatches(destination).toList(); + final substrings = destination + .split(regex) + .map((e) => Uri.encodeFull(decodeHtmlCharacters(e))) + .toList(); + + final buffer = StringBuffer(substrings[0]); + for (var i = 0; i < matches.length; i++) { + buffer.write(matches[i].match); + buffer.write(substrings[i + 1]); + } + + return buffer.toString(); + try { destination = Uri.decodeFull(destination); } catch (_) {} diff --git a/test/original/inline_images.unit b/test/original/inline_images.unit index 9e582646..817e4bde 100644 --- a/test/original/inline_images.unit +++ b/test/original/inline_images.unit @@ -22,4 +22,8 @@ ![Uh oh...]("onerror="alert('XSS')) <<< -

Uh oh...

\ No newline at end of file +

Uh oh...

+>>> image %2F shouldn't be encoded +![](https://example/foo%2Fvar) +<<< +

\ No newline at end of file From 64c11cd964cce935141648415950320d2badd6f1 Mon Sep 17 00:00:00 2001 From: mym0404 Date: Tue, 19 Mar 2024 01:49:44 +0900 Subject: [PATCH 3/9] Revert "chore(ide): ignore intellij ide settings in vcs" This reverts commit 9190b6bd900eab0b387a3fce573dfc87b89216e6. --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index 6e9d99d9..6ff0be3d 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,3 @@ .pub pubspec.lock doc/ -.idea/ From 5ad6feacd52b950f6f1d08265d2799432d852d25 Mon Sep 17 00:00:00 2001 From: mym0404 Date: Tue, 19 Mar 2024 01:51:33 +0900 Subject: [PATCH 4/9] refactor: remove dead codes --- lib/src/util.dart | 5 ----- 1 file changed, 5 deletions(-) diff --git a/lib/src/util.dart b/lib/src/util.dart index 33b048c7..27f30843 100644 --- a/lib/src/util.dart +++ b/lib/src/util.dart @@ -65,11 +65,6 @@ String normalizeLinkDestination(String destination) { } return buffer.toString(); - - try { - destination = Uri.decodeFull(destination); - } catch (_) {} - return Uri.encodeFull(decodeHtmlCharacters(destination)); } /// Normalizes a link title, including the process of HTML characters decoding From e835bd9b6d233cc7095dd33ddefa30714bd51a3b Mon Sep 17 00:00:00 2001 From: mym0404 Date: Tue, 19 Mar 2024 01:54:16 +0900 Subject: [PATCH 5/9] chore: fix typo in comment --- lib/src/util.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/util.dart b/lib/src/util.dart index 27f30843..6e0b6224 100644 --- a/lib/src/util.dart +++ b/lib/src/util.dart @@ -47,7 +47,7 @@ String normalizeLinkLabel(String label) { // https://spec.commonmark.org/0.30/#example-502 String normalizeLinkDestination(String destination) { // Split by url escaping characters - // Concat them with unmodified URL-escaping. + // Concatenate them with unmodified URL-escaping. // URL-escaping should be left alone inside the destination // Refer: https://spec.commonmark.org/0.30/#example-502. From bdf01c09601eea6b6aaccb9b1a9b118e671c338c Mon Sep 17 00:00:00 2001 From: mym0404 Date: Tue, 19 Mar 2024 01:56:34 +0900 Subject: [PATCH 6/9] refactor: change test name --- test/original/inline_images.unit | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/original/inline_images.unit b/test/original/inline_images.unit index 817e4bde..c8180ce9 100644 --- a/test/original/inline_images.unit +++ b/test/original/inline_images.unit @@ -23,7 +23,7 @@ <<<

Uh oh...

->>> image %2F shouldn't be encoded +>>> URL-escaping should be left alone inside the destination ![](https://example/foo%2Fvar) <<<

\ No newline at end of file From 94fed772ed15cf6aaf4d6dff664dd149030ea72c Mon Sep 17 00:00:00 2001 From: mym0404 Date: Tue, 19 Mar 2024 02:29:22 +0900 Subject: [PATCH 7/9] feat: add decodeFull logic for splitted strings --- lib/src/util.dart | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/lib/src/util.dart b/lib/src/util.dart index 6e0b6224..ca93e04f 100644 --- a/lib/src/util.dart +++ b/lib/src/util.dart @@ -53,15 +53,19 @@ String normalizeLinkDestination(String destination) { final regex = RegExp('%[0-9A-Fa-f]{2}'); final matches = regex.allMatches(destination).toList(); - final substrings = destination - .split(regex) - .map((e) => Uri.encodeFull(decodeHtmlCharacters(e))) - .toList(); - - final buffer = StringBuffer(substrings[0]); + final splitIterator = destination.split(regex).map((e) { + try { + e = Uri.decodeFull(e); + } catch (_) {} + return Uri.encodeFull(decodeHtmlCharacters(e)); + }).iterator; + + splitIterator.moveNext(); + final buffer = StringBuffer(splitIterator.current); for (var i = 0; i < matches.length; i++) { + splitIterator.moveNext(); buffer.write(matches[i].match); - buffer.write(substrings[i + 1]); + buffer.write(splitIterator.current); } return buffer.toString(); From 2e790e468dc78ddb3b26c4a7823b26d628dc07d4 Mon Sep 17 00:00:00 2001 From: mym0404 Date: Tue, 19 Mar 2024 02:30:57 +0900 Subject: [PATCH 8/9] chore: sync code From cd42034a39ea764b0a2aaca23af591a73331719c Mon Sep 17 00:00:00 2001 From: mym0404 Date: Tue, 19 Mar 2024 10:12:37 +0900 Subject: [PATCH 9/9] refactor: normalizeLinkDestination with functional way --- lib/src/util.dart | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/lib/src/util.dart b/lib/src/util.dart index ca93e04f..93ea1e65 100644 --- a/lib/src/util.dart +++ b/lib/src/util.dart @@ -52,23 +52,17 @@ String normalizeLinkDestination(String destination) { // Refer: https://spec.commonmark.org/0.30/#example-502. final regex = RegExp('%[0-9A-Fa-f]{2}'); - final matches = regex.allMatches(destination).toList(); - final splitIterator = destination.split(regex).map((e) { - try { - e = Uri.decodeFull(e); - } catch (_) {} - return Uri.encodeFull(decodeHtmlCharacters(e)); - }).iterator; - - splitIterator.moveNext(); - final buffer = StringBuffer(splitIterator.current); - for (var i = 0; i < matches.length; i++) { - splitIterator.moveNext(); - buffer.write(matches[i].match); - buffer.write(splitIterator.current); - } - return buffer.toString(); + return destination.splitMapJoin( + regex, + onMatch: (m) => m.match, + onNonMatch: (e) { + try { + e = Uri.decodeFull(e); + } catch (_) {} + return Uri.encodeFull(decodeHtmlCharacters(e)); + }, + ); } /// Normalizes a link title, including the process of HTML characters decoding