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.

301 lines
16KB

  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))