A Python module to crack Cloudflare's JavaScript challenge (aka "I'm Under Attack" mode)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

test.py 16 KiB

6 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. import parse
  2. import testdata
  3. import unittest
  4. import unittest.mock
  5. class TestCase(unittest.TestCase):
  6. '''
  7. Base test case class
  8. '''
  9. def __str__(self):
  10. '''
  11. Overwrite the standard string representation by an easier to read version.
  12. '''
  13. # Based on http://stackoverflow.com/a/18460031
  14. return '.'.join([self.__class__.__module__, self.__class__.__name__, self._testMethodName])
  15. def shortDescription(self):
  16. '''
  17. Disable displaying the first line of the docstring instead of module.class.method.
  18. '''
  19. # http://www.saltycrane.com/blog/2012/07/how-prevent-nose-unittest-using-docstring-when-verbosity-2/
  20. return None
  21. class TestStrEnum(TestCase):
  22. def test_clean_representation(self):
  23. self.assertEqual(repr(parse.Type.group), 'Type.group')
  24. self.assertEqual(repr(parse.Type.brackets), 'Type.brackets')
  25. self.assertEqual(repr(parse.Modifier.negate), 'Modifier.negate')
  26. self.assertEqual(repr(parse.Modifier.plus), 'Modifier.plus')
  27. class TestJSTypes(TestCase):
  28. def test_equality(self):
  29. self.assertEqual(parse.JSBool(True), parse.JSBool(True))
  30. self.assertEqual(parse.JSBool(False), parse.JSBool(False))
  31. self.assertNotEqual(parse.JSBool(True), parse.JSBool(False))
  32. self.assertNotEqual(parse.JSBool(False), parse.JSBool(True))
  33. self.assertEqual(parse.JSInt(0), parse.JSInt(0))
  34. self.assertEqual(parse.JSInt(42), parse.JSInt(42))
  35. self.assertEqual(parse.JSInt(-13), parse.JSInt(-13))
  36. self.assertNotEqual(parse.JSInt(0), parse.JSInt(42))
  37. self.assertNotEqual(parse.JSInt(42), parse.JSInt(0))
  38. self.assertNotEqual(parse.JSInt(0), parse.JSInt(-13))
  39. self.assertNotEqual(parse.JSInt(-13), parse.JSInt(42))
  40. self.assertEqual(parse.JSString(''), parse.JSString(''))
  41. self.assertEqual(parse.JSString('test'), parse.JSString('test'))
  42. self.assertNotEqual(parse.JSString(''), parse.JSString('test'))
  43. # Comparisons between different types are currently not supported (JS's equality algorithm is a nightmare) and always return False
  44. self.assertNotEqual(parse.JSBool(True), parse.JSInt(1))
  45. self.assertNotEqual(parse.JSBool(True), parse.JSString('true'))
  46. def test_operators(self):
  47. self.assertEqual(parse.JSBool(True) + parse.JSBool(True), parse.JSInt(2))
  48. self.assertEqual(parse.JSBool(True) + parse.JSInt(41), parse.JSInt(42))
  49. self.assertEqual(parse.JSBool(True) + parse.JSString('42'), parse.JSString('true42'))
  50. self.assertEqual(parse.JSBool(True) - parse.JSBool(True), parse.JSInt(0))
  51. self.assertEqual(parse.JSBool(False) - parse.JSBool(True), parse.JSInt(-1))
  52. self.assertEqual(parse.JSBool(True) - parse.JSInt(3), parse.JSInt(-2))
  53. self.assertEqual(parse.JSBool(True) - parse.JSString('14'), parse.JSInt(-13))
  54. self.assertEqual(parse.JSBool(True) - parse.JSString(''), parse.JSInt(1))
  55. #self.assertEqual(parse.JSBool(True) - parse.JSString('test'), parse.JSInt(NaN)) # Not supported
  56. #self.assertEqual(parse.JSBool(True) - parse.JSString('3test'), parse.JSInt(NaN)) # Not supported
  57. self.assertEqual(parse.JSBool(True) * parse.JSBool(True), parse.JSInt(1))
  58. self.assertEqual(parse.JSBool(False) * parse.JSBool(True), parse.JSInt(0))
  59. self.assertEqual(parse.JSBool(True) * parse.JSInt(42), parse.JSInt(42))
  60. self.assertEqual(parse.JSBool(False) * parse.JSInt(42), parse.JSInt(0))
  61. self.assertEqual(parse.JSBool(True) * parse.JSString('13'), parse.JSInt(13))
  62. self.assertEqual(parse.JSBool(True) * parse.JSString(''), parse.JSInt(0))
  63. #self.assertEqual(parse.JSBool(True) * parse.JSString('test'), parse.JSInt(NaN)) # Not supported
  64. #self.assertEqual(parse.JSBool(True) * parse.JSString('2test'), parse.JSInt(NaN)) # Not supported
  65. self.assertEqual(parse.JSInt(13) + parse.JSBool(True), parse.JSInt(14))
  66. self.assertEqual(parse.JSInt(13) + parse.JSInt(29), parse.JSInt(42))
  67. self.assertEqual(parse.JSInt(13) + parse.JSString('29'), parse.JSString('1329'))
  68. self.assertEqual(parse.JSInt(13) + parse.JSString(''), parse.JSString('13'))
  69. self.assertEqual(parse.JSInt(13) + parse.JSString('test'), parse.JSString('13test'))
  70. self.assertEqual(parse.JSInt(13) - parse.JSBool(True), parse.JSInt(12))
  71. self.assertEqual(parse.JSInt(13) - parse.JSInt(12), parse.JSInt(1))
  72. self.assertEqual(parse.JSInt(13) - parse.JSString('15'), parse.JSInt(-2))
  73. self.assertEqual(parse.JSInt(13) - parse.JSString(''), parse.JSInt(13))
  74. #self.assertEqual(parse.JSInt(13) - parse.JSString('test'), parse.JSInt(NaN)) # Not supported
  75. #self.assertEqual(parse.JSInt(13) - parse.JSString('13test'), parse.JSInt(NaN)) # Not supported
  76. self.assertEqual(parse.JSInt(3) * parse.JSBool(True), parse.JSInt(3))
  77. self.assertEqual(parse.JSInt(3) * parse.JSInt(4), parse.JSInt(12))
  78. self.assertEqual(parse.JSInt(3) * parse.JSString('4'), parse.JSInt(12))
  79. self.assertEqual(parse.JSInt(3) * parse.JSString(''), parse.JSInt(0))
  80. #self.assertEqual(parse.JSInt(3) * parse.JSString('test'), parse.JSInt(NaN)) # Not supported
  81. #self.assertEqual(parse.JSInt(3) * parse.JSString('1test'), parse.JSInt(NaN)) # Not supported
  82. self.assertEqual(parse.JSString('1') + parse.JSBool(True), parse.JSString('1true'))
  83. self.assertEqual(parse.JSString('') + parse.JSBool(False), parse.JSString('false'))
  84. self.assertEqual(parse.JSString('test') + parse.JSBool(True), parse.JSString('testtrue'))
  85. self.assertEqual(parse.JSString('1') + parse.JSInt(1), parse.JSString('11'))
  86. self.assertEqual(parse.JSString('1') + parse.JSString('1'), parse.JSString('11'))
  87. self.assertEqual(parse.JSString('13') - parse.JSBool(True), parse.JSInt(12))
  88. self.assertEqual(parse.JSString('') - parse.JSBool(True), parse.JSInt(-1))
  89. #self.assertEqual(parse.JSString('test') - parse.JSBool(True), parse.JSInt(NaN)) # Not supported
  90. #self.assertEqual(parse.JSString('3test') - parse.JSBool(True), parse.JSInt(NaN)) # Not supported
  91. self.assertEqual(parse.JSString('1') - parse.JSInt(3), parse.JSInt(-2))
  92. self.assertEqual(parse.JSString('') - parse.JSInt(-3), parse.JSInt(3))
  93. #self.assertEqual(parse.JSString('test') - parse.JSInt(13), parse.JSInt(NaN)) # Not supported
  94. #self.assertEqual(parse.JSString('13test') - parse.JSInt(13), parse.JSInt(NaN)) # Not supported
  95. self.assertEqual(parse.JSString('13') - parse.JSString('2'), parse.JSInt(11))
  96. self.assertEqual(parse.JSString('13') - parse.JSString(''), parse.JSInt(13))
  97. self.assertEqual(parse.JSString('') - parse.JSString('-3'), parse.JSInt(3))
  98. #self.assertEqual(parse.JSString('test') - parse.JSString('2'), parse.JSInt(NaN)) # Not supported
  99. #self.assertEqual(parse.JSString('13test') - parse.JSString('2'), parse.JSInt(NaN)) # Not supported
  100. #self.assertEqual(parse.JSString('2') - parse.JSString('test'), parse.JSInt(NaN)) # Not supported
  101. #self.assertEqual(parse.JSString('2') - parse.JSString('13test'), parse.JSInt(NaN)) # Not supported
  102. self.assertEqual(parse.JSString('3') * parse.JSBool(True), parse.JSInt(3))
  103. self.assertEqual(parse.JSString('') * parse.JSBool(True), parse.JSInt(0))
  104. #self.assertEqual(parse.JSString('test') * parse.JSBool(True), parse.JSInt(NaN)) # Not supported
  105. #self.assertEqual(parse.JSString('13test') * parse.JSBool(True), parse.JSInt(NaN)) # Not supported
  106. self.assertEqual(parse.JSString('3') * parse.JSInt(2), parse.JSInt(6))
  107. self.assertEqual(parse.JSString('') * parse.JSInt(13), parse.JSInt(0))
  108. #self.assertEqual(parse.JSString('test') * parse.JSInt(1), parse.JSInt(NaN)) # Not supported
  109. #self.assertEqual(parse.JSString('13test') * parse.JSInt(1), parse.JSInt(NaN)) # Not supported
  110. self.assertEqual(parse.JSString('3') * parse.JSString('2'), parse.JSInt(6))
  111. self.assertEqual(parse.JSString('3') * parse.JSString(''), parse.JSInt(0))
  112. self.assertEqual(parse.JSString('') * parse.JSString('3'), parse.JSInt(0))
  113. #self.assertEqual(parse.JSString('3') * parse.JSString('test'), parse.JSInt(NaN)) # Not supported
  114. #self.assertEqual(parse.JSString('') * parse.JSString('test'), parse.JSInt(NaN)) # Not supported
  115. #self.assertEqual(parse.JSString('test') * parse.JSString('3'), parse.JSInt(NaN)) # Not supported
  116. #self.assertEqual(parse.JSString('test') * parse.JSString(''), parse.JSInt(NaN)) # Not supported
  117. #self.assertEqual(parse.JSString('3test') * parse.JSString('3'), parse.JSInt(NaN)) # Not supported
  118. def test_casting(self):
  119. # Casting to Python objects
  120. self.assertEqual(bool(parse.JSBool(True)), True)
  121. self.assertEqual(bool(parse.JSBool(False)), False)
  122. self.assertEqual(int(parse.JSBool(True)), 1)
  123. self.assertEqual(int(parse.JSBool(False)), 0)
  124. self.assertEqual(str(parse.JSBool(True)), 'true') # JavaScript capitalisation!
  125. self.assertEqual(str(parse.JSBool(False)), 'false')
  126. self.assertEqual(bool(parse.JSInt(0)), False)
  127. self.assertEqual(bool(parse.JSInt(42)), True)
  128. self.assertEqual(int(parse.JSInt(0)), 0)
  129. self.assertEqual(int(parse.JSInt(42)), 42)
  130. self.assertEqual(str(parse.JSInt(0)), '0')
  131. self.assertEqual(str(parse.JSInt(42)), '42')
  132. self.assertEqual(bool(parse.JSString('')), False)
  133. self.assertEqual(bool(parse.JSString('test')), True)
  134. self.assertEqual(int(parse.JSString('')), 0)
  135. #self.assertEqual(int(parse.JSString('test')), NaN) # Not supported
  136. self.assertEqual(int(parse.JSString('0')), 0)
  137. self.assertEqual(int(parse.JSString('-13')), -13)
  138. self.assertEqual(str(parse.JSString('')), '')
  139. self.assertEqual(str(parse.JSString('test')), 'test')
  140. # Casting to JS types
  141. self.assertEqual(parse.JSBool(parse.JSBool(True)), parse.JSBool(True))
  142. self.assertEqual(parse.JSBool(parse.JSBool(False)), parse.JSBool(False))
  143. self.assertEqual(parse.JSInt(parse.JSBool(True)), parse.JSInt(1))
  144. self.assertEqual(parse.JSInt(parse.JSBool(False)), parse.JSInt(0))
  145. self.assertEqual(parse.JSString(parse.JSBool(True)), parse.JSString('true')) # JavaScript capitalisation!
  146. self.assertEqual(parse.JSString(parse.JSBool(False)), parse.JSString('false'))
  147. self.assertEqual(parse.JSBool(parse.JSInt(0)), parse.JSBool(False))
  148. self.assertEqual(parse.JSBool(parse.JSInt(42)), parse.JSBool(True))
  149. self.assertEqual(parse.JSInt(parse.JSInt(0)), parse.JSInt(0))
  150. self.assertEqual(parse.JSInt(parse.JSInt(42)), parse.JSInt(42))
  151. self.assertEqual(parse.JSString(parse.JSInt(0)), parse.JSString('0'))
  152. self.assertEqual(parse.JSString(parse.JSInt(42)), parse.JSString('42'))
  153. self.assertEqual(parse.JSBool(parse.JSString('')), parse.JSBool(False))
  154. self.assertEqual(parse.JSBool(parse.JSString('test')), parse.JSBool(True))
  155. #self.assertEqual(parse.JSInt(parse.JSString('')), parse.JSInt(0)) # Not supported (yet?)
  156. #self.assertEqual(parse.JSInt(parse.JSString('test')), parse.JSInt(NaN)) # Not supported (yet?)
  157. self.assertEqual(parse.JSInt(parse.JSString('0')), parse.JSInt(0))
  158. self.assertEqual(parse.JSInt(parse.JSString('-13')), parse.JSInt(-13))
  159. self.assertEqual(parse.JSString(parse.JSString('')), parse.JSString(''))
  160. self.assertEqual(parse.JSString(parse.JSString('test')), parse.JSString('test'))
  161. def test_repr(self):
  162. self.assertEqual(repr(parse.JSBool(True)), 'JSBool(True)')
  163. self.assertEqual(repr(parse.JSBool(False)), 'JSBool(False)')
  164. self.assertEqual(repr(parse.JSInt(0)), 'JSInt(0)')
  165. self.assertEqual(repr(parse.JSInt(-13)), 'JSInt(-13)')
  166. self.assertEqual(repr(parse.JSInt(42)), 'JSInt(42)')
  167. self.assertEqual(repr(parse.JSString('')), "JSString('')")
  168. self.assertEqual(repr(parse.JSString('test')), "JSString('test')")
  169. class TestItem(TestCase):
  170. def test_basic(self):
  171. item = parse.Item(parse.Type.group, [], values = [])
  172. item = parse.Item(parse.Type.group, [parse.Modifier.plus], values = [])
  173. with self.assertRaises(ValueError):
  174. parse.Item(-1, [])
  175. with self.assertRaises(TypeError):
  176. parse.Item(parse.Type.brackets, -1)
  177. with self.assertRaises(ValueError):
  178. parse.Item(parse.Type.brackets, [-1])
  179. with self.assertRaises(ValueError):
  180. parse.Item(parse.Type.group, []) # no values
  181. def test_evaluate_brackets(self):
  182. def test_brackets(modifiers, result):
  183. self.assertEqual(parse.Item(parse.Type.brackets, modifiers).evaluate(), result)
  184. test_brackets([], parse.JSString(''))
  185. test_brackets([parse.Modifier.plus], parse.JSInt(0))
  186. test_brackets([parse.Modifier.negate], parse.JSBool(False))
  187. # ++[] -> syntax error
  188. test_brackets([parse.Modifier.plus, parse.Modifier.negate], parse.JSInt(0))
  189. test_brackets([parse.Modifier.negate, parse.Modifier.plus], parse.JSBool(True))
  190. test_brackets([parse.Modifier.negate, parse.Modifier.negate], parse.JSBool(True))
  191. # +++[] -> syntax error
  192. # ++![] -> syntax error
  193. test_brackets([parse.Modifier.plus, parse.Modifier.negate, parse.Modifier.plus], parse.JSInt(1))
  194. test_brackets([parse.Modifier.plus, parse.Modifier.negate, parse.Modifier.negate], parse.JSInt(1))
  195. # !++[] -> syntax error
  196. test_brackets([parse.Modifier.negate, parse.Modifier.plus, parse.Modifier.negate], parse.JSBool(True))
  197. test_brackets([parse.Modifier.negate, parse.Modifier.negate, parse.Modifier.plus], parse.JSBool(False))
  198. test_brackets([parse.Modifier.negate, parse.Modifier.negate, parse.Modifier.negate], parse.JSBool(False))
  199. def test_evaluate_group(self):
  200. item = parse.Item(parse.Type.group, [], values = [])
  201. with self.assertRaises(ValueError):
  202. item.evaluate() # No evaluateFunction specified
  203. with self.assertRaises(ValueError):
  204. item.evaluate(13) # Not a callable
  205. mock = unittest.mock.Mock(return_value = 42)
  206. item = parse.Item(parse.Type.group, [], values = [parse.Item(parse.Type.brackets, [parse.Modifier.plus])])
  207. self.assertEqual(item.evaluate(evaluateFunction = mock), 42)
  208. self.assertEqual(mock.call_count, 1)
  209. self.assertEqual(len(mock.call_args), 2)
  210. self.assertEqual(len(mock.call_args[0]), 2)
  211. self.assertEqual(len(mock.call_args[1]), 0)
  212. self.assertIs(mock.call_args[0][0], item.values)
  213. self.assertIs(mock.call_args[0][1], item.modifiers)
  214. class TestFunctions(TestCase):
  215. def test_parse(self):
  216. self.assertEqual(parse.parse('!![]'), [parse.Item(parse.Type.brackets, [parse.Modifier.negate, parse.Modifier.negate])])
  217. self.assertEqual(parse.parse('!![]+!+![]'), [
  218. parse.Item(parse.Type.brackets, [parse.Modifier.negate, parse.Modifier.negate]),
  219. parse.Item(parse.Type.brackets, [parse.Modifier.negate, parse.Modifier.plus, parse.Modifier.negate]),
  220. ])
  221. self.assertEqual(parse.parse('(!![]+!+![]+[])+(+!![]+[])'), [
  222. parse.Item(parse.Type.group, [], [
  223. parse.Item(parse.Type.brackets, [parse.Modifier.negate, parse.Modifier.negate]),
  224. parse.Item(parse.Type.brackets, [parse.Modifier.negate, parse.Modifier.plus, parse.Modifier.negate]),
  225. parse.Item(parse.Type.brackets, []),
  226. ]),
  227. parse.Item(parse.Type.group, [], [
  228. parse.Item(parse.Type.brackets, [parse.Modifier.plus, parse.Modifier.negate, parse.Modifier.negate]),
  229. parse.Item(parse.Type.brackets, []),
  230. ]),
  231. ])
  232. self.assertEqual(parse.parse('+((!![]+!+![]+[])+(+!![]+[]))'), [
  233. parse.Item(parse.Type.group, [parse.Modifier.plus], values = [
  234. parse.Item(parse.Type.group, [], values = [
  235. parse.Item(parse.Type.brackets, [parse.Modifier.negate, parse.Modifier.negate]),
  236. parse.Item(parse.Type.brackets, [parse.Modifier.negate, parse.Modifier.plus, parse.Modifier.negate]),
  237. parse.Item(parse.Type.brackets, []),
  238. ]),
  239. parse.Item(parse.Type.group, [], values = [
  240. parse.Item(parse.Type.brackets, [parse.Modifier.plus, parse.Modifier.negate, parse.Modifier.negate]),
  241. parse.Item(parse.Type.brackets, []),
  242. ]),
  243. ]),
  244. ])
  245. def test_evaluate(self):
  246. self.assertEqual(parse.evaluate([parse.Item(parse.Type.brackets, [parse.Modifier.negate, parse.Modifier.negate])]), parse.JSBool(True))
  247. self.assertEqual(parse.evaluate([
  248. parse.Item(parse.Type.brackets, [parse.Modifier.negate, parse.Modifier.negate]),
  249. parse.Item(parse.Type.brackets, [parse.Modifier.negate, parse.Modifier.negate]),
  250. ]), parse.JSInt(2))
  251. self.assertEqual(parse.evaluate([
  252. parse.Item(parse.Type.brackets, [parse.Modifier.negate, parse.Modifier.negate]),
  253. parse.Item(parse.Type.brackets, [parse.Modifier.negate, parse.Modifier.negate]),
  254. parse.Item(parse.Type.brackets, []),
  255. ]), parse.JSString('2'))
  256. self.assertEqual(parse.evaluate([
  257. parse.Item(parse.Type.group, [], values = [
  258. parse.Item(parse.Type.brackets, [parse.Modifier.negate, parse.Modifier.negate]),
  259. parse.Item(parse.Type.brackets, [parse.Modifier.negate, parse.Modifier.negate]),
  260. parse.Item(parse.Type.brackets, []),
  261. ]),
  262. parse.Item(parse.Type.group, [], values = [
  263. parse.Item(parse.Type.brackets, [parse.Modifier.plus, parse.Modifier.negate, parse.Modifier.negate]),
  264. parse.Item(parse.Type.brackets, []),
  265. ]),
  266. ]), parse.JSString('21'))
  267. def test_crack(self):
  268. for url, html, result in testdata.data:
  269. self.assertEqual(parse.crack(url, html), parse.JSInt(result))