import { LinkParser } from '../inline'; import { textlink, medialink } from './link'; import { union, some } from '../../combinator'; import { Input, input } from '../context'; import { inspect } from '../../debug.test'; describe('Unit: parser/inline/link', () => { describe('link', () => { const link: LinkParser = union([ medialink, textlink, ]); const parser = some(link); it('xss', () => { assert.deepStrictEqual(inspect(parser, input('[]{javascript:alert}')), [['javascript:alert'], '']); assert.deepStrictEqual(inspect(parser, input('[]{vbscript:alert}')), [['vbscript:alert'], '']); assert.deepStrictEqual(inspect(parser, input('[]{data:text/html;base64,PHNjcmlwdD5hbGVydCgnWFNTJyk8L3NjcmlwdD4K}')), [['data:text/html;base64,PHNjcmlwdD5hbGVydCgnWFNTJyk8L3NjcmlwdD4K'], '']); assert.deepStrictEqual(inspect(parser, input('[]{any:alert}')), [['any:alert'], '']); assert.deepStrictEqual(inspect(parser, input('[]{"}')), [['"'], '']); assert.deepStrictEqual(inspect(parser, input('[]{<}')), [['<'], '']); assert.deepStrictEqual(inspect(parser, input('[]{\\}')), [['\\'], '']); assert.deepStrictEqual(inspect(parser, input('[]{\\"}')), [['\\"'], '']); assert.deepStrictEqual(inspect(parser, input('[]{\\<}')), [['\\<'], '']); }); it('fishing', () => { assert.deepStrictEqual(inspect(parser, input('[http://host]{http://evil}')), [['http://host'], '']); assert.deepStrictEqual(inspect(parser, input('[\\http://host]{http://evil}')), [['http://host'], '']); assert.deepStrictEqual(inspect(parser, input('[https://host]{http://host}')), [['https://host'], '']); assert.deepStrictEqual(inspect(parser, input('[[]{http://host}.com]{http://host}')), [['[]{http://host}.com'], '']); assert.deepStrictEqual(inspect(parser, input('[[]{http://host/a}b]{http://host/ab}')), [['[]{http://host/a}b'], '']); assert.deepStrictEqual(inspect(parser, input('{http%73://host}')), [['http%73://host'], '']); assert.deepStrictEqual(inspect(parser, input('{http://a%C3%A1}')), [['http://a%C3%A1'], '']); assert.deepStrictEqual(inspect(parser, input('[http://á]{http://evil}')), [['http://á'], '']); assert.deepStrictEqual(inspect(parser, input('[xxx://á]{http://evil}')), [['xxx://á'], '']); assert.deepStrictEqual(inspect(parser, input('[mailto:á]{http://evil}')), [['mailto:á'], '']); assert.deepStrictEqual(inspect(parser, input('[file:///]{http://evil}')), [['file:///'], '']); assert.deepStrictEqual(inspect(parser, input('[.http://á]{http://evil}')), [['.http://á'], '']); assert.deepStrictEqual(inspect(parser, input('[0987654321]{tel:1234567890}')), [['0987654321'], '']); assert.deepStrictEqual(inspect(parser, input('[1234567890-]{tel:1234567890}')), [['1234567890-'], '']); assert.deepStrictEqual(inspect(parser, input('[-1234567890]{tel:1234567890}')), [['-1234567890'], '']); assert.deepStrictEqual(inspect(parser, input('[123456789a]{tel:1234567890}')), [['123456789a'], '']); assert.deepStrictEqual(inspect(parser, input('[1234567890]{tel:ttel:1234567890}')), [['1234567890'], '']); assert.deepStrictEqual(inspect(parser, input('[#a]{b}')), [['#a'], '']); assert.deepStrictEqual(inspect(parser, input('[\\#a]{b}')), [['#a'], '']); assert.deepStrictEqual(inspect(parser, input('[c #a]{b}')), [['c #a'], '']); assert.deepStrictEqual(inspect(parser, input('[c \\#a]{b}')), [['c #a'], '']); assert.deepStrictEqual(inspect(parser, input('[]{#a}')), [['#a'], '']); assert.deepStrictEqual(inspect(parser, input('[@a]{b}')), [['@a'], '']); assert.deepStrictEqual(inspect(parser, input('[\\@a]{b}')), [['@a'], '']); assert.deepStrictEqual(inspect(parser, input('[c @a]{b}')), [['c @a'], '']); assert.deepStrictEqual(inspect(parser, input('[c \\@a]{b}')), [['c @a'], '']); assert.deepStrictEqual(inspect(parser, input('[]{@a}')), [['@a'], '']); }); it('invalid', () => { assert.deepStrictEqual(inspect(parser, input('')), undefined); assert.deepStrictEqual(inspect(parser, input('{}')), undefined); assert.deepStrictEqual(inspect(parser, input('[{b}')), undefined); assert.deepStrictEqual(inspect(parser, input('[]')), undefined); assert.deepStrictEqual(inspect(parser, input('[]{}')), undefined); assert.deepStrictEqual(inspect(parser, input('[]{ }')), [['[]{ }'], '']); assert.deepStrictEqual(inspect(parser, input('[]{ }')), undefined); assert.deepStrictEqual(inspect(parser, input('[]{ }')), undefined); assert.deepStrictEqual(inspect(parser, input('[]{{}')), undefined); assert.deepStrictEqual(inspect(parser, input('[]{}}')), undefined); assert.deepStrictEqual(inspect(parser, input('[]{{}}')), undefined); assert.deepStrictEqual(inspect(parser, input('[]{{b}}')), undefined); assert.deepStrictEqual(inspect(parser, input('[]{b\nc}')), [['[]{b'], '\nc}']); assert.deepStrictEqual(inspect(parser, input('[]{b\\\nc}')), [['[]{b\\'], '\nc}']); assert.deepStrictEqual(inspect(parser, input('[]{ b}')), [['[]{ b}'], '']); assert.deepStrictEqual(inspect(parser, input('[]{ b\n}')), [['[]{ b'], '\n}']); assert.deepStrictEqual(inspect(parser, input('[ ]{}')), undefined); assert.deepStrictEqual(inspect(parser, input('[ ]{ }')), undefined); assert.deepStrictEqual(inspect(parser, input('[ ]{b}')), undefined); assert.deepStrictEqual(inspect(parser, input('[ ]{b}')), undefined); assert.deepStrictEqual(inspect(parser, input('[ a]{b}')), undefined); assert.deepStrictEqual(inspect(parser, input('[ a ]{b}')), undefined); assert.deepStrictEqual(inspect(parser, input('[\\ a]{b}')), undefined); assert.deepStrictEqual(inspect(parser, input('[ \\ a]{b}')), undefined); assert.deepStrictEqual(inspect(parser, input('[\n]{b}')), undefined); assert.deepStrictEqual(inspect(parser, input('[\\ ]{b}')), undefined); assert.deepStrictEqual(inspect(parser, input('[\\\n]{b}')), undefined); assert.deepStrictEqual(inspect(parser, input('[ ]{b}')), undefined); assert.deepStrictEqual(inspect(parser, input('[[]{b}')), undefined); assert.deepStrictEqual(inspect(parser, input('[]]{b}')), undefined); assert.deepStrictEqual(inspect(parser, input('[a]{}')), undefined); assert.deepStrictEqual(inspect(parser, input('[a\nb]{b}')), undefined); assert.deepStrictEqual(inspect(parser, input('[a\\\nb]{b}')), undefined); assert.deepStrictEqual(inspect(parser, input('[]{b}')), undefined); assert.deepStrictEqual(inspect(parser, input('[*a\nb*]{/}')), undefined); assert.deepStrictEqual(inspect(parser, input('[http://host]{http://host}')), [['http://host'], '']); assert.deepStrictEqual(inspect(parser, input('[]{ttp://host}')), [['ttp://host'], '']); assert.deepStrictEqual(inspect(parser, input('[]{http://[::ffff:0:0%1]}')), [['http://[::ffff:0:0%1]'], '']); assert.deepStrictEqual(inspect(parser, input('[]{http://[::ffff:0:0/96]}')), [['http://[::ffff:0:0/96]'], '']); assert.deepStrictEqual(inspect(parser, input('[]{^/.}')), [[`^/.`], '']); assert.deepStrictEqual(inspect(parser, input('[]{^/..}')), [[`^/..`], '']); assert.deepStrictEqual(inspect(parser, input('[]{^/../}')), [[`^/../`], '']); assert.deepStrictEqual(inspect(parser, input('[]{^/../..}')), [[`^/../..`], '']); assert.deepStrictEqual(inspect(parser, input('[]{^/../b}')), [[`^/../b`], '']); assert.deepStrictEqual(inspect(parser, input('[]{^/../b/..}')), [[`^/../b/..`], '']); assert.deepStrictEqual(inspect(parser, input(' []{b}')), undefined); assert.deepStrictEqual(inspect(parser, input('![]{/}')), undefined); }); it('basic', () => { assert.deepStrictEqual(inspect(parser, input('[]{b}')), [['b'], '']); assert.deepStrictEqual(inspect(parser, input('[]{b }')), [['b'], '']); assert.deepStrictEqual(inspect(parser, input('[]{b }')), [['[]{b'], ' }']); assert.deepStrictEqual(inspect(parser, input('[]{ b }')), [['b'], '']); assert.deepStrictEqual(inspect(parser, input('[]{ b }')), [['[]{ b'], ' }']); assert.deepStrictEqual(inspect(parser, input('[]{ b }')), undefined); assert.deepStrictEqual(inspect(parser, input('[]{ b }')), undefined); assert.deepStrictEqual(inspect(parser, input('[]{"}')), [[`"`], '']); assert.deepStrictEqual(inspect(parser, input('[]{"}"}')), [[`"`], '"}']); assert.deepStrictEqual(inspect(parser, input('[]{\\}')), [[`\\`], '']); assert.deepStrictEqual(inspect(parser, input('[]{\\ }')), [[`\\`], '']); assert.deepStrictEqual(inspect(parser, input('[]{\\b}')), [[`\\b`], '']); assert.deepStrictEqual(inspect(parser, input('[]{?b=c+d&\\#}')), [['?b=c+d&\\#'], '']); assert.deepStrictEqual(inspect(parser, input('[]{?©}')), [['?&copy;'], '']); assert.deepStrictEqual(inspect(parser, input('[]{#}')), [['#'], '']); assert.deepStrictEqual(inspect(parser, input('[]{#b}')), [['#b'], '']); assert.deepStrictEqual(inspect(parser, input('[]{./b}')), [['./b'], '']); assert.deepStrictEqual(inspect(parser, input('[]{^/b}')), [[`^/b`], '']); assert.deepStrictEqual(inspect(parser, input('[]{^/b?/../}')), [[`^/b?/../`], '']); assert.deepStrictEqual(inspect(parser, input('[]{^/b#/../}')), [[`^/b#/../`], '']); assert.deepStrictEqual(inspect(parser, input('[]{^/b}', new Input({ host: new URL('/dir', location.origin) }))), [[`^/b`], '']); assert.deepStrictEqual(inspect(parser, input('[]{^/b}', new Input({ host: new URL('/dir/', location.origin) }))), [[`^/b`], '']); assert.deepStrictEqual(inspect(parser, input('[]{^/b}', new Input({ host: new URL('/folder/doc.md', location.origin) }))), [[`^/b`], '']); assert.deepStrictEqual(inspect(parser, input('[]{^/b}', new Input({ host: new URL('/folder/doc.md/', location.origin) }))), [[`^/b`], '']); assert.deepStrictEqual(inspect(parser, input('[]{^/b}', new Input({ host: new URL('/.file', location.origin) }))), [[`^/b`], '']); assert.deepStrictEqual(inspect(parser, input('[]{^/b}', new Input({ host: new URL('/0.0a', location.origin) }))), [[`^/b`], '']); assert.deepStrictEqual(inspect(parser, input('[]{^/b}', new Input({ host: new URL('/0.a0', location.origin) }))), [[`^/b`], '']); assert.deepStrictEqual(inspect(parser, input('[]{^/b}', new Input({ host: new URL('/0.0', location.origin) }))), [[`^/b`], '']); assert.deepStrictEqual(inspect(parser, input('[]{^/b}', new Input({ host: new URL('/0.0,0.0,0z', location.origin) }))), [[`^/b`], '']); assert.deepStrictEqual(inspect(parser, input('[a ]{b}')), [['a'], '']); assert.deepStrictEqual(inspect(parser, input('[a ]{b}')), [['a'], '']); assert.deepStrictEqual(inspect(parser, input('[a]{b}')), [['a'], '']); assert.deepStrictEqual(inspect(parser, input('[a]{#}')), [['a'], '']); assert.deepStrictEqual(inspect(parser, input('[a]{#b}')), [['a'], '']); assert.deepStrictEqual(inspect(parser, input('[a b]{c}')), [['a b'], '']); assert.deepStrictEqual(inspect(parser, input(`[]{?#${encodeURIComponent(':/[]{}<>?#=& ')}}`)), [['?#%3A%2F[]{}<>%3F%23%3D%26%20'], '']); assert.deepStrictEqual(inspect(parser, input('{b}')), [['b'], '']); assert.deepStrictEqual(inspect(parser, input('{ ][ }')), [[']['], '']); assert.deepStrictEqual(inspect(parser, input('{ }{ }')), [['}{'], '']); assert.deepStrictEqual(inspect(parser, input('{Http://host}')), [['Http://host'], '']); }); it('tel', () => { assert.deepStrictEqual(inspect(parser, input('{tel:1234567890}')), [[`tel:1234567890`], '']); assert.deepStrictEqual(inspect(parser, input('{Tel:1234567890}')), [[`Tel:1234567890`], '']); assert.deepStrictEqual(inspect(parser, input('{tel:+1234567890}')), [[`tel:+1234567890`], '']); assert.deepStrictEqual(inspect(parser, input('{tel:+12-345-67-890}')), [[`tel:+12-345-67-890`], '']); assert.deepStrictEqual(inspect(parser, input('[1234567890]{tel:1234567890}')), [[`1234567890`], '']); assert.deepStrictEqual(inspect(parser, input('[1234567890]{tel:12-3456-7890}')), [[`1234567890`], '']); assert.deepStrictEqual(inspect(parser, input('[12-3456-7890]{tel:1234567890}')), [[`12-3456-7890`], '']); assert.deepStrictEqual(inspect(parser, input('[+12-34567-890]{tel:+12-345-67890}')), [[`+12-34567-890`], '']); }); it('media', () => { assert.deepStrictEqual(inspect(parser, input('[![]{a}]{a}')), [['a'], '']); assert.deepStrictEqual(inspect(parser, input('[![]{a}]{b}')), [['a'], '']); assert.deepStrictEqual(inspect(parser, input('[![]{a} ]{b}')), [['![]{a}'], '']); assert.deepStrictEqual(inspect(parser, input('[![]{a}![]{a}]{b}')), [['![]{a}![]{a}'], '']); assert.deepStrictEqual(inspect(parser, input('[[![]{a}]{b}]{c}')), [['[![]{a}]{b}'], '']); assert.deepStrictEqual(inspect(parser, input('[!http://host]{b}')), [['http://host'], '']); }); it('nest', () => { assert.deepStrictEqual(inspect(parser, input('[*]{/}')), [['*'], '']); assert.deepStrictEqual(inspect(parser, input('[\\[]{/}')), [['['], '']); assert.deepStrictEqual(inspect(parser, input('[\\]]{/}')), [[']'], '']); assert.deepStrictEqual(inspect(parser, input('[[]{a}]{a}')), [['[]{a}'], '']); assert.deepStrictEqual(inspect(parser, input('[[]{a}]{b}')), [['[]{a}'], '']); assert.deepStrictEqual(inspect(parser, input('[[![]{a}]{a}]{a}')), [['[![]{a}]{a}'], '']); assert.deepStrictEqual(inspect(parser, input('[[![]{a}]{a}]{b}')), [['[![]{a}]{a}'], '']); assert.deepStrictEqual(inspect(parser, input('[[![]{a}]{b}]{b}')), [['[![]{a}]{b}'], '']); assert.deepStrictEqual(inspect(parser, input('[((a))]{b}')), [['((a))'], '']); assert.deepStrictEqual(inspect(parser, input('[[[a]]]{b}')), [['[[a]]'], '']); assert.deepStrictEqual(inspect(parser, input('[#a]{b}')), [['#a'], '']); assert.deepStrictEqual(inspect(parser, input('[@a]{b}')), [['@a'], '']); assert.deepStrictEqual(inspect(parser, input('[@a@b]{c}')), [['@a@b'], '']); assert.deepStrictEqual(inspect(parser, input('[a@b]{c}')), [['a@b'], '']); assert.deepStrictEqual(inspect(parser, input('[==a==]{b}')), [['a'], '']); assert.deepStrictEqual(inspect(parser, input('[*a*]{b}')), [['a'], '']); }); it('external', () => { assert.deepStrictEqual(inspect(parser, input('[]{//host}')), [['//host'], '']); assert.deepStrictEqual(inspect(parser, input('[]{//[::]}')), [['//[::]'], '']); }); it('attribute', () => { assert.deepStrictEqual(inspect(parser, input('[]{/ name=}')), [['/'], '']); assert.deepStrictEqual(inspect(parser, input('[]{/ name="}')), [['/'], '']); assert.deepStrictEqual(inspect(parser, input('[]{/ name="""}')), [['/'], '']); assert.deepStrictEqual(inspect(parser, input('[]{/ name}')), [['/'], '']); assert.deepStrictEqual(inspect(parser, input('[]{/ name=""}')), [['/'], '']); assert.deepStrictEqual(inspect(parser, input('[]{/ name=" "}')), [['/'], '']); assert.deepStrictEqual(inspect(parser, input('[]{/ name="\\""}')), [['/'], '']); assert.deepStrictEqual(inspect(parser, input('[]{/ __proto__}')), [['/'], '']); assert.deepStrictEqual(inspect(parser, input('[]{/ constructor}')), [['/'], '']); assert.deepStrictEqual(inspect(parser, input('[]{/ rel="prefetch"}')), [['/'], '']); assert.deepStrictEqual(inspect(parser, input('[]{/ aspect-ratio="4/3"}')), [['/'], '']); assert.deepStrictEqual(inspect(parser, input('[]{/ 4:3}')), [['/'], '']); assert.deepStrictEqual(inspect(parser, input('[]{/ =}')), [['/'], '']); assert.deepStrictEqual(inspect(parser, input('[]{/\nname}')), [['[]{/'], '\nname}']); }); it('nofollow', () => { assert.deepStrictEqual(inspect(parser, input('[]{/ nofollow=}')), [['/'], '']); assert.deepStrictEqual(inspect(parser, input('[]{/ nofollow=nofollow}')), [['/'], '']); assert.deepStrictEqual(inspect(parser, input('[]{/ nofollow=""}')), [['/'], '']); assert.deepStrictEqual(inspect(parser, input('[]{/ nofollow="nofollow"}')), [['/'], '']); assert.deepStrictEqual(inspect(parser, input('[]{/ nofollow nofollow}')), [['/'], '']); assert.deepStrictEqual(inspect(parser, input('[]{/ nofollow}')), [['/'], '']); assert.deepStrictEqual(inspect(parser, input('[]{/ nofollow }')), [['/'], '']); assert.deepStrictEqual(inspect(parser, input('[]{/ nofollow }')), [['[]{/ nofollow'], ' }']); assert.deepStrictEqual(inspect(parser, input('[]{/ nofollow}')), [['[]{/'], ' nofollow}']); assert.deepStrictEqual(inspect(parser, input('[]{ / nofollow}')), [['/'], '']); assert.deepStrictEqual(inspect(parser, input('[]{ / nofollow }')), [['/'], '']); assert.deepStrictEqual(inspect(parser, input('[]{ / nofollow }')), [['[]{ / nofollow'], ' }']); assert.deepStrictEqual(inspect(parser, input('[]{ / nofollow}')), [['[]{ /'], ' nofollow}']); assert.deepStrictEqual(inspect(parser, input('[]{http://host nofollow}')), [['http://host'], '']); assert.deepStrictEqual(inspect(parser, input('[!http://host]{http://host nofollow}')), [['http://host'], '']); }); }); });