Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: keep consistency with backend email validation #566

Merged
merged 8 commits into from
Aug 29, 2023

Conversation

Antasel
Copy link
Contributor

@Antasel Antasel commented Aug 16, 2023

Fixed Issues

$ Expensify/App#17387
Proposal: Expensify/App#17387 (comment), Expensify/App#17387 (comment)

Tests

  1. Go to a chat and send following valid emails and verify that all are parsed as email
Valid emails
        // Domain length (63 chars in each label)
        test@asjjssjdjdjdjdjdjjeiwiwiwowkdjdjdieikdjfidekjcjdkekejdcjdkeekcj.com
        abc@abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890.km
        abc@co.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890.km

        // Address length (64 chars)
        sjjssjdjdjdjdjdjjeiwiwiwowkdjdjdieikdjfidekjcjdkekejdcjdkeekcjab@test.com

        // Overall length (254 chars)
        averylongaddresspartthatalmostwillreachthelimitofcharsperaddress@nowwejustneedaverylongdomainpartthatwill.reachthetotallengthlimitforthewholeemailaddress.whichis254charsaccordingtothePHPvalidate-email-filter.extendingthetestlongeruntilwereachtheright.com

        // Domain with lots of dashes
        sjjssjdjdjdjdjdjjeiwiwiwowkdjdjdieikdjfidekjcjdkekejdcjdkeekcjab@asj-j-s-sjdjdjdjd-jdjjeiwiwiwowkdjdjdieikdjfidekjcjdkekejdcjdke.com.ab.net.aa.bb.cc.dd.ee
        abc@g---m--ai-l.com

        // Domain with repeated labels of 63 chars
        test@asjjssjdjdjdjdjdjjeiwiwiwowkdjdjdieikdjfidekasgasgasgasgashfnfn.asjjssjdjdjdjdjdjjeiwiwiwowkdjdjdieikdjfidekasgasgasgasgashfnfn.asjjssjdjdjdjdjdjjeiwiwiwowkdjdjdieikdjfidekasgasgasgasgashfnfn.com

        // TLD >=2 chars
        abc@gmail.co
        a@a.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijk

        // Very short address
        a@example.com

        // xn-- style domain name
        test@xn--diseolatinoamericano-76b.com

        // Unusual but valid prefixes
        -test@example.com
        _test@example.com
        #test@example.com
        test.+123@example.com
        -test-@example.com
  1. send following invalid emails and verify that the emails are not parsed as email, but only valid parts are extracted as email
