contrast-agent 3.8.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (500) hide show
  1. checksums.yaml +7 -0
  2. data/.clang-format +5 -0
  3. data/.dockerignore +10 -0
  4. data/.gitignore +58 -0
  5. data/.gitmodules +6 -0
  6. data/.rspec +6 -0
  7. data/.simplecov +4 -0
  8. data/Gemfile +7 -0
  9. data/LICENSE.txt +12 -0
  10. data/Rakefile +15 -0
  11. data/exe/contrast_service +29 -0
  12. data/ext/build_funchook.rb +48 -0
  13. data/ext/cs__assess_active_record_named/cs__active_record_named.c +47 -0
  14. data/ext/cs__assess_active_record_named/cs__active_record_named.h +10 -0
  15. data/ext/cs__assess_active_record_named/extconf.rb +2 -0
  16. data/ext/cs__assess_array/cs__assess_array.c +38 -0
  17. data/ext/cs__assess_array/cs__assess_array.h +9 -0
  18. data/ext/cs__assess_array/extconf.rb +2 -0
  19. data/ext/cs__assess_basic_object/cs__assess_basic_object.c +50 -0
  20. data/ext/cs__assess_basic_object/cs__assess_basic_object.h +17 -0
  21. data/ext/cs__assess_basic_object/extconf.rb +2 -0
  22. data/ext/cs__assess_fiber_track/cs__assess_fiber_track.c +86 -0
  23. data/ext/cs__assess_fiber_track/cs__assess_fiber_track.h +34 -0
  24. data/ext/cs__assess_fiber_track/extconf.rb +2 -0
  25. data/ext/cs__assess_hash/cs__assess_hash.c +64 -0
  26. data/ext/cs__assess_hash/cs__assess_hash.h +24 -0
  27. data/ext/cs__assess_hash/extconf.rb +2 -0
  28. data/ext/cs__assess_kernel/cs__assess_kernel.c +36 -0
  29. data/ext/cs__assess_kernel/cs__assess_kernel.h +10 -0
  30. data/ext/cs__assess_kernel/extconf.rb +2 -0
  31. data/ext/cs__assess_marshal_module/cs__assess_marshal_module.c +47 -0
  32. data/ext/cs__assess_marshal_module/cs__assess_marshal_module.h +18 -0
  33. data/ext/cs__assess_marshal_module/extconf.rb +2 -0
  34. data/ext/cs__assess_module/cs__assess_module.c +78 -0
  35. data/ext/cs__assess_module/cs__assess_module.h +25 -0
  36. data/ext/cs__assess_module/extconf.rb +2 -0
  37. data/ext/cs__assess_regexp/cs__assess_regexp.c +48 -0
  38. data/ext/cs__assess_regexp/cs__assess_regexp.h +22 -0
  39. data/ext/cs__assess_regexp/extconf.rb +2 -0
  40. data/ext/cs__assess_regexp_track/cs__assess_regexp_track.c +63 -0
  41. data/ext/cs__assess_regexp_track/cs__assess_regexp_track.h +29 -0
  42. data/ext/cs__assess_regexp_track/extconf.rb +2 -0
  43. data/ext/cs__assess_string/cs__assess_string.c +38 -0
  44. data/ext/cs__assess_string/cs__assess_string.h +19 -0
  45. data/ext/cs__assess_string/extconf.rb +2 -0
  46. data/ext/cs__assess_string_interpolation26/cs__assess_string_interpolation26.c +31 -0
  47. data/ext/cs__assess_string_interpolation26/cs__assess_string_interpolation26.h +13 -0
  48. data/ext/cs__assess_string_interpolation26/extconf.rb +2 -0
  49. data/ext/cs__common/cs__common.c +60 -0
  50. data/ext/cs__common/cs__common.h +28 -0
  51. data/ext/cs__common/extconf.rb +20 -0
  52. data/ext/cs__contrast_patch/cs__contrast_patch.c +445 -0
  53. data/ext/cs__contrast_patch/cs__contrast_patch.h +196 -0
  54. data/ext/cs__contrast_patch/extconf.rb +2 -0
  55. data/ext/cs__protect_kernel/cs__protect_kernel.c +37 -0
  56. data/ext/cs__protect_kernel/cs__protect_kernel.h +11 -0
  57. data/ext/cs__protect_kernel/extconf.rb +2 -0
  58. data/ext/cs__scope/cs__scope.c +96 -0
  59. data/ext/cs__scope/cs__scope.h +33 -0
  60. data/ext/cs__scope/extconf.rb +2 -0
  61. data/ext/extconf_common.rb +49 -0
  62. data/funchook/LICENSE +360 -0
  63. data/funchook/Makefile +29 -0
  64. data/funchook/Makefile.in +29 -0
  65. data/funchook/README.md +121 -0
  66. data/funchook/appveyor.yml +42 -0
  67. data/funchook/autogen.sh +3 -0
  68. data/funchook/autom4te.cache/output.0 +4976 -0
  69. data/funchook/autom4te.cache/requests +78 -0
  70. data/funchook/autom4te.cache/traces.0 +364 -0
  71. data/funchook/config.guess +1530 -0
  72. data/funchook/config.log +490 -0
  73. data/funchook/config.status +1016 -0
  74. data/funchook/config.sub +1773 -0
  75. data/funchook/configure +4976 -0
  76. data/funchook/configure.ac +59 -0
  77. data/funchook/distorm/COPYING +26 -0
  78. data/funchook/distorm/MANIFEST +25 -0
  79. data/funchook/distorm/MANIFEST.in +4 -0
  80. data/funchook/distorm/README.md +12 -0
  81. data/funchook/distorm/disOps/disOps.py +795 -0
  82. data/funchook/distorm/disOps/x86db.py +404 -0
  83. data/funchook/distorm/disOps/x86header.py +247 -0
  84. data/funchook/distorm/disOps/x86sets.py +1664 -0
  85. data/funchook/distorm/examples/cs/TestdiStorm/Program.cs +79 -0
  86. data/funchook/distorm/examples/cs/TestdiStorm/Properties/AssemblyInfo.cs +36 -0
  87. data/funchook/distorm/examples/cs/TestdiStorm/TestdiStorm.csproj +69 -0
  88. data/funchook/distorm/examples/cs/distorm-net.sln +26 -0
  89. data/funchook/distorm/examples/cs/distorm-net/CodeInfo.cs +23 -0
  90. data/funchook/distorm/examples/cs/distorm-net/DecodedInst.cs +15 -0
  91. data/funchook/distorm/examples/cs/distorm-net/DecodedResult.cs +14 -0
  92. data/funchook/distorm/examples/cs/distorm-net/DecomposedInst.cs +36 -0
  93. data/funchook/distorm/examples/cs/distorm-net/DecomposedResult.cs +14 -0
  94. data/funchook/distorm/examples/cs/distorm-net/Opcodes.cs +1268 -0
  95. data/funchook/distorm/examples/cs/distorm-net/Opcodes.tt +37 -0
  96. data/funchook/distorm/examples/cs/distorm-net/Operand.cs +25 -0
  97. data/funchook/distorm/examples/cs/distorm-net/Properties/AssemblyInfo.cs +36 -0
  98. data/funchook/distorm/examples/cs/distorm-net/diStorm3.cs +411 -0
  99. data/funchook/distorm/examples/cs/distorm-net/distorm-net.csproj +80 -0
  100. data/funchook/distorm/examples/cs/readme +3 -0
  101. data/funchook/distorm/examples/ddk/README +48 -0
  102. data/funchook/distorm/examples/ddk/distorm.ini +11 -0
  103. data/funchook/distorm/examples/ddk/dummy.c +15 -0
  104. data/funchook/distorm/examples/ddk/main.c +91 -0
  105. data/funchook/distorm/examples/ddk/makefile +1 -0
  106. data/funchook/distorm/examples/ddk/sources +10 -0
  107. data/funchook/distorm/examples/java/Makefile +23 -0
  108. data/funchook/distorm/examples/java/distorm/src/Main.java +43 -0
  109. data/funchook/distorm/examples/java/distorm/src/diStorm3/CodeInfo.java +27 -0
  110. data/funchook/distorm/examples/java/distorm/src/diStorm3/DecodedInst.java +32 -0
  111. data/funchook/distorm/examples/java/distorm/src/diStorm3/DecodedResult.java +11 -0
  112. data/funchook/distorm/examples/java/distorm/src/diStorm3/DecomposedInst.java +89 -0
  113. data/funchook/distorm/examples/java/distorm/src/diStorm3/DecomposedResult.java +11 -0
  114. data/funchook/distorm/examples/java/distorm/src/diStorm3/OpcodeEnum.java +131 -0
  115. data/funchook/distorm/examples/java/distorm/src/diStorm3/Opcodes.java +1123 -0
  116. data/funchook/distorm/examples/java/distorm/src/diStorm3/Operand.java +24 -0
  117. data/funchook/distorm/examples/java/distorm/src/diStorm3/distorm3.java +41 -0
  118. data/funchook/distorm/examples/java/jdistorm.c +405 -0
  119. data/funchook/distorm/examples/java/jdistorm.h +40 -0
  120. data/funchook/distorm/examples/java/jdistorm.sln +20 -0
  121. data/funchook/distorm/examples/java/jdistorm.vcproj +208 -0
  122. data/funchook/distorm/examples/linux/Makefile +15 -0
  123. data/funchook/distorm/examples/linux/main.c +181 -0
  124. data/funchook/distorm/examples/tests/Makefile +15 -0
  125. data/funchook/distorm/examples/tests/main.cpp +42 -0
  126. data/funchook/distorm/examples/tests/main.py +66 -0
  127. data/funchook/distorm/examples/tests/test_distorm3.py +1672 -0
  128. data/funchook/distorm/examples/tests/tests.sln +20 -0
  129. data/funchook/distorm/examples/tests/tests.vcxproj +82 -0
  130. data/funchook/distorm/examples/tests/tests.vcxproj.filters +22 -0
  131. data/funchook/distorm/examples/win32/disasm.sln +25 -0
  132. data/funchook/distorm/examples/win32/disasm.vcxproj +201 -0
  133. data/funchook/distorm/examples/win32/disasm.vcxproj.filters +14 -0
  134. data/funchook/distorm/examples/win32/main.cpp +163 -0
  135. data/funchook/distorm/include/distorm.h +482 -0
  136. data/funchook/distorm/include/mnemonics.h +301 -0
  137. data/funchook/distorm/make/linux/Makefile +28 -0
  138. data/funchook/distorm/make/mac/Makefile +24 -0
  139. data/funchook/distorm/make/win32/cdistorm.vcxproj +239 -0
  140. data/funchook/distorm/make/win32/cdistorm.vcxproj.filters +80 -0
  141. data/funchook/distorm/make/win32/distorm.sln +25 -0
  142. data/funchook/distorm/make/win32/resource.h +14 -0
  143. data/funchook/distorm/make/win32/resource.rc +99 -0
  144. data/funchook/distorm/python/distorm3/__init__.py +957 -0
  145. data/funchook/distorm/python/distorm3/sample.py +51 -0
  146. data/funchook/distorm/setup.cfg +10 -0
  147. data/funchook/distorm/setup.py +266 -0
  148. data/funchook/distorm/src/config.h +169 -0
  149. data/funchook/distorm/src/decoder.c +641 -0
  150. data/funchook/distorm/src/decoder.h +33 -0
  151. data/funchook/distorm/src/distorm.c +413 -0
  152. data/funchook/distorm/src/instructions.c +597 -0
  153. data/funchook/distorm/src/instructions.h +463 -0
  154. data/funchook/distorm/src/insts.c +7939 -0
  155. data/funchook/distorm/src/insts.h +64 -0
  156. data/funchook/distorm/src/mnemonics.c +284 -0
  157. data/funchook/distorm/src/operands.c +1290 -0
  158. data/funchook/distorm/src/operands.h +28 -0
  159. data/funchook/distorm/src/prefix.c +368 -0
  160. data/funchook/distorm/src/prefix.h +64 -0
  161. data/funchook/distorm/src/textdefs.c +172 -0
  162. data/funchook/distorm/src/textdefs.h +57 -0
  163. data/funchook/distorm/src/wstring.c +47 -0
  164. data/funchook/distorm/src/wstring.h +35 -0
  165. data/funchook/distorm/src/x86defs.h +82 -0
  166. data/funchook/include/funchook.h +123 -0
  167. data/funchook/install-sh +527 -0
  168. data/funchook/src/Makefile +70 -0
  169. data/funchook/src/Makefile.in +70 -0
  170. data/funchook/src/__strerror.h +109 -0
  171. data/funchook/src/config.h +101 -0
  172. data/funchook/src/config.h.in +100 -0
  173. data/funchook/src/decoder.o +0 -0
  174. data/funchook/src/distorm.o +0 -0
  175. data/funchook/src/funchook.c +440 -0
  176. data/funchook/src/funchook.o +0 -0
  177. data/funchook/src/funchook_internal.h +155 -0
  178. data/funchook/src/funchook_io.c +182 -0
  179. data/funchook/src/funchook_io.h +64 -0
  180. data/funchook/src/funchook_io.o +0 -0
  181. data/funchook/src/funchook_syscall.S +134 -0
  182. data/funchook/src/funchook_syscall.o +0 -0
  183. data/funchook/src/funchook_unix.c +480 -0
  184. data/funchook/src/funchook_unix.o +0 -0
  185. data/funchook/src/funchook_windows.c +397 -0
  186. data/funchook/src/funchook_x86.c +622 -0
  187. data/funchook/src/funchook_x86.o +0 -0
  188. data/funchook/src/instructions.o +0 -0
  189. data/funchook/src/insts.o +0 -0
  190. data/funchook/src/libfunchook.so +0 -0
  191. data/funchook/src/mnemonics.o +0 -0
  192. data/funchook/src/operands.o +0 -0
  193. data/funchook/src/os_func.c +115 -0
  194. data/funchook/src/os_func.h +75 -0
  195. data/funchook/src/os_func.o +0 -0
  196. data/funchook/src/os_func_unix.c +94 -0
  197. data/funchook/src/os_func_unix.o +0 -0
  198. data/funchook/src/os_func_windows.c +32 -0
  199. data/funchook/src/prefix.o +0 -0
  200. data/funchook/src/printf_base.c +1688 -0
  201. data/funchook/src/printf_base.h +46 -0
  202. data/funchook/src/printf_base.o +0 -0
  203. data/funchook/src/textdefs.o +0 -0
  204. data/funchook/src/wstring.o +0 -0
  205. data/funchook/test/Makefile +43 -0
  206. data/funchook/test/Makefile.in +43 -0
  207. data/funchook/test/funchook_test +0 -0
  208. data/funchook/test/libfunchook_test.c +25 -0
  209. data/funchook/test/libfunchook_test.so +0 -0
  210. data/funchook/test/libfunchook_test2.c +18 -0
  211. data/funchook/test/suffix.list +600 -0
  212. data/funchook/test/test_main.c +430 -0
  213. data/funchook/test/test_main.o +0 -0
  214. data/funchook/test/x86_64_test.S +10 -0
  215. data/funchook/test/x86_64_test.o +0 -0
  216. data/funchook/test/x86_test.S +339 -0
  217. data/funchook/win32/config.h +1 -0
  218. data/funchook/win32/funchook.sln +52 -0
  219. data/funchook/win32/funchook.vcxproj +188 -0
  220. data/funchook/win32/funchook.vcxproj.filters +84 -0
  221. data/funchook/win32/funchook_test.vcxproj +170 -0
  222. data/funchook/win32/funchook_test.vcxproj.filters +22 -0
  223. data/funchook/win32/funchook_test_dll.vcxproj +184 -0
  224. data/funchook/win32/funchook_test_dll.vcxproj.filters +30 -0
  225. data/funchook/win32/funchook_test_exe.def +3 -0
  226. data/lib/contrast-agent.rb +8 -0
  227. data/lib/contrast.rb +57 -0
  228. data/lib/contrast/agent.rb +80 -0
  229. data/lib/contrast/agent/assess.rb +45 -0
  230. data/lib/contrast/agent/assess/adjusted_span.rb +25 -0
  231. data/lib/contrast/agent/assess/class_reverter.rb +82 -0
  232. data/lib/contrast/agent/assess/contrast_event.rb +398 -0
  233. data/lib/contrast/agent/assess/frozen_properties.rb +41 -0
  234. data/lib/contrast/agent/assess/insulator.rb +53 -0
  235. data/lib/contrast/agent/assess/policy/dynamic_source_factory.rb +78 -0
  236. data/lib/contrast/agent/assess/policy/patcher.rb +85 -0
  237. data/lib/contrast/agent/assess/policy/policy.rb +116 -0
  238. data/lib/contrast/agent/assess/policy/policy_node.rb +289 -0
  239. data/lib/contrast/agent/assess/policy/policy_scanner.rb +44 -0
  240. data/lib/contrast/agent/assess/policy/preshift.rb +94 -0
  241. data/lib/contrast/agent/assess/policy/propagation_method.rb +260 -0
  242. data/lib/contrast/agent/assess/policy/propagation_node.rb +127 -0
  243. data/lib/contrast/agent/assess/policy/propagator.rb +35 -0
  244. data/lib/contrast/agent/assess/policy/propagator/append.rb +54 -0
  245. data/lib/contrast/agent/assess/policy/propagator/base.rb +37 -0
  246. data/lib/contrast/agent/assess/policy/propagator/center.rb +73 -0
  247. data/lib/contrast/agent/assess/policy/propagator/custom.rb +36 -0
  248. data/lib/contrast/agent/assess/policy/propagator/database_write.rb +62 -0
  249. data/lib/contrast/agent/assess/policy/propagator/insert.rb +55 -0
  250. data/lib/contrast/agent/assess/policy/propagator/keep.rb +26 -0
  251. data/lib/contrast/agent/assess/policy/propagator/next.rb +42 -0
  252. data/lib/contrast/agent/assess/policy/propagator/prepend.rb +50 -0
  253. data/lib/contrast/agent/assess/policy/propagator/remove.rb +76 -0
  254. data/lib/contrast/agent/assess/policy/propagator/replace.rb +27 -0
  255. data/lib/contrast/agent/assess/policy/propagator/reverse.rb +38 -0
  256. data/lib/contrast/agent/assess/policy/propagator/select.rb +86 -0
  257. data/lib/contrast/agent/assess/policy/propagator/splat.rb +60 -0
  258. data/lib/contrast/agent/assess/policy/propagator/split.rb +49 -0
  259. data/lib/contrast/agent/assess/policy/propagator/substitution.rb +169 -0
  260. data/lib/contrast/agent/assess/policy/propagator/trim.rb +81 -0
  261. data/lib/contrast/agent/assess/policy/rewriter_patch.rb +79 -0
  262. data/lib/contrast/agent/assess/policy/source_method.rb +209 -0
  263. data/lib/contrast/agent/assess/policy/source_node.rb +62 -0
  264. data/lib/contrast/agent/assess/policy/trigger_method.rb +209 -0
  265. data/lib/contrast/agent/assess/policy/trigger_node.rb +198 -0
  266. data/lib/contrast/agent/assess/policy/trigger_validation/ssrf_validator.rb +77 -0
  267. data/lib/contrast/agent/assess/policy/trigger_validation/trigger_validation.rb +31 -0
  268. data/lib/contrast/agent/assess/policy/trigger_validation/xss_validator.rb +40 -0
  269. data/lib/contrast/agent/assess/properties.rb +392 -0
  270. data/lib/contrast/agent/assess/rule.rb +18 -0
  271. data/lib/contrast/agent/assess/rule/base.rb +72 -0
  272. data/lib/contrast/agent/assess/rule/csrf.rb +66 -0
  273. data/lib/contrast/agent/assess/rule/csrf/csrf_action.rb +28 -0
  274. data/lib/contrast/agent/assess/rule/csrf/csrf_applicator.rb +69 -0
  275. data/lib/contrast/agent/assess/rule/csrf/csrf_watcher.rb +132 -0
  276. data/lib/contrast/agent/assess/rule/provider.rb +21 -0
  277. data/lib/contrast/agent/assess/rule/provider/hardcoded_key.rb +62 -0
  278. data/lib/contrast/agent/assess/rule/provider/hardcoded_password.rb +73 -0
  279. data/lib/contrast/agent/assess/rule/provider/hardcoded_value_rule.rb +121 -0
  280. data/lib/contrast/agent/assess/rule/redos.rb +68 -0
  281. data/lib/contrast/agent/assess/rule/response_scanning_rule.rb +47 -0
  282. data/lib/contrast/agent/assess/rule/response_watcher.rb +36 -0
  283. data/lib/contrast/agent/assess/rule/watcher.rb +36 -0
  284. data/lib/contrast/agent/assess/tag.rb +151 -0
  285. data/lib/contrast/agent/at_exit_hook.rb +33 -0
  286. data/lib/contrast/agent/class_reopener.rb +195 -0
  287. data/lib/contrast/agent/deadzone/policy/deadzone_node.rb +26 -0
  288. data/lib/contrast/agent/deadzone/policy/policy.rb +57 -0
  289. data/lib/contrast/agent/disable_reaction.rb +24 -0
  290. data/lib/contrast/agent/exclusion_matcher.rb +190 -0
  291. data/lib/contrast/agent/feature_state.rb +379 -0
  292. data/lib/contrast/agent/inventory/policy/policy.rb +32 -0
  293. data/lib/contrast/agent/inventory/policy/trigger_node.rb +22 -0
  294. data/lib/contrast/agent/logger_manager.rb +116 -0
  295. data/lib/contrast/agent/middleware.rb +352 -0
  296. data/lib/contrast/agent/module_data.rb +16 -0
  297. data/lib/contrast/agent/patching/policy/after_load_patch.rb +37 -0
  298. data/lib/contrast/agent/patching/policy/after_load_patcher.rb +58 -0
  299. data/lib/contrast/agent/patching/policy/method_policy.rb +94 -0
  300. data/lib/contrast/agent/patching/policy/module_policy.rb +116 -0
  301. data/lib/contrast/agent/patching/policy/patch.rb +312 -0
  302. data/lib/contrast/agent/patching/policy/patch_status.rb +192 -0
  303. data/lib/contrast/agent/patching/policy/patcher.rb +310 -0
  304. data/lib/contrast/agent/patching/policy/policy.rb +138 -0
  305. data/lib/contrast/agent/patching/policy/policy_node.rb +80 -0
  306. data/lib/contrast/agent/patching/policy/policy_unpatcher.rb +28 -0
  307. data/lib/contrast/agent/patching/policy/trigger_node.rb +81 -0
  308. data/lib/contrast/agent/protect/policy/policy.rb +37 -0
  309. data/lib/contrast/agent/protect/policy/trigger_node.rb +23 -0
  310. data/lib/contrast/agent/protect/rule.rb +58 -0
  311. data/lib/contrast/agent/protect/rule/base.rb +300 -0
  312. data/lib/contrast/agent/protect/rule/base_service.rb +88 -0
  313. data/lib/contrast/agent/protect/rule/cmd_injection.rb +156 -0
  314. data/lib/contrast/agent/protect/rule/csrf.rb +118 -0
  315. data/lib/contrast/agent/protect/rule/csrf/csrf_evaluator.rb +103 -0
  316. data/lib/contrast/agent/protect/rule/csrf/csrf_token_injector.rb +85 -0
  317. data/lib/contrast/agent/protect/rule/default_scanner.rb +300 -0
  318. data/lib/contrast/agent/protect/rule/deserialization.rb +193 -0
  319. data/lib/contrast/agent/protect/rule/http_method_tampering.rb +80 -0
  320. data/lib/contrast/agent/protect/rule/no_sqli.rb +101 -0
  321. data/lib/contrast/agent/protect/rule/no_sqli/mongo_no_sql_scanner.rb +40 -0
  322. data/lib/contrast/agent/protect/rule/path_traversal.rb +143 -0
  323. data/lib/contrast/agent/protect/rule/sqli.rb +101 -0
  324. data/lib/contrast/agent/protect/rule/sqli/default_sql_scanner.rb +16 -0
  325. data/lib/contrast/agent/protect/rule/sqli/mysql_sql_scanner.rb +38 -0
  326. data/lib/contrast/agent/protect/rule/sqli/postgres_sql_scanner.rb +22 -0
  327. data/lib/contrast/agent/protect/rule/sqli/sqlite_sql_scanner.rb +19 -0
  328. data/lib/contrast/agent/protect/rule/unsafe_file_upload.rb +20 -0
  329. data/lib/contrast/agent/protect/rule/xss.rb +24 -0
  330. data/lib/contrast/agent/protect/rule/xxe.rb +120 -0
  331. data/lib/contrast/agent/protect/rule/xxe/entity_wrapper.rb +82 -0
  332. data/lib/contrast/agent/railtie.rb +30 -0
  333. data/lib/contrast/agent/reaction_processor.rb +47 -0
  334. data/lib/contrast/agent/request.rb +493 -0
  335. data/lib/contrast/agent/request_context.rb +225 -0
  336. data/lib/contrast/agent/require_state.rb +61 -0
  337. data/lib/contrast/agent/response.rb +215 -0
  338. data/lib/contrast/agent/rewriter.rb +244 -0
  339. data/lib/contrast/agent/scope.rb +28 -0
  340. data/lib/contrast/agent/service_heartbeat.rb +37 -0
  341. data/lib/contrast/agent/settings_state.rb +148 -0
  342. data/lib/contrast/agent/socket_client.rb +125 -0
  343. data/lib/contrast/agent/thread.rb +26 -0
  344. data/lib/contrast/agent/tracepoint_hook.rb +51 -0
  345. data/lib/contrast/agent/version.rb +8 -0
  346. data/lib/contrast/api.rb +17 -0
  347. data/lib/contrast/api/.gitkeep +0 -0
  348. data/lib/contrast/api/connection_status.rb +49 -0
  349. data/lib/contrast/api/socket.rb +43 -0
  350. data/lib/contrast/api/speedracer.rb +206 -0
  351. data/lib/contrast/api/tcp_socket.rb +31 -0
  352. data/lib/contrast/api/unix_socket.rb +25 -0
  353. data/lib/contrast/common_agent_configuration.rb +86 -0
  354. data/lib/contrast/components/agent.rb +85 -0
  355. data/lib/contrast/components/app_context.rb +188 -0
  356. data/lib/contrast/components/assess.rb +67 -0
  357. data/lib/contrast/components/config.rb +135 -0
  358. data/lib/contrast/components/contrast_service.rb +113 -0
  359. data/lib/contrast/components/heap_dump.rb +34 -0
  360. data/lib/contrast/components/interface.rb +178 -0
  361. data/lib/contrast/components/inventory.rb +23 -0
  362. data/lib/contrast/components/logger.rb +92 -0
  363. data/lib/contrast/components/protect.rb +38 -0
  364. data/lib/contrast/components/sampling.rb +41 -0
  365. data/lib/contrast/components/scope.rb +106 -0
  366. data/lib/contrast/components/settings.rb +140 -0
  367. data/lib/contrast/config.rb +33 -0
  368. data/lib/contrast/config/agent_configuration.rb +24 -0
  369. data/lib/contrast/config/application_configuration.rb +27 -0
  370. data/lib/contrast/config/assess_configuration.rb +22 -0
  371. data/lib/contrast/config/assess_rules_configuration.rb +18 -0
  372. data/lib/contrast/config/base_configuration.rb +105 -0
  373. data/lib/contrast/config/default_value.rb +16 -0
  374. data/lib/contrast/config/exception_configuration.rb +21 -0
  375. data/lib/contrast/config/heap_dump_configuration.rb +23 -0
  376. data/lib/contrast/config/inventory_configuration.rb +20 -0
  377. data/lib/contrast/config/logger_configuration.rb +20 -0
  378. data/lib/contrast/config/protect_configuration.rb +20 -0
  379. data/lib/contrast/config/protect_rule_configuration.rb +37 -0
  380. data/lib/contrast/config/protect_rules_configuration.rb +30 -0
  381. data/lib/contrast/config/root_configuration.rb +26 -0
  382. data/lib/contrast/config/ruby_configuration.rb +39 -0
  383. data/lib/contrast/config/sampling_configuration.rb +22 -0
  384. data/lib/contrast/config/server_configuration.rb +23 -0
  385. data/lib/contrast/config/service_configuration.rb +22 -0
  386. data/lib/contrast/configuration.rb +214 -0
  387. data/lib/contrast/core_extensions/assess.rb +51 -0
  388. data/lib/contrast/core_extensions/assess/array.rb +58 -0
  389. data/lib/contrast/core_extensions/assess/assess_extension.rb +145 -0
  390. data/lib/contrast/core_extensions/assess/basic_object.rb +15 -0
  391. data/lib/contrast/core_extensions/assess/erb.rb +42 -0
  392. data/lib/contrast/core_extensions/assess/exec_trigger.rb +48 -0
  393. data/lib/contrast/core_extensions/assess/fiber.rb +125 -0
  394. data/lib/contrast/core_extensions/assess/hash.rb +22 -0
  395. data/lib/contrast/core_extensions/assess/kernel.rb +95 -0
  396. data/lib/contrast/core_extensions/assess/module.rb +14 -0
  397. data/lib/contrast/core_extensions/assess/regexp.rb +206 -0
  398. data/lib/contrast/core_extensions/assess/string.rb +75 -0
  399. data/lib/contrast/core_extensions/assess/tilt_template_trigger.rb +73 -0
  400. data/lib/contrast/core_extensions/delegator.rb +14 -0
  401. data/lib/contrast/core_extensions/eval_trigger.rb +52 -0
  402. data/lib/contrast/core_extensions/inventory.rb +22 -0
  403. data/lib/contrast/core_extensions/inventory/datastores.rb +37 -0
  404. data/lib/contrast/core_extensions/module.rb +42 -0
  405. data/lib/contrast/core_extensions/object.rb +27 -0
  406. data/lib/contrast/core_extensions/protect.rb +20 -0
  407. data/lib/contrast/core_extensions/protect/applies_command_injection_rule.rb +70 -0
  408. data/lib/contrast/core_extensions/protect/applies_deserialization_rule.rb +58 -0
  409. data/lib/contrast/core_extensions/protect/applies_no_sqli_rule.rb +81 -0
  410. data/lib/contrast/core_extensions/protect/applies_path_traversal_rule.rb +119 -0
  411. data/lib/contrast/core_extensions/protect/applies_sqli_rule.rb +63 -0
  412. data/lib/contrast/core_extensions/protect/applies_xxe_rule.rb +141 -0
  413. data/lib/contrast/core_extensions/protect/kernel.rb +30 -0
  414. data/lib/contrast/core_extensions/protect/psych.rb +7 -0
  415. data/lib/contrast/core_extensions/thread.rb +31 -0
  416. data/lib/contrast/internal_exception.rb +8 -0
  417. data/lib/contrast/rails_extensions/assess/action_controller_inheritance.rb +48 -0
  418. data/lib/contrast/rails_extensions/assess/active_record.rb +32 -0
  419. data/lib/contrast/rails_extensions/assess/active_record_named.rb +61 -0
  420. data/lib/contrast/rails_extensions/assess/configuration.rb +26 -0
  421. data/lib/contrast/rails_extensions/buffer.rb +30 -0
  422. data/lib/contrast/rails_extensions/rack.rb +45 -0
  423. data/lib/contrast/security_exception.rb +14 -0
  424. data/lib/contrast/sinatra_extensions/assess/cookie.rb +26 -0
  425. data/lib/contrast/sinatra_extensions/inventory/sinatra_base.rb +59 -0
  426. data/lib/contrast/tasks/service.rb +95 -0
  427. data/lib/contrast/utils/assess/sampling_util.rb +96 -0
  428. data/lib/contrast/utils/assess/tracking_util.rb +39 -0
  429. data/lib/contrast/utils/boolean_util.rb +33 -0
  430. data/lib/contrast/utils/cache.rb +69 -0
  431. data/lib/contrast/utils/class_util.rb +58 -0
  432. data/lib/contrast/utils/comment_range.rb +19 -0
  433. data/lib/contrast/utils/data_store_util.rb +23 -0
  434. data/lib/contrast/utils/duck_utils.rb +58 -0
  435. data/lib/contrast/utils/env_configuration_item.rb +52 -0
  436. data/lib/contrast/utils/environment_util.rb +152 -0
  437. data/lib/contrast/utils/freeze_util.rb +36 -0
  438. data/lib/contrast/utils/gemfile_reader.rb +191 -0
  439. data/lib/contrast/utils/hash_digest.rb +148 -0
  440. data/lib/contrast/utils/heap_dump_util.rb +113 -0
  441. data/lib/contrast/utils/invalid_configuration_util.rb +88 -0
  442. data/lib/contrast/utils/inventory_util.rb +126 -0
  443. data/lib/contrast/utils/io_util.rb +61 -0
  444. data/lib/contrast/utils/object_share.rb +117 -0
  445. data/lib/contrast/utils/operating_environment.rb +38 -0
  446. data/lib/contrast/utils/os.rb +49 -0
  447. data/lib/contrast/utils/path_util.rb +151 -0
  448. data/lib/contrast/utils/performs_logging.rb +152 -0
  449. data/lib/contrast/utils/preflight_util.rb +13 -0
  450. data/lib/contrast/utils/prevent_serialization.rb +52 -0
  451. data/lib/contrast/utils/rack_assess_session_cookie.rb +104 -0
  452. data/lib/contrast/utils/rails_assess_configuration.rb +95 -0
  453. data/lib/contrast/utils/random_util.rb +22 -0
  454. data/lib/contrast/utils/resource_loader.rb +23 -0
  455. data/lib/contrast/utils/ruby_ast_rewriter.rb +74 -0
  456. data/lib/contrast/utils/scope_util.rb +99 -0
  457. data/lib/contrast/utils/service_response_util.rb +116 -0
  458. data/lib/contrast/utils/service_sender_util.rb +98 -0
  459. data/lib/contrast/utils/sha256_builder.rb +69 -0
  460. data/lib/contrast/utils/sinatra_helper.rb +49 -0
  461. data/lib/contrast/utils/stack_trace_utils.rb +209 -0
  462. data/lib/contrast/utils/string_utils.rb +72 -0
  463. data/lib/contrast/utils/tag_util.rb +139 -0
  464. data/lib/contrast/utils/thread_tracker.rb +54 -0
  465. data/lib/contrast/utils/timer.rb +78 -0
  466. data/resources/assess/policy.json +1673 -0
  467. data/resources/csrf/inject.js +44 -0
  468. data/resources/deadzone/policy.json +55 -0
  469. data/resources/factory-bot-spec/spec_helper.rb +30 -0
  470. data/resources/inventory/policy.json +110 -0
  471. data/resources/protect/policy.json +417 -0
  472. data/resources/rubocops/kernel/catch_cop.rb +37 -0
  473. data/resources/rubocops/kernel/require_cop.rb +37 -0
  474. data/resources/rubocops/kernel/require_relative_cop.rb +33 -0
  475. data/resources/rubocops/module/autoload_cop.rb +37 -0
  476. data/resources/rubocops/module/const_defined_cop.rb +37 -0
  477. data/resources/rubocops/module/const_get_cop.rb +37 -0
  478. data/resources/rubocops/module/const_set_cop.rb +37 -0
  479. data/resources/rubocops/module/constants_cop.rb +37 -0
  480. data/resources/rubocops/module/name_cop.rb +37 -0
  481. data/resources/rubocops/object/class_cop.rb +37 -0
  482. data/resources/rubocops/object/freeze_cop.rb +37 -0
  483. data/resources/rubocops/object/frozen_cop.rb +37 -0
  484. data/resources/rubocops/object/is_a_cop.rb +37 -0
  485. data/resources/rubocops/object/method_cop.rb +37 -0
  486. data/resources/rubocops/object/respond_to_cop.rb +37 -0
  487. data/resources/rubocops/object/singleton_class_cop.rb +37 -0
  488. data/resources/rubocops/regexp/spelling_cop.rb +44 -0
  489. data/resources/rubocops/thread/new_cop.rb +39 -0
  490. data/resources/ruby-spec/ancestors_spec.rb +70 -0
  491. data/resources/ruby-spec/modulo_spec.rb +831 -0
  492. data/resources/ruby-spec/parameters_spec.rb +261 -0
  493. data/resources/ruby-spec/ruby_spec_spec_helper.rb +35 -0
  494. data/resources/test_marker.txt +1 -0
  495. data/ruby-agent.gemspec +129 -0
  496. data/service_executables/.gitkeep +0 -0
  497. data/service_executables/VERSION +1 -0
  498. data/service_executables/linux/contrast-service +0 -0
  499. data/service_executables/mac/contrast-service +0 -0
  500. metadata +945 -0
