security.test.js 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. 'use strict'
  2. const test = require('tape')
  3. const fastURI = require('..')
  4. test('parse marks malformed authority and port inputs as errors', (t) => {
  5. const malformedCases = [
  6. {
  7. input: 'http://[::1]foo',
  8. expectedError: 'URI path must start with "/" when authority is present.'
  9. },
  10. {
  11. input: 'http://[::1]:80abc/path',
  12. expectedError: 'URI path must start with "/" when authority is present.'
  13. },
  14. {
  15. input: 'http://example.com:80abc/path',
  16. expectedError: 'URI path must start with "/" when authority is present.'
  17. },
  18. {
  19. input: 'http://[::1]:65536',
  20. expectedError: 'URI port is malformed.'
  21. }
  22. ]
  23. t.plan(malformedCases.length)
  24. malformedCases.forEach(({ input, expectedError }) => {
  25. t.equal(fastURI.parse(input).error, expectedError, input)
  26. })
  27. })
  28. test('normalize does not canonicalize malformed URLs into different valid URLs', (t) => {
  29. const malformedCases = [
  30. 'http://[::1]foo',
  31. 'http://[::1]:80abc/path',
  32. 'http://example.com:80abc/path',
  33. 'http://[::1]:65536'
  34. ]
  35. t.plan(malformedCases.length)
  36. malformedCases.forEach((input) => {
  37. t.equal(fastURI.normalize(input), input, input)
  38. })
  39. })
  40. test('equal returns false when either side is malformed', (t) => {
  41. const malformedPairs = [
  42. ['http://[::1]foo', 'http://[::1]/foo'],
  43. ['http://[::1]:80abc/path', 'http://[::1]/abc/path'],
  44. ['http://example.com:80abc/path', 'http://example.com/abc/path'],
  45. ['http://[::1]:65536', 'http://[::1]:65536/']
  46. ]
  47. t.plan(malformedPairs.length)
  48. malformedPairs.forEach(([left, right]) => {
  49. t.equal(fastURI.equal(left, right), false, `${left} != ${right}`)
  50. })
  51. })
  52. test('normalize preserves encoded authority delimiters in host', (t) => {
  53. const cases = [
  54. ['http://trusted.com%40evil.com/', 'http://trusted.com%40evil.com/'],
  55. ['http://example.com%3A8080/', 'http://example.com%3A8080/'],
  56. ['http://example.com%2Fevil.com/path', 'http://example.com%2Fevil.com/path'],
  57. ['http://example.com%23fragment/path', 'http://example.com%23fragment/path'],
  58. ['http://example.com%3Fq=evil/path', 'http://example.com%3Fq=evil/path'],
  59. ['http://user%3Apass%40evil.com/', 'http://user%3Apass%40evil.com/'],
  60. ['http://user@trusted.com%40evil.com/', 'http://user@trusted.com%40evil.com/'],
  61. ['https://trusted.com%40evil.com/', 'https://trusted.com%40evil.com/'],
  62. ['ws://trusted.com%40evil.com/chat', 'ws://trusted.com%40evil.com/chat'],
  63. ['wss://trusted.com%40evil.com/chat', 'wss://trusted.com%40evil.com/chat']
  64. ]
  65. t.plan(cases.length)
  66. cases.forEach(([input, expected]) => {
  67. t.equal(fastURI.normalize(input), expected, input)
  68. })
  69. })
  70. test('parse preserves encoded authority delimiters in host', (t) => {
  71. const cases = [
  72. ['http://trusted.com%40evil.com/', 'trusted.com%40evil.com'],
  73. ['http://example.com%3A8080/', 'example.com%3A8080'],
  74. ['http://user%3Apass%40evil.com/', 'user%3Apass%40evil.com']
  75. ]
  76. t.plan(cases.length)
  77. cases.forEach(([input, expectedHost]) => {
  78. t.equal(fastURI.parse(input).host, expectedHost, input)
  79. })
  80. })
  81. test('equal returns false when encoded delimiters differ from live delimiters', (t) => {
  82. const pairs = [
  83. ['http://trusted.com%40evil.com/', 'http://trusted.com@evil.com/'],
  84. ['http://example.com%3A8080/', 'http://example.com:8080/']
  85. ]
  86. t.plan(pairs.length)
  87. pairs.forEach(([left, right]) => {
  88. t.equal(fastURI.equal(left, right, {}), false, `${left} != ${right}`)
  89. })
  90. })
  91. test('resolve preserves encoded authority delimiters', (t) => {
  92. const result = fastURI.resolve('http://base.com/', '//trusted.com%40evil.com/path')
  93. const parsed = fastURI.parse(result)
  94. t.plan(1)
  95. t.notEqual(parsed.host, 'evil.com', '//trusted.com%40evil.com/path')
  96. })
  97. test('serialize escapes authority delimiters in host field', (t) => {
  98. const result = fastURI.serialize({ scheme: 'http', host: 'trusted.com@evil.com', path: '/' })
  99. const parsed = fastURI.parse(result)
  100. t.plan(1)
  101. t.notEqual(parsed.host, 'evil.com', 'host: trusted.com@evil.com')
  102. })
  103. test('normalize does not double-decode %2540 into a live @', (t) => {
  104. const result = fastURI.normalize('http://trusted.com%2540evil.com/')
  105. const parsed = fastURI.parse(result)
  106. t.plan(1)
  107. t.notEqual(parsed.host, 'trusted.com@evil.com', 'http://trusted.com%2540evil.com/')
  108. })