[FIX] web_editor: fix url regex when containing symbols

Commit [1] introduces a stronger regex for url containing symbols. It did so by
using a negative lookbehind, which was not supported on some version of Safari
iOS and edge. Later commit [2] was introduced in attempt to reproduce the same
behaviour without using negative lookbehind but missed some cases such as github
compare link where the url had multiple symbols.

This commit is an attempt to reproduce the same behaviour like [1] while
improving [2].

[1]: a42a19e
[2]: ff99e45

task-3468646

closes odoo/odoo#143250

Signed-off-by: Geelen Sébastien (sge) <sge@odoo.com>
This commit is contained in:
Deependra Solanki
2023-11-23 08:52:04 +00:00
parent de34fed834
commit 34550223aa
3 changed files with 56 additions and 1 deletions
@@ -50,7 +50,7 @@ const tldWhitelist = [
'ug', 'uk', 'um', 'us', 'uy', 'uz', 'va', 'vc', 've', 'vg', 'vi', 'vn',
'vu', 'wf', 'ws', 'ye', 'yt', 'yu', 'za', 'zm', 'zr', 'zw', 'co\\.uk'];
const urlRegexBase = `|(?:www.))[-a-zA-Z0-9@:%._\\+~#=]{2,256}\\.[a-zA-Z][a-zA-Z0-9]{1,62}|(?:[-a-zA-Z0-9@:%._\\+~#=]{2,256}\\.(?:${tldWhitelist.join('|')})\\b))(?:\\/[^\\s.,'")}\\]]*[?#.,)}\\]'"]?[^\\s.,'")}\\]]+|(?:[^!(){}.,\\[\\]'"\\s]+)|\\/[^\\s.,'")}\\]]*[^\\s?#.,'")}\\]]*)?`;
const urlRegexBase = `|(?:www.))[-a-zA-Z0-9@:%._\\+~#=]{2,256}\\.[a-zA-Z][a-zA-Z0-9]{1,62}|(?:[-a-zA-Z0-9@:%._\\+~#=]{2,256}\\.(?:${tldWhitelist.join('|')})\\b))(?:(?:[/?#])[^\\s]*[^!.,})\\]'"\\s]|(?:[^!(){}.,[\\]'"\\s]+))?`;
const httpCapturedRegex= `(https?:\\/\\/)`;
export const URL_REGEX = new RegExp(`((?:(?:${httpCapturedRegex}${urlRegexBase})`, 'i');
@@ -48,6 +48,7 @@ describe('Link', () => {
testUrlRegex('google.com!', {expectedUrl: 'google.com'});
testUrlRegex('google.com)', {expectedUrl: 'google.com'});
testUrlRegex('google.com(', {expectedUrl: 'google.com'});
testUrlRegex('google.com/ a', {expectedUrl: 'google.com/'});
testUrlRegex('google.com. a', {expectedUrl: 'google.com'});
testUrlRegex('google.com, a', {expectedUrl: 'google.com'});
@@ -59,6 +60,20 @@ describe('Link', () => {
testUrlRegex('google.com/}', {expectedUrl: 'google.com/'});
testUrlRegex("google.com/'", {expectedUrl: 'google.com/'});
testUrlRegex('google.com/"', {expectedUrl: 'google.com/'});
testUrlRegex('google.com#.', {expectedUrl: 'google.com#'});
testUrlRegex('google.com#,', {expectedUrl: 'google.com#'});
testUrlRegex('google.com#)', {expectedUrl: 'google.com#'});
testUrlRegex('google.com#]', {expectedUrl: 'google.com#'});
testUrlRegex('google.com#}', {expectedUrl: 'google.com#'});
testUrlRegex("google.com#'", {expectedUrl: 'google.com#'});
testUrlRegex('google.com#"', {expectedUrl: 'google.com#'});
testUrlRegex('google.com?,', {expectedUrl: 'google.com?'});
testUrlRegex('google.com?.', {expectedUrl: 'google.com?'});
testUrlRegex('google.com?)', {expectedUrl: 'google.com?'});
testUrlRegex('google.com?]', {expectedUrl: 'google.com?'});
testUrlRegex('google.com?}', {expectedUrl: 'google.com?'});
testUrlRegex("google.com?'", {expectedUrl: 'google.com?'});
testUrlRegex('google.com?"', {expectedUrl: 'google.com?'});
// The previous special character should be included when they are nt at the end.
testUrlRegex('google.com/.a', {expectedUrl: 'google.com/.a'});
@@ -73,20 +88,33 @@ describe('Link', () => {
testUrlRegex('google.com/(', {expectedUrl: 'google.com/('});
testUrlRegex('google.com/[', {expectedUrl: 'google.com/['});
testUrlRegex('google.com/{', {expectedUrl: 'google.com/{'});
testUrlRegex('google.com?(', {expectedUrl: 'google.com?('});
testUrlRegex('google.com?[', {expectedUrl: 'google.com?['});
testUrlRegex('google.com?{', {expectedUrl: 'google.com?{'});
testUrlRegex('google.com#(', {expectedUrl: 'google.com#('});
testUrlRegex('google.com#[', {expectedUrl: 'google.com#['});
testUrlRegex('google.com#{', {expectedUrl: 'google.com#{'});
testUrlRegex('google.co.uk');
testUrlRegex('google123.com');
testUrlRegex('http://google.com');
testUrlRegex('http://google123.com');
testUrlRegex('https://google.com');
testUrlRegex('https://google123.com');
testUrlRegex('https://www.google.com');
testUrlRegex('https://google.shop');
testNotUrlRegex('google.shop');
testUrlRegex('google.com/');
testUrlRegex('google.com/path/123/abc/4');
testUrlRegex('http://google.com/');
testUrlRegex('http://google.com/home');
testUrlRegex('http://google.com/home/');
testUrlRegex('https://google.com/');
testUrlRegex('https://google.co.uk/');
testUrlRegex('https://www.google.com/');
testNotUrlRegex('google.shop/');
testUrlRegex('http://google.com/foo#test');
testUrlRegex('http://google.com/#test');
testNotUrlRegex('a.bcd.ef');
testUrlRegex('a.bc.de');
testNotUrlRegex('a.bc.d');
@@ -98,11 +126,26 @@ describe('Link', () => {
testUrlRegex('google.com?data=hello', { expectedUrl: 'google.com?data=hello' });
testUrlRegex('google.com/?data=hello', { expectedUrl: 'google.com/?data=hello' });
testUrlRegex('google.com/foo/?data=hello', { expectedUrl: 'google.com/foo/?data=hello' });
testUrlRegex('google.com/foo/?data1=hello1&data2=hello2', { expectedUrl: 'google.com/foo/?data1=hello1&data2=hello2' });
testUrlRegex('google.com/.?data=hello', { expectedUrl: 'google.com/.?data=hello' });
testUrlRegex('google.com?data=hello#anchor', { expectedUrl: 'google.com?data=hello#anchor' });
testUrlRegex('google.com/?data=hello#anchor', { expectedUrl: 'google.com/?data=hello#anchor' });
testUrlRegex('google.com/.?data=hello#anchor', { expectedUrl: 'google.com/.?data=hello#anchor' });
testUrlRegex('google.com/foo/?data=hello&data2=foo#anchor', { expectedUrl: 'google.com/foo/?data=hello&data2=foo#anchor' });
// Url containing some special characters
testUrlRegex('www.google.com/path/1-2-3', { expectedUrl: 'www.google.com/path/1-2-3' });
testUrlRegex('https://google.com/abc..def', { expectedUrl: 'https://google.com/abc..def' });
testUrlRegex('https://google.com/a/b+c@d', { expectedUrl: 'https://google.com/a/b+c@d' });
testUrlRegex('sub.example-website.com', { expectedUrl: 'sub.example-website.com' });
testUrlRegex('http://sub.example-website.com', { expectedUrl: 'http://sub.example-website.com' });
testUrlRegex('http://user:password@example.com', { expectedUrl: 'http://user:password@example.com' });
testUrlRegex('http://google.com/a_b', { expectedUrl: 'http://google.com/a_b' });
testUrlRegex('https://google.com?query=ab.cd', { expectedUrl: 'https://google.com?query=ab.cd' });
testUrlRegex(`google.com/'ab'/cd`, { expectedUrl: "google.com/'ab'/cd" });
testUrlRegex(`www.google.com/a!b/c?d,e,f#g!i`, { expectedUrl: 'www.google.com/a!b/c?d,e,f#g!i' });
testUrlRegex(`www.google.com/a%b%c`, { expectedUrl: 'www.google.com/a%b%c' });
testUrlRegex(`http://google.com?a.b.c&d!e#e'f`, { expectedUrl: "http://google.com?a.b.c&d!e#e'f" });
});
describe('insert Link', () => {
describe('range collapsed', () => {
@@ -21,6 +21,18 @@ describe('urlRegex', () => {
const match = text.match(URL_REGEX);
chai.expect(match[0]).to.be.equal(url);
});
it('should match abc.abc.com', () => {
const url = 'abc.abc.com';
const text = `abc ${url} abc`;
const match = text.match(URL_REGEX);
chai.expect(match[0]).to.be.equal(url);
});
it('should not match abc.abc.abc', () => {
const url = 'abc.abc.abc';
const text = `abc ${url} abc`;
const match = text.match(URL_REGEX);
chai.expect(match).to.be.equal(null);
});
it('should match http://abc.abc.abc', () => {
const url = 'http://abc.abc.abc';
const text = `abc ${url} abc`;