@@ -0,0 +1,98 @@
1
+ # Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
+ # frozen_string_literal: true
3
+
4
+ cs__scoped_require 'contrast/components/interface'
5
+
6
+ module Contrast
7
+ module Utils
8
+ # This module keeps a background thread, initialized at startup, running. This thread is
9
+ # responsible for pulling a message off the queue, sending that message to SpeedRacer, and
10
+ # processing the response returned back from SpeedRacer. When we didn't know our config
11
+ # values, we may have queued assess messages to send later. This thread is also
12
+ # responsible for checking to see if we are now ready to send any of these assess messages
13
+ # to SpeedRacer.
14
+ module ServiceSenderUtil
15
+ include Contrast::Components::Interface
16
+ access_component :contrast_service, :logging, :analysis, :agent
17
+
18
+ class << self
19
+ attr_reader :assess_messages, :ready_messages_queue
20
+
21
+ def push_to_ready_queue msg
22
+ # Since a message may try to be pushed before sending_thread starts up, we need to initialize
23
+ # the queue on first message sent
24
+ @ready_messages_queue ||= Queue.new
25
+ ready_messages_queue.push msg
26
+ end
27
+
28
+ def sending_thread
29
+ # in case we got here before a message attempted to be sent, let's make sure these are initialized
30
+ @ready_messages_queue ||= Queue.new
31
+ @assess_messages ||= []
32
+
33
+ @_sender_thread ||= Contrast::Agent::Thread.new do
34
+ loop do
35
+ check_assess_queue if assess_messages # don't bother checking if assess queue is already cleared
36
+ # if ready messages queue is empty, calling thread is suspended until a message is pushed onto queue
37
+ msg = ready_messages_queue.pop
38
+ begin
39
+ response = Contrast::Agent::FeatureState.instance.client.send_to_speedracer msg
40
+ Contrast::Utils::ServiceResponseUtil.process_response(response) if response
41
+ rescue StandardError => e
42
+ logger.error(e, 'Could not send message to service from service sender thread.')
43
+ end
44
+ end
45
+ end
46
+ logger.debug(nil, 'Started background sending thread.')
47
+ end
48
+ alias_method :start, :sending_thread
49
+
50
+ def stop
51
+ Thread.kill(@_sender_thread) if @_sender_thread&.alive?
52
+ end
53
+
54
+ def add_to_assess_messages msg
55
+ # This list holds messages containing assess findings. We currently
56
+ # do not know if the agent is running in assess, so until we do then
57
+ # we must keep the messages stored here.
58
+ @assess_messages ||= []
59
+ assess_messages << msg
60
+ end
61
+
62
+ private
63
+
64
+ def check_assess_queue
65
+ return unless AGENT.ready?
66
+
67
+ if ASSESS.enabled?
68
+ assess_messages.each do |msg|
69
+ update_queued_finding msg
70
+ ready_messages_queue.push msg # this message is ready to be sent to SR
71
+ end
72
+ end
73
+ @assess_messages = nil # clear out queue, we no longer need it
74
+ end
75
+
76
+ # When we queued up findings, we didn't have access to a configuration
77
+ # object. As such, we have to make decisions now for those findings.
78
+ def update_queued_finding msg
79
+ # Findings only exist in activity messages
80
+ return unless msg.is_a?(Contrast::Api::Dtm::Activity)
81
+
82
+ # So set their tags
83
+ msg.finding_tags = Contrast::Utils::StringUtils.force_utf8(ASSESS.tags)
84
+
85
+ # and see if they're even enabled
86
+ check = msg.findings.dup
87
+ check.each do |finding|
88
+ msg.findings.delete(finding) if ASSESS.rule_disabled?(finding.rule_id)
89
+ end
90
+
91
+ msg.findings.each do |finding|
92
+ finding.session_id = Contrast::Agent::FeatureState.instance.current_session_id
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,69 @@
1
+ # Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
+ # frozen_string_literal: true
3
+
4
+ cs__scoped_require 'singleton'
5
+ cs__scoped_require 'contrast/utils/object_share'
6
+
7
+ module Contrast
8
+ module Utils
9
+ # Utility methods for building and caching hashes from strings
10
+ class Sha256Builder
11
+ include Singleton
12
+
13
+ def initialize
14
+ @sha256_cache = {}
15
+ @gem_hash_cache = {}
16
+ end
17
+
18
+ # Return a list of "source" files. Ignore metadata files as well as files
19
+ # in the spec, test or exe directories. Could potentially miss important
20
+ # files but good enough for the time being.
21
+ PATHS = '{lib,bin,ext}/**/*.{rb,c,h,c++,cpp,java,rs}'
22
+ def files path
23
+ if Dir.exist?(path)
24
+ Dir.glob(File.join(path, PATHS))
25
+ else
26
+ []
27
+ end
28
+ end
29
+
30
+ # Generate a SHA256 hash of the combined source code of this Gem
31
+ def sha256 path
32
+ return nil unless path
33
+ return nil unless File.exist?(path) && !File.directory?(path)
34
+
35
+ @sha256_cache[path] ||= Digest::SHA256.file(path).to_s
36
+ end
37
+
38
+ def build_from_spec spec
39
+ name = spec.file_name.to_s
40
+ cached = @gem_hash_cache[name]
41
+ return cached if cached
42
+
43
+ gem_path = File.join(cache_dir(spec), name)
44
+ hash = sha256(gem_path)
45
+
46
+ @gem_hash_cache[name] = hash
47
+ hash
48
+ end
49
+
50
+ def cache_dir spec
51
+ gems_dir = spec.gems_dir
52
+ parent_dir = File.dirname(gems_dir)
53
+ File.join(parent_dir, Contrast::Utils::ObjectShare::CACHE)
54
+ end
55
+
56
+ def self.files path
57
+ instance.files(path)
58
+ end
59
+
60
+ def self.sha256 path
61
+ instance.sha256(path)
62
+ end
63
+
64
+ def self.build_from_spec spec
65
+ instance.build_from_spec(spec)
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,49 @@
1
+ # Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
+ # frozen_string_literal: true
3
+
4
+ module Contrast
5
+ module Utils
6
+ # This module is to help perform sometimes necessary tasks specific to Sinatra
7
+ module SinatraHelper
8
+ SINATRA_VIEWS = [
9
+ ['public/stylesheets', '*.scss', %w[SASS]],
10
+ ['views', '*.html', %w[HTML5]],
11
+ ['views', '*.html.erb', %w[HTML5 ERB]],
12
+ ['views', '*.html.haml', %w[HTML5 HAML]],
13
+ ['public', '*.html', %w[HTML5]]
14
+ ].cs__freeze
15
+
16
+ def self.app_class
17
+ @_app_class ||= begin
18
+ return nil unless defined?(Sinatra) && defined?(Sinatra::Base)
19
+
20
+ sinatra_layers = ObjectSpace.each_object(Sinatra::Base).to_a
21
+ result_layer = sinatra_layers.find { |layer| layer.app.nil? }
22
+ result_layer
23
+ end
24
+ end
25
+
26
+ def self.scannable_view_dirs
27
+ @_scannable_view_dirs ||= begin
28
+ views = SINATRA_VIEWS.dup
29
+ views << [view_directory, '*.erb', %w[HTML5 ERB]] if view_directory
30
+ views << [view_directory, '*.haml', %w[HTML5 HAML]] if view_directory
31
+ views << [public_directory, '*.html', %w[HTML5]] if public_directory
32
+ views
33
+ end
34
+ end
35
+
36
+ def self.view_directory
37
+ @_view_directory ||= begin
38
+ app_class&.settings&.views
39
+ end
40
+ end
41
+
42
+ def self.public_directory
43
+ @_public_directory ||= begin
44
+ app_class&.settings&.public_dir
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,209 @@
1
+ # Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
+ # frozen_string_literal: true
3
+
4
+ cs__scoped_require 'contrast/utils/object_share'
5
+ cs__scoped_require 'contrast/api'
6
+
7
+ module Contrast
8
+ module Utils
9
+ # Utilities for converting ruby stack trace into DTMs
10
+ class StackTraceUtils
11
+ CONTRAST_MARKER = 'contrast/core_extensions'
12
+ MONKEYPATCH_MARKER = 'cs__'
13
+
14
+ # TODO: RUBY-532
15
+ CLASSNAME_CACHE = Contrast::Utils::Cache.new
16
+
17
+ # need lib here to separate from specs
18
+ AGENT_CLASS_MARKERS = %w[
19
+ /lib/contrast/
20
+ ].cs__freeze
21
+
22
+ def self.custom_code_context?
23
+ stack = Kernel.caller(0, 15)
24
+ i = 0
25
+ while i < stack.length
26
+ stack_element = stack[i]
27
+ if stack_element.include?('contrast')
28
+ # Noop
29
+ elsif stack_element.include?('gems')
30
+ return false
31
+ else
32
+ return true
33
+ end
34
+ i += 1
35
+ end
36
+ end
37
+
38
+ def self.build(
39
+ skip: 0,
40
+ depth: 10,
41
+ ignore: false,
42
+ ignore_strings: AGENT_CLASS_MARKERS,
43
+ class_lookup: false,
44
+ rasp_element: true)
45
+
46
+ stack = caller(skip.to_i, depth.to_i)
47
+ return [] unless stack
48
+
49
+ stack = reject_caller_entries(stack, ignore_strings) if ignore
50
+ stack.map! do |entry|
51
+ element = rasp_or_assess(rasp_element)
52
+ element = fill_element(element, entry, class_lookup)
53
+ element
54
+ end
55
+ stack.compact!
56
+ stack
57
+ end
58
+
59
+ def self.reject_caller_entries stack, ignore_strings
60
+ return stack unless ignore_strings&.any?
61
+
62
+ stack.reject do |entry|
63
+ ignore_strings.any? { |marker| entry.include?(marker) } ||
64
+ entry.include?(MONKEYPATCH_MARKER)
65
+ end
66
+ end
67
+
68
+ def self.rasp_or_assess rasp_element
69
+ if rasp_element
70
+ Contrast::Api::Dtm::StackTraceElement.new
71
+ else
72
+ Contrast::Api::Dtm::TraceStack.new
73
+ end
74
+ end
75
+
76
+ def self.to_dtm_stack stack_locations: nil, rasp_element: true
77
+ return [] unless stack_locations
78
+
79
+ stack_locations = reject_locations(stack_locations)
80
+ stack_locations.map! do |caller_location|
81
+ element = rasp_or_assess(rasp_element)
82
+ element = fill_loc_element(element, caller_location)
83
+ element
84
+ end
85
+ stack_locations.compact!
86
+ stack_locations
87
+ end
88
+
89
+ def self.reject_locations stack_locations
90
+ stack_locations.reject do |entry|
91
+ class_path = entry.path
92
+ method = entry.label
93
+ AGENT_CLASS_MARKERS.any? { |marker| class_path.include?(marker) } ||
94
+ method.include?(MONKEYPATCH_MARKER)
95
+ end
96
+ end
97
+
98
+ # "/.rvm/rubies/ruby-1.9.3-p551/lib/ruby/1.9.1/irb/workspace.rb:80:in `eval'"
99
+ def self.fill_element element, str, class_lookup
100
+ return element if str.nil? || str.strip.empty?
101
+
102
+ path, line, method = str.split(':')
103
+ element.line_number = line.to_i
104
+ file_name = filename_from_path(path)
105
+ element.file_name = Contrast::Utils::StringUtils.force_utf8(file_name)
106
+ declaring_class = best_classname(path, element.file_name) if class_lookup
107
+ element.declaring_class = Contrast::Utils::StringUtils.force_utf8(declaring_class)
108
+ method_name = find_method_name(method)
109
+ element.method_name = Contrast::Utils::StringUtils.force_utf8(method_name)
110
+ element
111
+ rescue StandardError
112
+ # NOOP
113
+ nil
114
+ end
115
+
116
+ def self.best_classname path, file
117
+ name = first_class(path)
118
+ name || look_like_classname(file)
119
+ end
120
+
121
+ # "/.rvm/rubies/ruby-1.9.3-p551/lib/ruby/1.9.1/irb/workspace.rb:80:in `eval'"
122
+ def self.fill_loc_element element, caller_location
123
+ return element unless caller_location
124
+
125
+ lineno = caller_location.lineno
126
+ element.line_number = lineno.to_i
127
+ path = caller_location.path
128
+ path = Contrast::Utils::StringUtils.force_utf8(path)
129
+ file_name = filename_from_path(path)
130
+ element.file_name = Contrast::Utils::StringUtils.force_utf8(file_name)
131
+ element.declaring_class = path
132
+ label = caller_location.label
133
+ element.method_name = Contrast::Utils::StringUtils.force_utf8(label)
134
+ element
135
+ rescue StandardError
136
+ # NOOP
137
+ nil
138
+ end
139
+
140
+ def self.filename_from_path path
141
+ file_idx = path.rindex(Contrast::Utils::ObjectShare::SLASH)
142
+ if file_idx
143
+ txt_idx = file_idx + 1
144
+ path[txt_idx, path.length - txt_idx]
145
+ else
146
+ path
147
+ end
148
+ end
149
+
150
+ # Bit of a HACK: Given a path to a file, assume that the first line in the
151
+ # form `class Name` is the class that was loaded. True most of the time.
152
+ #
153
+ # Using regexp here is expensive b/c it creates a ton of new Strings. We're
154
+ # trying to avoid that, so our guess is a little more clumsy, but should
155
+ # still work.
156
+ #
157
+ # Note: Might need to tune end marker to include /n
158
+ # based on: /\s*class\s+([_[:alpha:]][_[:alnum:]]*)/m
159
+ CLASS_MARKER = ' class '
160
+ CLASS_END_MARKER = Contrast::Utils::ObjectShare::NEW_LINE
161
+ def self.first_class path
162
+ return nil if path.nil? || path.empty?
163
+
164
+ name = CLASSNAME_CACHE[path]
165
+ return name if name
166
+
167
+ text = File.read(path)
168
+ name = parse_string(text, CLASS_MARKER, CLASS_END_MARKER)
169
+ CLASSNAME_CACHE[path] = name if name
170
+ name
171
+ end
172
+
173
+ RB_MARKER = '.rb'
174
+ # Convert a file to look like a classname
175
+ # If the file ends w/ '.rb', trim that off
176
+ # If the file doesn't start with a capital letter,
177
+ # capitalize it
178
+ def self.look_like_classname file
179
+ file = file.to_s
180
+ file[0].capitalize + (file.end_with?(RB_MARKER) ? file.slice(1..-4) : file.slice(1..-1))
181
+ end
182
+
183
+ # Using regexp here is expensive b/c it creates a ton of new Strings. We're
184
+ # trying to avoid that, so our guess is a little more clumsy, but should
185
+ # still work.
186
+ #
187
+ # Note: Might need to tune end marker to include /n
188
+ # based on: /[`]([^']*)[']/
189
+ METHOD_MARKER = Contrast::Utils::ObjectShare::TICK
190
+ METHOD_END_MARKER = Contrast::Utils::ObjectShare::COMMA
191
+ def self.find_method_name method
192
+ parse_string(method, METHOD_MARKER, METHOD_END_MARKER)
193
+ end
194
+
195
+ def self.parse_string string, start_marker, end_marker
196
+ return nil unless string
197
+
198
+ start_idx = string.index(start_marker)
199
+ return nil unless start_idx
200
+
201
+ start_idx += start_marker.length # account for marker length
202
+ end_idx = string.index(end_marker, start_idx)
203
+ end_idx ||= string.length
204
+ len = end_idx - start_idx
205
+ string[start_idx, len]
206
+ end
207
+ end
208
+ end
209
+ end
@@ -0,0 +1,72 @@
1
+ # Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
+ # frozen_string_literal: true
3
+
4
+ module Contrast
5
+ module Utils
6
+ # Utilities for encoding and normalizing strings
7
+ class StringUtils
8
+ UTF8 = 'utf-8'
9
+ HTTP_PREFIX = 'HTTP-'
10
+
11
+ # Convenience method. We assume that we're working on Strings or tags
12
+ # String representations of things. To that end, we'll to_s anything
13
+ # that comes in before returning its length.
14
+ #
15
+ # But don't worry though, String.to_s just returns self. teehee
16
+ def self.ret_length string
17
+ string.nil? ? 0 : string.to_s.length
18
+ end
19
+
20
+ # Protobuf has a very strict typing. Nil is not a String and will throw
21
+ # an exception if you try to set it. Use this to be safe.
22
+ # Uses the object share to avoid creating several new strings per request
23
+ def self.protobuf_safe_string string
24
+ string.nil? ? Contrast::Utils::ObjectShare::EMPTY_STRING : string.to_s
25
+ end
26
+
27
+ # Truncate a string to 255 characters max length
28
+ def self.truncate str, default = Contrast::Utils::ObjectShare::EMPTY_STRING
29
+ return default if str.nil?
30
+
31
+ str.to_s[0..255]
32
+ end
33
+
34
+ def self.force_utf8 str, logger = nil
35
+ return Contrast::Utils::ObjectShare::EMPTY_STRING unless str
36
+
37
+ str = str.to_s
38
+ if str.encoding == Encoding::UTF_8
39
+ str = str.encode(UTF8, invalid: :replace, undef: :replace) unless str.valid_encoding?
40
+ else
41
+ str = str.encode(UTF8, str.encoding, invalid: :replace, undef: :replace)
42
+ end
43
+ str.to_s
44
+ rescue StandardError => e
45
+ # We were unable to switch the String to a UTF-8 format.
46
+ # Return non-nil so as not to throw an exception later when trying
47
+ # to do regexp or other compares on the String
48
+ logger&.debug "Unable to change '#{ str }' to valid UTF-8: #{ e.message }"
49
+
50
+ Contrast::Utils::ObjectShare::EMPTY_STRING
51
+ end
52
+
53
+ # Given a string return a normalized version of that string.
54
+ # Keys are memoized so that the normalization process doesn't need
55
+ # to happen every time.
56
+ def self.normalized_key str
57
+ return nil unless str
58
+
59
+ str = str.to_s
60
+ @_normalized_keys ||= {}
61
+ if @_normalized_keys.key?(str)
62
+ @_normalized_keys[str]
63
+ else
64
+ up = str.upcase.strip
65
+ up = up.gsub(/[_-]/, '-')
66
+ up = up[5..-1] if up.start_with?(HTTP_PREFIX)
67
+ @_normalized_keys[str] = up
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end