Invalid emails
        $test@gmail.com
        !test@gmail.com
        "test"@gmail.com
        ~abc@gmail.com~
        abc@gmail.com~
        test@example_123site.com
        test{@example.com
        test..new@example.com
        test@example-.a.com
        test@example......a.com

        // Invalid period location
        .test@example.com
        .test.new@example.com
        test.@example.com

        // Domain too long (>63 chars in each label)
        test@averylongdomainpartoftheemailthatwillgooverthelimitasitismorethan63chars.com
        abc@abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890a.km
        abc@co.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890a.km

        // Address too long (>64 chars)
        averylongaddresspartoftheemailthatwillgovoerthelimitasitismorethan64chars@example.com

        // Incorrect domains start/end
        test@example-.com
        test@-example-.com

        // TLD too short
        test@example.a

        // TLD too long
        a@a.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijkl
  1. Navigate to Settings > Profile > Contact Method > New Contact Method, try an valid / invalid email

Demo Video:

test-keep-consistency-with-email-validation.mp4

Autotest cases:

Str-test.js new tests
describe('Str.isValidEmail', () => {
    it('Correctly identifies valid emails', () => {
        expect(Str.isValidEmail('abc@gmail.com')).toBeTruthy();

        // Domain length (63 chars in each label)
        expect(Str.isValidEmail('test@asjjssjdjdjdjdjdjjeiwiwiwowkdjdjdieikdjfidekjcjdkekejdcjdkeekcj.com')).toBeTruthy();
        expect(Str.isValidEmail('abc@abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890.km')).toBeTruthy();
        expect(Str.isValidEmail('abc@co.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890.km')).toBeTruthy();

        // Address length (64 chars)
        expect(Str.isValidEmail('sjjssjdjdjdjdjdjjeiwiwiwowkdjdjdieikdjfidekjcjdkekejdcjdkeekcjab@test.com')).toBeTruthy();

        // Overall length (254 chars)
        expect(Str.isValidEmail('averylongaddresspartthatalmostwillreachthelimitofcharsperaddress@nowwejustneedaverylongdomainpartthatwill.reachthetotallengthlimitforthewholeemailaddress.whichis254charsaccordingtothePHPvalidate-email-filter.extendingthetestlongeruntilwereachtheright.com')).toBeTruthy();

        // Domain with lots of dashes
        expect(Str.isValidEmail('sjjssjdjdjdjdjdjjeiwiwiwowkdjdjdieikdjfidekjcjdkekejdcjdkeekcjab@asj-j-s-sjdjdjdjd-jdjjeiwiwiwowkdjdjdieikdjfidekjcjdkekejdcjdke.com.ab.net.aa.bb.cc.dd.ee')).toBeTruthy();
        expect(Str.isValidEmail('abc@g---m--ai-l.com')).toBeTruthy();

        // Domain with repeated labels of 63 chars
        expect(Str.isValidEmail('test@asjjssjdjdjdjdjdjjeiwiwiwowkdjdjdieikdjfidekasgasgasgasgashfnfn.asjjssjdjdjdjdjdjjeiwiwiwowkdjdjdieikdjfidekasgasgasgasgashfnfn.asjjssjdjdjdjdjdjjeiwiwiwowkdjdjdieikdjfidekasgasgasgasgashfnfn.com')).toBeTruthy();

        // TLD >=2 chars
        expect(Str.isValidEmail('abc@gmail.co')).toBeTruthy();
        expect(Str.isValidEmail('a@a.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijk')).toBeTruthy();

        // Very short address
        expect(Str.isValidEmail('a@example.com')).toBeTruthy();

        // xn-- style domain name
        expect(Str.isValidEmail('test@xn--diseolatinoamericano-76b.com')).toBeTruthy();

        // Unusual but valid prefixes
        expect(Str.isValidEmail('-test@example.com')).toBeTruthy();
        expect(Str.isValidEmail('_test@example.com')).toBeTruthy();
        expect(Str.isValidEmail('#test@example.com')).toBeTruthy();
        expect(Str.isValidEmail('test.+123@example.com')).toBeTruthy();
        expect(Str.isValidEmail('-test-@example.com')).toBeTruthy();

        // Invalid chars
        expect(Str.isValidEmail('$test@gmail.com')).toBeFalsy();
        expect(Str.isValidEmail('!test@gmail.com')).toBeFalsy();
        expect(Str.isValidEmail('"test"@gmail.com')).toBeFalsy();
        expect(Str.isValidEmail('~abc@gmail.com~')).toBeFalsy();
        expect(Str.isValidEmail('abc@gmail.com~')).toBeFalsy();
        expect(Str.isValidEmail('test@example_123site.com')).toBeFalsy();
        expect(Str.isValidEmail('test{@example.com')).toBeFalsy();
        expect(Str.isValidEmail('test..new@example.com')).toBeFalsy();
        expect(Str.isValidEmail('test@example-.a.com')).toBeFalsy();
        expect(Str.isValidEmail('test@example......a.com')).toBeFalsy();

        // Invalid period location
        expect(Str.isValidEmail('.test@example.com')).toBeFalsy();
        expect(Str.isValidEmail('.test.new@example.com')).toBeFalsy();
        expect(Str.isValidEmail('test.@example.com')).toBeFalsy();

        // Domain too long (>63 chars in each label)
        expect(Str.isValidEmail('test@averylongdomainpartoftheemailthatwillgooverthelimitasitismorethan63chars.com')).toBeFalsy();
        expect(Str.isValidEmail('abc@abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890a.km')).toBeFalsy();
        expect(Str.isValidEmail('abc@co.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890a.km')).toBeFalsy();

        // Address too long (>64 chars)
        expect(Str.isValidEmail('averylongaddresspartoftheemailthatwillgovoerthelimitasitismorethan64chars@example.com')).toBeFalsy();

        // Incorrect domains start/end
        expect(Str.isValidEmail('test@example-.com')).toBeFalsy();
        expect(Str.isValidEmail('test@-example-.com')).toBeFalsy();

        // TLD too short
        expect(Str.isValidEmail('test@example.a')).toBeFalsy();

        // TLD too long
        expect(Str.isValidEmail('a@a.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijkl')).toBeFalsy();
    });
});
ExpensiMark-HTML-test.js new tests
// Check emails within other markdown
test('Test emails within other markdown', () => {
    const testString = '> test@example.com\n'
    + '```test@example.com```\n'
    + '`test@example.com`\n'
    + '_test@example.com_ '
    + '__test@example.com_';
    const result = '<blockquote><a href="mailto:test@example.com">test@example.com</a></blockquote>'
    + '<pre>test@example.com</pre>'
    + '<code>test@example.com</code><br />'
    + '<em><a href="mailto:test@example.com">test@example.com</a></em> '
    + '<em><a href="mailto:_test@example.com">_test@example.com</a></em>';
    expect(parser.replace(testString)).toBe(result);
});

// Check email regex's validity at various limits
test('Test markdown replacement for valid emails', () => {
    const testString = 'A simple email: abc@gmail.com, '
    + 'or a very short one a@example.com '
    + 'hitting the maximum domain length (63 chars) test@asjjssjdjdjdjdjdjjeiwiwiwowkdjdjdieikdjfidekjcjdkekejdcjdkeekcj.com '
    + 'or the maximum address length (64 chars) sjjssjdjdjdjdjdjjeiwiwiwowkdjdjdieikdjfidekjcjdkekejdcjdkeekcjab@test.com '
    + 'overall length of 254 averylongaddresspartthatalmostwillreachthelimitofcharsperaddress@nowwejustneedaverylongdomainpartthatwill.reachthetotallengthlimitforthewholeemailaddress.whichis254charsaccordingtothePHPvalidate-email-filter.extendingthetestlongeruntilwereachtheright.com '
    + 'domain with many dashes sjjssjdjdjdjdjdjjeiwiwiwowkdjdjdieikdjfidekjcjdkekejdcjdkeekcjab@asj-j-s-sjdjdjdjd-jdjjeiwiwiwowkdjdjdieikdjfidekjcjdkekejdcjdke.com.ab.net.aa.bb.cc.dd.ee '
    + ' how about a domain with repeated labels of 63 chars test@asjjssjdjdjdjdjdjjeiwiwiwowkdjdjdieikdjfidekasgasgasgasgashfnfn.asjjssjdjdjdjdjdjjeiwiwiwowkdjdjdieikdjfidekasgasgasgasgashfnfn.asjjssjdjdjdjdjdjjeiwiwiwowkdjdjdieikdjfidekasgasgasgasgashfnfn.com '
    + 'max length email with italics '
    + '_averylongaddresspartthatalmostwillreachthelimitofcharsperaddress@nowwejustneedaverylongdomainpartthatwill.reachthetotallengthlimitforthewholeemailaddress.whichis254charsaccordingtothePHPvalidate-email-filter.extendingthetestlongeruntilwereachtheright.com_ '
    + ' xn-- style domain test@xn--diseolatinoamericano-76b.com '
    + 'or a more complex case where we need to determine where to apply italics markdown '
    + '_email@test.com\n_email2@test.com\n\nemail3@test.com_ '
    + 'some unusual, but valid prefixes -test@example.com '
    + ' and _test@example.com '
    + 'a max length email enclosed in brackets '
    + '(averylongaddresspartthatalmostwillreachthelimitofcharsperaddress@nowwejustneedaverylongdomainpartthatwill.reachthetotallengthlimitforthewholeemailaddress.whichis254charsaccordingtothePHPvalidate-email-filter.extendingthetestlongeruntilwereachtheright.com) '
    + 'max length email with ellipsis ending '
    + 'averylongaddresspartthatalmostwillreachthelimitofcharsperaddress@nowwejustneedaverylongdomainpartthatwill.reachthetotallengthlimitforthewholeemailaddress.whichis254charsaccordingtothePHPvalidate-email-filter.extendingthetestlongeruntilwereachtheright.com... '
    + 'try a markdown link with a valid max-length email '
    + '[text](sjjssjdjdjdjdjdjjeiwiwiwowkdjdjdieikdjfidekjcjdkekejdcjdkeekcjab@asjjssjdjdjdjdjdjjeiwiwiwowkdjdjdieikdjfidekjcjdkekejdcjdkeekcj.com.a.aa.asjjssjdjdjdjdjdjjeiwiwiwowkdjdjdieikdjfidekjcjdkekejdcjdkeekcj.asjjssjdjdjdjdjdjjeiwiwiwowkdjdjdieikdjfidekjcjasfff)';
    const result = 'A simple email: <a href="mailto:abc@gmail.com">abc@gmail.com</a>, '
    + 'or a very short one <a href="mailto:a@example.com">a@example.com</a> '
    + 'hitting the maximum domain length (63 chars) <a href="mailto:test@asjjssjdjdjdjdjdjjeiwiwiwowkdjdjdieikdjfidekjcjdkekejdcjdkeekcj.com">test@asjjssjdjdjdjdjdjjeiwiwiwowkdjdjdieikdjfidekjcjdkekejdcjdkeekcj.com</a> '
    + 'or the maximum address length (64 chars) <a href="mailto:sjjssjdjdjdjdjdjjeiwiwiwowkdjdjdieikdjfidekjcjdkekejdcjdkeekcjab@test.com">sjjssjdjdjdjdjdjjeiwiwiwowkdjdjdieikdjfidekjcjdkekejdcjdkeekcjab@test.com</a> '
    + 'overall length of 254 <a href="mailto:averylongaddresspartthatalmostwillreachthelimitofcharsperaddress@nowwejustneedaverylongdomainpartthatwill.reachthetotallengthlimitforthewholeemailaddress.whichis254charsaccordingtothePHPvalidate-email-filter.extendingthetestlongeruntilwereachtheright.com">averylongaddresspartthatalmostwillreachthelimitofcharsperaddress@nowwejustneedaverylongdomainpartthatwill.reachthetotallengthlimitforthewholeemailaddress.whichis254charsaccordingtothePHPvalidate-email-filter.extendingthetestlongeruntilwereachtheright.com</a> '
    + 'domain with many dashes <a href="mailto:sjjssjdjdjdjdjdjjeiwiwiwowkdjdjdieikdjfidekjcjdkekejdcjdkeekcjab@asj-j-s-sjdjdjdjd-jdjjeiwiwiwowkdjdjdieikdjfidekjcjdkekejdcjdke.com.ab.net.aa.bb.cc.dd.ee">sjjssjdjdjdjdjdjjeiwiwiwowkdjdjdieikdjfidekjcjdkekejdcjdkeekcjab@asj-j-s-sjdjdjdjd-jdjjeiwiwiwowkdjdjdieikdjfidekjcjdkekejdcjdke.com.ab.net.aa.bb.cc.dd.ee</a> '
    + ' how about a domain with repeated labels of 63 chars <a href="mailto:test@asjjssjdjdjdjdjdjjeiwiwiwowkdjdjdieikdjfidekasgasgasgasgashfnfn.asjjssjdjdjdjdjdjjeiwiwiwowkdjdjdieikdjfidekasgasgasgasgashfnfn.asjjssjdjdjdjdjdjjeiwiwiwowkdjdjdieikdjfidekasgasgasgasgashfnfn.com">test@asjjssjdjdjdjdjdjjeiwiwiwowkdjdjdieikdjfidekasgasgasgasgashfnfn.asjjssjdjdjdjdjdjjeiwiwiwowkdjdjdieikdjfidekasgasgasgasgashfnfn.asjjssjdjdjdjdjdjjeiwiwiwowkdjdjdieikdjfidekasgasgasgasgashfnfn.com</a> '
    + 'max length email with italics '
    + '<em><a href="mailto:averylongaddresspartthatalmostwillreachthelimitofcharsperaddress@nowwejustneedaverylongdomainpartthatwill.reachthetotallengthlimitforthewholeemailaddress.whichis254charsaccordingtothePHPvalidate-email-filter.extendingthetestlongeruntilwereachtheright.com">averylongaddresspartthatalmostwillreachthelimitofcharsperaddress@nowwejustneedaverylongdomainpartthatwill.reachthetotallengthlimitforthewholeemailaddress.whichis254charsaccordingtothePHPvalidate-email-filter.extendingthetestlongeruntilwereachtheright.com</a></em> '
    + ' xn-- style domain <a href="mailto:test@xn--diseolatinoamericano-76b.com">test@xn--diseolatinoamericano-76b.com</a> '
    + 'or a more complex case where we need to determine where to apply italics markdown '
    + '<em><a href="mailto:email@test.com">email@test.com</a><br />'
    + '<a href="mailto:_email2@test.com">_email2@test.com</a><br /><br />'
    + '<a href="mailto:email3@test.com">email3@test.com</a></em> '
    + 'some unusual, but valid prefixes <a href="mailto:-test@example.com">-test@example.com</a> '
    + ' and <a href="mailto:_test@example.com">_test@example.com</a> '
    + 'a max length email enclosed in brackets '
    + '(<a href="mailto:averylongaddresspartthatalmostwillreachthelimitofcharsperaddress@nowwejustneedaverylongdomainpartthatwill.reachthetotallengthlimitforthewholeemailaddress.whichis254charsaccordingtothePHPvalidate-email-filter.extendingthetestlongeruntilwereachtheright.com">averylongaddresspartthatalmostwillreachthelimitofcharsperaddress@nowwejustneedaverylongdomainpartthatwill.reachthetotallengthlimitforthewholeemailaddress.whichis254charsaccordingtothePHPvalidate-email-filter.extendingthetestlongeruntilwereachtheright.com</a>) '
    + 'max length email with ellipsis ending '
    + '<a href="mailto:averylongaddresspartthatalmostwillreachthelimitofcharsperaddress@nowwejustneedaverylongdomainpartthatwill.reachthetotallengthlimitforthewholeemailaddress.whichis254charsaccordingtothePHPvalidate-email-filter.extendingthetestlongeruntilwereachtheright.com">averylongaddresspartthatalmostwillreachthelimitofcharsperaddress@nowwejustneedaverylongdomainpartthatwill.reachthetotallengthlimitforthewholeemailaddress.whichis254charsaccordingtothePHPvalidate-email-filter.extendingthetestlongeruntilwereachtheright.com</a>... '
    + 'try a markdown link with a valid max-length email '
    + '<a href="mailto:sjjssjdjdjdjdjdjjeiwiwiwowkdjdjdieikdjfidekjcjdkekejdcjdkeekcjab@asjjssjdjdjdjdjdjjeiwiwiwowkdjdjdieikdjfidekjcjdkekejdcjdkeekcj.com.a.aa.asjjssjdjdjdjdjdjjeiwiwiwowkdjdjdieikdjfidekjcjdkekejdcjdkeekcj.asjjssjdjdjdjdjdjjeiwiwiwowkdjdjdieikdjfidekjcjasfff">text</a>';
    expect(parser.replace(testString)).toBe(result);
});

test('Test markdown replacement for invalid emails', () => {
    const testString = 'Replace the valid email part within a string '
    + '.test@example.com '
    + '$test@gmail.com '
    + 'test..new@example.com '
    + 'Some chars that are not allowed within emails '
    + 'test{@example.com '
    + 'domain length over limit test@averylongdomainpartoftheemailthatwillgooverthelimitasitismorethan63chars.com '
    + 'address over limit averylongaddresspartoftheemailthatwillgovoerthelimitasitismorethan64chars@example.com '
    + 'overall length too long '
    + 'sjjssjdjdjdjdjdjjeiwiwiwowkdjdjdieikdjfidekjcjdkekejdcjdkeekcjab@asjjssjdjdjdjdjdjjeiwiwiwowkdjdjdieikdjfidekjcjdkekejdcjdkeekcj.com.a.aa.asjjssjdjdjdjdjdjjeiwiwiwowkdjdjdieikdjfidekjcjdkekejdcjdkeekcj.asjjssjdjdjdjdjdjjeiwiwiwowkdjdjdieikdjfidekjcjasfffa '
    + 'invalid domain start/end '
    + 'test@example-.com '
    + 'test@-example-.com '
    + 'test@example.a '
    + '[text](sjjssjdjdjdjdjdjjeiwiwiwowkdjdjdieikdjfidekjcjdkekejdcjdkeekcjab@asjjssjdjdjdjdjdjjeiwiwiwowkdjdjdieikdjfidekjcjdkekejdcjdkeekcj.com.a.aa.asjjssjdjdjdjdjdjjeiwiwiwowkdjdjdieikdjfidekjcjdkekejdcjdkeekcj.asjjssjdjdjdjdjdjjeiwiwiwowkdjdjdieikdjfidekjcjasfffa)';
    const result = 'Replace the valid email part within a string '
    + '.<a href="mailto:test@example.com">test@example.com</a> '
    + '$<a href="mailto:test@gmail.com">test@gmail.com</a> '
    + 'test..<a href="mailto:new@example.com">new@example.com</a> '
    + 'Some chars that are not allowed within emails '
    + 'test{@example.com '
    + 'domain length over limit test@averylongdomainpartoftheemailthatwillgooverthelimitasitismorethan63chars.com '
    + 'address over limit averylongaddresspartoftheemailthatwillgovoerthelimitasitismorethan64chars@example.com '
    + 'overall length too long '
    + 'sjjssjdjdjdjdjdjjeiwiwiwowkdjdjdieikdjfidekjcjdkekejdcjdkeekcjab@asjjssjdjdjdjdjdjjeiwiwiwowkdjdjdieikdjfidekjcjdkekejdcjdkeekcj.com.a.aa.asjjssjdjdjdjdjdjjeiwiwiwowkdjdjdieikdjfidekjcjdkekejdcjdkeekcj.asjjssjdjdjdjdjdjjeiwiwiwowkdjdjdieikdjfidekjcjasfffa '
    + 'invalid domain start/end '
    + 'test@example-.com '
    + 'test@-example-.com '
    + 'test@example.a '
    + '[text](sjjssjdjdjdjdjdjjeiwiwiwowkdjdjdieikdjfidekjcjdkekejdcjdkeekcjab@asjjssjdjdjdjdjdjjeiwiwiwowkdjdjdieikdjfidekjcjdkekejdcjdkeekcj.com.a.aa.asjjssjdjdjdjdjdjjeiwiwiwowkdjdjdieikdjfidekjcjdkekejdcjdkeekcj.asjjssjdjdjdjdjdjjeiwiwiwowkdjdjdieikdjfidekjcjasfffa)';
    expect(parser.replace(testString)).toBe(result);
});

@aldo-expensify
Copy link
Contributor

Failing to add @aimane-chnaif as reviewer 🤷

@aimane-chnaif
Copy link
Contributor

@jjcoffee please take first round of review and test

Copy link
Contributor

@aimane-chnaif aimane-chnaif left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Antasel please fix lint. Also, as agreed, we can skip the case of _ prefixed email inside italic markdown. This will make code much simpler.

@Antasel
Copy link
Contributor Author

Antasel commented Aug 17, 2023

@aimane-chnaif
I've fixed lint

as agreed, we can skip the case of _ prefixed email inside italic markdown. This will make code much simpler.

Also restored autoemail & quote rule's order and some tweaks on Italic rule
according to the change, autotest cases are updated

@jjcoffee
Copy link
Contributor

@aimane-chnaif Can you clarify what you mean by the case of "_ prefixed email inside italic markdown"? Do you mean:

  1. Email with leading underscore (_test@example.com) wrapped in italic markdown: __test@example.com_
  2. Normal email wrapped in italic markdown: _test@example.com_

@@ -102,10 +102,10 @@ test('Test markdown replacement for emails wrapped in bold/strikethrough/italic
expect(parser.replace(testInput)).toBe('<strong><a href="mailto:abc@gmail.com">abc@gmail.com</a></strong>');

testInput = '_abc@gmail.com_';
expect(parser.replace(testInput)).toBe('<em><a href="mailto:abc@gmail.com">abc@gmail.com</a></em>');
expect(parser.replace(testInput)).toBe('<a href="mailto:_abc@gmail.com">_abc@gmail.com</a>_');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this would be expected behaviour and would result in a regression. If you wrap a normal email (abc@gmail.com) in italic markdown it should just be italicised and linked. cc @aimane-chnaif

Copy link
Contributor

@aimane-chnaif aimane-chnaif Aug 17, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. If we just change parsing order of autoEmail and italic, should this be fixed?

@Antasel Let's add all of these in test case. Github markdown seems to have different logic

Copy link
Contributor Author

@Antasel Antasel Aug 17, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Antasel Let's add all of these in test case. Github markdown seems to have different logic

those cases are already covered in Expensify/App#17387 (comment)
so there is no need to restore the changed order of autoemail and italic rule, just leave it as it is.
I will revert last commit.
How you think ? @jjcoffee

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Antasel Yes I think that's the only way to get the behaviour we want here. I don't think it's possible to isolate a fix for _abc@gmail.com_ from __abc@gmail.com_, which is what @aimane-chnaif was initially talking about.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@aimane-chnaif you meant "the case of _ prefixed email inside italic markdown can be skipped" is following case ?

__abc@gmail.com_ -> _abc@gmail.com
after parsed, underscore is not contained in email
if so, it can be done by only moving autoemail rule after italic rule. no need extra tweak in italic rule
cc: @aimane-chnaif

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am fine with it. @jjcoffee you too?

Copy link
Contributor

@jjcoffee jjcoffee Aug 17, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Antasel Sorry I'm not clear, what would the result be for __abc@gmail.com_?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That expected to be parsed as _abc@gmail.com but _abc@gmail.com actually, @Antasel you meant correct?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@aimane-chnaif I thought you wanted _<em><a href="mailto:abc@gmail.com">abc@gmail.com</a></em> after parsed.
currently with Expensify/App#17387 (comment), it is parsed as <em><a href="mailto:_abc@gmail.com">_abc@gmail.com</a></em>

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's what I don't care too much. Either result is fine to me


testInput = '~*_abc@gmail.com_*~';
expect(parser.replace(testInput)).toBe('<del><strong><em><a href="mailto:abc@gmail.com">abc@gmail.com</a></em></strong></del>');
expect(parser.replace(testInput)).toBe('<del><strong><a href="mailto:_abc@gmail.com">_abc@gmail.com</a>_</strong></del>');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, I don't think this is the expected behaviour.

@jjcoffee
Copy link
Contributor

@Antasel Let's add some of the markdown tests from ExpensiMark-HTML-test.js into the Tests section of the PR so it's easier to visualise how it will work for markdown cases. For example _abc@gmail.com_ would be useful, maybe some of the multiline ones too?

@jjcoffee
Copy link
Contributor

@Antasel Please can you fix the lint issues again.

@aimane-chnaif
Copy link
Contributor

@Antasel I just noticed that your commit signature is unverified.

@jjcoffee
Copy link
Contributor

@Antasel See here at point 10. It might be easiest to close this PR and open a new one where you make new signed commits, then you'll get a "Verified" badge here:
image

@Antasel
Copy link
Contributor Author

Antasel commented Aug 17, 2023

thanks, I will do it now,
but I remember I followed it before

@jjcoffee
Copy link
Contributor

The result is not correct for .test.new@example.com:

image

Also doesn't work with it on its own. Can you check @Antasel?

@aimane-chnaif
Copy link
Contributor

The result is not correct for .test.new@example.com:

image

Also doesn't work with it on its own. Can you check @Antasel?

This is more like a bug in Expensify/App#16762.
If it's not quick fix, can be out of scope.
As it is parsed as email in current app which is wrong, I won't say this is regression.

@jjcoffee
Copy link
Contributor

jjcoffee commented Aug 17, 2023

@aimane-chnaif Are you saying it's incorrect to parse test.new@example.com as an email, or just the one with the leading dot? The former is correct as far as I know! Current production:
image

@Antasel
Copy link
Contributor Author

Antasel commented Aug 17, 2023

Screenshot_1
@jjcoffee I am getting correctly

@Antasel
Copy link
Contributor Author

Antasel commented Aug 17, 2023

image
@aimane-chnaif commit signature has been verified

@aimane-chnaif
Copy link
Contributor

@Antasel is it now ready for review?

@Antasel
Copy link
Contributor Author

Antasel commented Aug 17, 2023

we need to check why @jjcoffee is getting incorrectly

@Antasel
Copy link
Contributor Author

Antasel commented Aug 17, 2023

@jjcoffee which platform did you check it on ?

@jjcoffee
Copy link
Contributor

@Antasel I think all your commits need to be signed - you've only signed the new one. I think that's correct right @aimane-chnaif?

I will retest soon - I might have some cached node_modules messing things up 😄

@aimane-chnaif
Copy link
Contributor

@Antasel there's still unsigned commit. All commits should be signed

Screen Shot 2023-08-18 at 12 00 12 AM

@jjcoffee
Copy link
Contributor

@Antasel It fails when I add it as a test, so it must be an issue with the regex:

image

@aimane-chnaif
Copy link
Contributor

'Maximum Regex stack depth reached'

This was reported before and now marked as fixed - Expensify/App#21266

@jjcoffee
Copy link
Contributor

@Antasel Can you try merging main in case the issue is resolved by the PR @aimane-chnaif mentions?

@Antasel
Copy link
Contributor Author

Antasel commented Aug 23, 2023

noted, let me try

@Antasel
Copy link
Contributor Author

Antasel commented Aug 23, 2023

@jjcoffee
my test was on the main where the PR had been merged

@Antasel
Copy link
Contributor Author

Antasel commented Aug 23, 2023

@Antasel I'm confused, are you saying that autolink is trying to parse the domain part of this email:

yes, sure
if we disable autolink rule, no error is happened

@Antasel
Copy link
Contributor Author

Antasel commented Aug 23, 2023

@jjcoffee @aimane-chnaif
you can try at your side.
on latest version of expensify-common, please limit domain level length to 10 on MARKDOWN_EMAIL regex, then autolink rule is not parsing even simple invalid email T@aaaaaaaaaaaa.aaaaaaaaaaaa.aaaaa , causing the error.
maybe #559 's contributor should check it again

@Antasel
Copy link
Contributor Author

Antasel commented Aug 23, 2023

Screenshot_1
I am getting this warning, but ios app gets stuck for 10 seconds

@Antasel
Copy link
Contributor Author

Antasel commented Aug 24, 2023

@aimane-chnaif @jjcoffee
I've posted more reasonable bug report (Expensify/App#21266 (comment)) on #21266 .
The issue is out of current PR's scope.
I think we can move forward.

@jjcoffee
Copy link
Contributor

@Antasel Agree it looks like a separate issue. From what I understand, any invalid email (like a super long email that's over the length limits) will not be parsed by the email rule so the autolinker tries to parse it and fails because of issues with the autolink rule. I think it's worth reporting this as a separate bug on Slack.

I think next steps here are to add some additional manual tests:

  1. Try to login with an invalid email + an email at the limit (e.g. just below length limit)
  2. Navigate to Settings > Profile > Contact Method > New Contact Method, try an invalid email

I will run some platform tests today, but otherwise it's ready for review. We're running close to the 9 day limit for merging, so let's try and get this merged today! cc @aimane-chnaif

@Antasel
Copy link
Contributor Author

Antasel commented Aug 24, 2023

@jjcoffee noted
Could you please make video of iOS, mobile safari, desktop Platform to save time, whilst testing ?

@jjcoffee
Copy link
Contributor

jjcoffee commented Aug 24, 2023

@Antasel Actually we can ignore tests for sign-in as if FE validates, BE will still return that it's an invalid email (the error message is just slightly different). Also, there's now(?) a length limit on all email input fields, so you can't enter an email >254 chars anyway 😄

Can you add Navigate to Settings > Profile > Contact Method > New Contact Method, try an invalid email as a test to the description here please? Maybe specifically for a@a.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijkl

@Antasel
Copy link
Contributor Author

Antasel commented Aug 24, 2023

Can you add Navigate to Settings > Profile > Contact Method > New Contact Method, try an invalid email as a test to the description here please? Maybe specifically for a@a.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijkl

I've added it and updated demo video.
now Could we move forward ?
@aimane-chnaif @jjcoffee

@jjcoffee
Copy link
Contributor

@Antasel Thanks! Please also remove the // Overall length too long item in the invalid emails list since this will always fail the test on iOS.

@jjcoffee
Copy link
Contributor

jjcoffee commented Aug 24, 2023

Tests well, just waiting for the Android build. I think this is ready for review @aimane-chnaif - please prioritise as we're getting close to the 9 day limit. Thanks!

Screenshots/Videos

Web

New Contact method

email-regex-chrome-desktop-contact-method-2023-08-24_15.32.58.mp4

Markdown

email-regex-chrome-desktop-markdown-2023-08-24_15.34.03.mp4
Mobile Web - Chrome

New Contact method

android-chrome-contact-methods.mp4

Markdown - valid

android-chrome-markdown.mp4

Markdown - invalid

Uploading android-chrome-markdown-invalid.mp4…

Mobile Web - Safari
email-regex-ios-safari-2023-08-24_17.08.50.mp4
Desktop
email-regex-mac-desktop-2023-08-24_17.15.02.mp4
iOS

New Contact method

email-regex-ios-native-contact-method-2023-08-24_17.26.22.mp4

Markdown

email-regex-ios-native-markdown-2023-08-24_16.55.48.mp4
Android
email-regex-android-2023-08-25_14.35.53.mp4

@Antasel
Copy link
Contributor Author

Antasel commented Aug 24, 2023

@Antasel Thanks! Please also remove the // Overall length too long item in the invalid emails list since this will always fail the test on iOS.

It's removed

@jjcoffee
Copy link
Contributor

Android test added! @aimane-chnaif Do you think you can review today?

@aimane-chnaif
Copy link
Contributor

This is not expected. Italicize should not happen when there's non-blank character before starting _ and after ending _

Screenshot 2023-08-25 at 1 38 05 PM

@jjcoffee
Copy link
Contributor

jjcoffee commented Aug 25, 2023

I guess this is to do with putting the autoEmail rule after the italic rule, since a~*_b@gmail.com would otherwise be parsed by autoEmail as this being the email part: _b@gmail.com. cc @Antasel

@jjcoffee
Copy link
Contributor

@aimane-chnaif Actually this is current behaviour on main, so unrelated to this PR:
image

@aimane-chnaif
Copy link
Contributor

Nvm. No matter this is bug or not, I think this can be out of scope as already happens on staging:

Screenshot 2023-08-25 at 1 48 18 PM

@aimane-chnaif
Copy link
Contributor

Screenshots/Videos

Web
valid.emails.mov
invalid.emails.mov
contact.method.mov
Mobile Web - Chrome
mchrome.mov
Mobile Web - Safari
msafari.mov
Desktop
desktop.mov
iOS
ios.mov
Android
android.mov

Copy link
Contributor

@aimane-chnaif aimane-chnaif left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!
@NikkiWines all yours

Copy link
Contributor

@NikkiWines NikkiWines left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Amazing 🤩 one very minor question but otherwise looks good.

Comment on lines 134 to 104
expect(Str.isValidEmail('test@gmail')).toBeFalsy();
expect(Str.isValidEmail('@gmail.com')).toBeFalsy();
expect(Str.isValidEmail('usernamelongerthan64charactersshouldnotworkaccordingtorfc822whichisusedbyphp@gmail.com')).toBeFalsy();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All of these should still be invalid, right? Why not retain these tests?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Though looks like at least the last one is already covered by the test on 184

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right. They are not intentionally removed but maybe overwritten since these are recently added in #562 and #563 after @Antasel prepared these cases for testing.
@Antasel let's add these back. I just tested these cases and still work fine.
And also pull main

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@NikkiWines @aimane-chnaif
The cases have been restored.

@NikkiWines NikkiWines merged commit e63d06e into Expensify:main Aug 29, 2023
3 checks passed
Comment on lines +142 to +165
{
/**
* Use \b in this case because it will match on words, letters,
* and _: https://www.rexegg.com/regex-boundaries.html#wordboundary
* The !_blank is to prevent the `target="_blank">` section of the
* link replacement from being captured Additionally, something like
* `\b\_([^<>]*?)\_\b` doesn't work because it won't replace
* `_https://www.test.com_`
* Use [\s\S]* instead of .* to match newline
*/
name: 'italic',
regex: /(\b_+|\b)(?!_blank")_((?![\s_])[\s\S]*?[^\s_])_(?![^\W_])(?![^<]*(<\/pre>|<\/code>|<\/a>|<\/mention-user>|_blank))/g,

// We want to add extraLeadingUnderscores back before the <em> tag unless textWithinUnderscores starts with valid email
replacement: (match, extraLeadingUnderscores, textWithinUnderscores) => {
if (textWithinUnderscores.includes('<pre>') || this.containsNonPairTag(textWithinUnderscores)) {
return match;
}
if (String(textWithinUnderscores).match(`^${CONST.REG_EXP.MARKDOWN_EMAIL}`)) {
return `<em>${extraLeadingUnderscores}${textWithinUnderscores}</em>`;
}
return `${extraLeadingUnderscores}<em>${textWithinUnderscores}</em>`;
},
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We used to have the quote rule run before the italic rule. Changing that order caused an invalid markdown rendering for cases like:

_Msg then a
> quote_

Coming from Expensify/App#26941

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants