scheme-validation.test.js 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. 'use strict'
  2. const test = require('tape')
  3. const fastURI = require('..')
  4. const MALFORMED_SCHEME_ERROR = 'URI scheme is malformed.'
  5. const malformedSchemes = [
  6. '%2f%2fevil.example:/pwn',
  7. '%u002f%u002fevil.example:/pwn',
  8. '%0d%0aSet-Cookie:%20sid=attacker:/p',
  9. 'foo%3Abar:value',
  10. 'foo%2Fbar:value',
  11. '1http://example.com/',
  12. 'foo_bar:value',
  13. 'éxample:value',
  14. 'Kttp://example.com/',
  15. 'ſcheme:value'
  16. ]
  17. test('parse validates the decoded scheme against RFC 3986', (t) => {
  18. const validSchemes = [
  19. ['a:value', 'a'],
  20. ['HTTP://example.com/', 'http'],
  21. ['a1+.-:value', 'a1+.-'],
  22. ['%4Aavascript:alert(1)', 'javascript'],
  23. ['foo%2Bbar:value', 'foo+bar'],
  24. ['%u006Aavascript:1', 'javascript'],
  25. ['ht%74ps://example.com/', 'https']
  26. ]
  27. for (const [uri, scheme] of validSchemes) {
  28. const parsed = fastURI.parse(uri)
  29. t.equal(parsed.error, undefined, uri)
  30. t.equal(parsed.scheme, scheme, uri + ' scheme')
  31. }
  32. for (const uri of malformedSchemes) {
  33. const parsed = fastURI.parse(uri)
  34. t.equal(parsed.error, MALFORMED_SCHEME_ERROR, uri)
  35. }
  36. t.end()
  37. })
  38. test('decoded schemes select their scheme handlers', (t) => {
  39. t.equal(
  40. fastURI.normalize('ht%74ps://example.com:443'),
  41. 'https://example.com/',
  42. 'HTTP normalization runs after decoding the scheme'
  43. )
  44. // 3.x has no mailto scheme handler (added in v4); use the ws handler to
  45. // verify that a percent-encoded scheme still selects its scheme handler
  46. const ws = fastURI.parse('we%62socket://example.com/')
  47. t.equal(ws.scheme, 'websocket', 'ws parsing runs after decoding the scheme')
  48. t.end()
  49. })
  50. test('normalize preserves schemes that decode to invalid identifiers', (t) => {
  51. for (const uri of malformedSchemes) {
  52. t.equal(fastURI.normalize(uri), uri, uri)
  53. }
  54. t.end()
  55. })
  56. test('scheme normalization cannot introduce authority or control delimiters', (t) => {
  57. const authority = '%2f%2fevil.example:/pwn'
  58. const crlf = '%0d%0aSet-Cookie:%20sid=attacker:/p'
  59. t.equal(fastURI.parse(authority).host, undefined, 'original input has no authority')
  60. t.equal(fastURI.normalize(authority), authority, 'normalization does not create an authority')
  61. t.equal(fastURI.normalize(crlf), crlf, 'normalization does not emit raw CRLF')
  62. t.equal(fastURI.normalize(crlf).includes('\r\n'), false, 'normalized output contains no raw CRLF')
  63. t.end()
  64. })
  65. test('equal returns false for malformed decoded schemes', (t) => {
  66. for (const uri of malformedSchemes) {
  67. t.equal(fastURI.equal(uri, uri, {}), false, uri)
  68. }
  69. t.end()
  70. })
  71. test('resolve rejects malformed decoded schemes in either input', (t) => {
  72. t.throws(
  73. () => fastURI.resolve('%2f%2fevil.example:/base', 'child'),
  74. /URI scheme is malformed\./,
  75. 'malformed base'
  76. )
  77. t.throws(
  78. () => fastURI.resolve('https://allowed.example/app/', '%2f%2fevil.example:/pwn'),
  79. /URI scheme is malformed\./,
  80. 'malformed relative reference'
  81. )
  82. t.end()
  83. })
  84. test('serialize validates decoded component schemes', (t) => {
  85. t.equal(
  86. fastURI.serialize({ scheme: 'foo%2Bbar', path: 'value' }),
  87. 'foo+bar:value',
  88. 'valid decoded scheme is serialized'
  89. )
  90. t.throws(
  91. () => fastURI.serialize({ scheme: '//evil.example', path: '/pwn' }),
  92. /URI scheme is malformed\./,
  93. 'raw invalid scheme'
  94. )
  95. t.throws(
  96. () => fastURI.serialize({ scheme: '%2f%2fevil.example', path: '/pwn' }),
  97. /URI scheme is malformed\./,
  98. 'encoded invalid scheme'
  99. )
  100. t.equal(
  101. fastURI.equal(
  102. { scheme: '%2f%2fevil.example', path: '/pwn' },
  103. { scheme: '%2f%2fevil.example', path: '/pwn' },
  104. {}
  105. ),
  106. false,
  107. 'equality fails closed for malformed component objects'
  108. )
  109. t.end()
  110. })