immunio 1.2.1 → 2.0.2

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 (291) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +13 -5
  3. data/ext/immunio/Rakefile +14 -6
  4. data/lib/immunio/context.rb +2 -0
  5. data/lib/immunio/plugins/action_view.rb +7 -668
  6. data/lib/immunio/plugins/action_view/action_view.rb +22 -0
  7. data/lib/immunio/plugins/action_view/active_support_hash.rb +29 -0
  8. data/lib/immunio/plugins/action_view/cache_store.rb +24 -0
  9. data/lib/immunio/plugins/action_view/erubi.rb +38 -0
  10. data/lib/immunio/plugins/action_view/erubis.rb +39 -0
  11. data/lib/immunio/plugins/action_view/fragment_caching.rb +29 -0
  12. data/lib/immunio/plugins/action_view/haml.rb +46 -0
  13. data/lib/immunio/plugins/action_view/slim.rb +42 -0
  14. data/lib/immunio/plugins/action_view/template.rb +431 -0
  15. data/lib/immunio/plugins/action_view/template_rendering.rb +45 -0
  16. data/lib/immunio/plugins/http_tracker.rb +2 -0
  17. data/lib/immunio/plugins/io.rb +34 -0
  18. data/lib/immunio/version.rb +1 -1
  19. data/lua-hooks/Makefile +36 -9
  20. data/lua-hooks/ext/luajit/COPYRIGHT +1 -1
  21. data/lua-hooks/ext/luajit/Makefile +22 -15
  22. data/lua-hooks/ext/luajit/README +2 -2
  23. data/lua-hooks/ext/luajit/doc/bluequad-print.css +1 -1
  24. data/lua-hooks/ext/luajit/doc/bluequad.css +1 -1
  25. data/lua-hooks/ext/luajit/doc/changes.html +69 -3
  26. data/lua-hooks/ext/luajit/doc/contact.html +10 -3
  27. data/lua-hooks/ext/luajit/doc/ext_c_api.html +2 -2
  28. data/lua-hooks/ext/luajit/doc/ext_ffi.html +2 -2
  29. data/lua-hooks/ext/luajit/doc/ext_ffi_api.html +2 -2
  30. data/lua-hooks/ext/luajit/doc/ext_ffi_semantics.html +3 -4
  31. data/lua-hooks/ext/luajit/doc/ext_ffi_tutorial.html +2 -2
  32. data/lua-hooks/ext/luajit/doc/ext_jit.html +3 -3
  33. data/lua-hooks/ext/luajit/doc/ext_profiler.html +2 -2
  34. data/lua-hooks/ext/luajit/doc/extensions.html +47 -20
  35. data/lua-hooks/ext/luajit/doc/faq.html +2 -2
  36. data/lua-hooks/ext/luajit/doc/install.html +74 -45
  37. data/lua-hooks/ext/luajit/doc/luajit.html +5 -5
  38. data/lua-hooks/ext/luajit/doc/running.html +3 -3
  39. data/lua-hooks/ext/luajit/doc/status.html +13 -8
  40. data/lua-hooks/ext/luajit/dynasm/dasm_arm.h +1 -1
  41. data/lua-hooks/ext/luajit/dynasm/dasm_arm.lua +1 -1
  42. data/lua-hooks/ext/luajit/dynasm/dasm_arm64.h +1 -1
  43. data/lua-hooks/ext/luajit/dynasm/dasm_arm64.lua +1 -1
  44. data/lua-hooks/ext/luajit/dynasm/dasm_mips.h +8 -5
  45. data/lua-hooks/ext/luajit/dynasm/dasm_mips.lua +66 -11
  46. data/lua-hooks/ext/luajit/dynasm/dasm_mips64.lua +12 -0
  47. data/lua-hooks/ext/luajit/dynasm/dasm_ppc.h +1 -1
  48. data/lua-hooks/ext/luajit/dynasm/dasm_ppc.lua +1 -1
  49. data/lua-hooks/ext/luajit/dynasm/dasm_proto.h +1 -1
  50. data/lua-hooks/ext/luajit/dynasm/dasm_x64.lua +1 -1
  51. data/lua-hooks/ext/luajit/dynasm/dasm_x86.h +1 -1
  52. data/lua-hooks/ext/luajit/dynasm/dasm_x86.lua +5 -1
  53. data/lua-hooks/ext/luajit/dynasm/dynasm.lua +2 -2
  54. data/lua-hooks/ext/luajit/etc/luajit.1 +1 -1
  55. data/lua-hooks/ext/luajit/etc/luajit.pc +1 -1
  56. data/lua-hooks/ext/luajit/src/Makefile +15 -11
  57. data/lua-hooks/ext/luajit/src/Makefile.dep +16 -16
  58. data/lua-hooks/ext/luajit/src/host/buildvm.c +2 -2
  59. data/lua-hooks/ext/luajit/src/host/buildvm.h +1 -1
  60. data/lua-hooks/ext/luajit/src/host/buildvm_asm.c +9 -4
  61. data/lua-hooks/ext/luajit/src/host/buildvm_fold.c +2 -2
  62. data/lua-hooks/ext/luajit/src/host/buildvm_lib.c +1 -1
  63. data/lua-hooks/ext/luajit/src/host/buildvm_libbc.h +14 -3
  64. data/lua-hooks/ext/luajit/src/host/buildvm_peobj.c +27 -3
  65. data/lua-hooks/ext/luajit/src/host/genlibbc.lua +1 -1
  66. data/lua-hooks/ext/luajit/src/host/genminilua.lua +6 -5
  67. data/lua-hooks/ext/luajit/src/host/minilua.c +1 -1
  68. data/lua-hooks/ext/luajit/src/jit/bc.lua +1 -1
  69. data/lua-hooks/ext/luajit/src/jit/bcsave.lua +8 -8
  70. data/lua-hooks/ext/luajit/src/jit/dis_arm.lua +2 -2
  71. data/lua-hooks/ext/luajit/src/jit/dis_arm64.lua +1216 -0
  72. data/lua-hooks/ext/luajit/src/jit/dis_arm64be.lua +12 -0
  73. data/lua-hooks/ext/luajit/src/jit/dis_mips.lua +35 -20
  74. data/lua-hooks/ext/luajit/src/jit/dis_mips64.lua +17 -0
  75. data/lua-hooks/ext/luajit/src/jit/dis_mips64el.lua +17 -0
  76. data/lua-hooks/ext/luajit/src/jit/dis_mipsel.lua +1 -1
  77. data/lua-hooks/ext/luajit/src/jit/dis_ppc.lua +2 -2
  78. data/lua-hooks/ext/luajit/src/jit/dis_x64.lua +1 -1
  79. data/lua-hooks/ext/luajit/src/jit/dis_x86.lua +7 -4
  80. data/lua-hooks/ext/luajit/src/jit/dump.lua +17 -12
  81. data/lua-hooks/ext/luajit/src/jit/p.lua +3 -2
  82. data/lua-hooks/ext/luajit/src/jit/v.lua +2 -2
  83. data/lua-hooks/ext/luajit/src/jit/zone.lua +1 -1
  84. data/lua-hooks/ext/luajit/src/lauxlib.h +14 -20
  85. data/lua-hooks/ext/luajit/src/lib_aux.c +38 -27
  86. data/lua-hooks/ext/luajit/src/lib_base.c +12 -5
  87. data/lua-hooks/ext/luajit/src/lib_bit.c +1 -1
  88. data/lua-hooks/ext/luajit/src/lib_debug.c +5 -5
  89. data/lua-hooks/ext/luajit/src/lib_ffi.c +2 -2
  90. data/lua-hooks/ext/luajit/src/lib_init.c +16 -16
  91. data/lua-hooks/ext/luajit/src/lib_io.c +6 -7
  92. data/lua-hooks/ext/luajit/src/lib_jit.c +14 -4
  93. data/lua-hooks/ext/luajit/src/lib_math.c +1 -5
  94. data/lua-hooks/ext/luajit/src/lib_os.c +1 -1
  95. data/lua-hooks/ext/luajit/src/lib_package.c +14 -23
  96. data/lua-hooks/ext/luajit/src/lib_string.c +1 -5
  97. data/lua-hooks/ext/luajit/src/lib_table.c +21 -1
  98. data/lua-hooks/ext/luajit/src/lj.supp +3 -3
  99. data/lua-hooks/ext/luajit/src/lj_alloc.c +174 -83
  100. data/lua-hooks/ext/luajit/src/lj_api.c +97 -18
  101. data/lua-hooks/ext/luajit/src/lj_arch.h +54 -22
  102. data/lua-hooks/ext/luajit/src/lj_asm.c +172 -53
  103. data/lua-hooks/ext/luajit/src/lj_asm.h +1 -1
  104. data/lua-hooks/ext/luajit/src/lj_asm_arm.h +19 -16
  105. data/lua-hooks/ext/luajit/src/lj_asm_arm64.h +2022 -0
  106. data/lua-hooks/ext/luajit/src/lj_asm_mips.h +564 -158
  107. data/lua-hooks/ext/luajit/src/lj_asm_ppc.h +19 -18
  108. data/lua-hooks/ext/luajit/src/lj_asm_x86.h +578 -92
  109. data/lua-hooks/ext/luajit/src/lj_bc.c +1 -1
  110. data/lua-hooks/ext/luajit/src/lj_bc.h +1 -1
  111. data/lua-hooks/ext/luajit/src/lj_bcdump.h +1 -1
  112. data/lua-hooks/ext/luajit/src/lj_bcread.c +1 -1
  113. data/lua-hooks/ext/luajit/src/lj_bcwrite.c +1 -1
  114. data/lua-hooks/ext/luajit/src/lj_buf.c +1 -1
  115. data/lua-hooks/ext/luajit/src/lj_buf.h +1 -1
  116. data/lua-hooks/ext/luajit/src/lj_carith.c +1 -1
  117. data/lua-hooks/ext/luajit/src/lj_carith.h +1 -1
  118. data/lua-hooks/ext/luajit/src/lj_ccall.c +172 -7
  119. data/lua-hooks/ext/luajit/src/lj_ccall.h +21 -5
  120. data/lua-hooks/ext/luajit/src/lj_ccallback.c +71 -17
  121. data/lua-hooks/ext/luajit/src/lj_ccallback.h +1 -1
  122. data/lua-hooks/ext/luajit/src/lj_cconv.c +4 -2
  123. data/lua-hooks/ext/luajit/src/lj_cconv.h +1 -1
  124. data/lua-hooks/ext/luajit/src/lj_cdata.c +7 -5
  125. data/lua-hooks/ext/luajit/src/lj_cdata.h +1 -1
  126. data/lua-hooks/ext/luajit/src/lj_clib.c +5 -5
  127. data/lua-hooks/ext/luajit/src/lj_clib.h +1 -1
  128. data/lua-hooks/ext/luajit/src/lj_cparse.c +11 -6
  129. data/lua-hooks/ext/luajit/src/lj_cparse.h +1 -1
  130. data/lua-hooks/ext/luajit/src/lj_crecord.c +70 -14
  131. data/lua-hooks/ext/luajit/src/lj_crecord.h +1 -1
  132. data/lua-hooks/ext/luajit/src/lj_ctype.c +1 -1
  133. data/lua-hooks/ext/luajit/src/lj_ctype.h +8 -8
  134. data/lua-hooks/ext/luajit/src/lj_debug.c +1 -1
  135. data/lua-hooks/ext/luajit/src/lj_debug.h +1 -1
  136. data/lua-hooks/ext/luajit/src/lj_def.h +6 -9
  137. data/lua-hooks/ext/luajit/src/lj_dispatch.c +3 -3
  138. data/lua-hooks/ext/luajit/src/lj_dispatch.h +2 -1
  139. data/lua-hooks/ext/luajit/src/lj_emit_arm.h +5 -4
  140. data/lua-hooks/ext/luajit/src/lj_emit_arm64.h +419 -0
  141. data/lua-hooks/ext/luajit/src/lj_emit_mips.h +100 -20
  142. data/lua-hooks/ext/luajit/src/lj_emit_ppc.h +4 -4
  143. data/lua-hooks/ext/luajit/src/lj_emit_x86.h +116 -25
  144. data/lua-hooks/ext/luajit/src/lj_err.c +34 -13
  145. data/lua-hooks/ext/luajit/src/lj_err.h +1 -1
  146. data/lua-hooks/ext/luajit/src/lj_errmsg.h +1 -1
  147. data/lua-hooks/ext/luajit/src/lj_ff.h +1 -1
  148. data/lua-hooks/ext/luajit/src/lj_ffrecord.c +58 -49
  149. data/lua-hooks/ext/luajit/src/lj_ffrecord.h +1 -1
  150. data/lua-hooks/ext/luajit/src/lj_frame.h +33 -6
  151. data/lua-hooks/ext/luajit/src/lj_func.c +4 -2
  152. data/lua-hooks/ext/luajit/src/lj_func.h +1 -1
  153. data/lua-hooks/ext/luajit/src/lj_gc.c +16 -7
  154. data/lua-hooks/ext/luajit/src/lj_gc.h +1 -1
  155. data/lua-hooks/ext/luajit/src/lj_gdbjit.c +31 -1
  156. data/lua-hooks/ext/luajit/src/lj_gdbjit.h +1 -1
  157. data/lua-hooks/ext/luajit/src/lj_ir.c +69 -96
  158. data/lua-hooks/ext/luajit/src/lj_ir.h +29 -18
  159. data/lua-hooks/ext/luajit/src/lj_ircall.h +24 -30
  160. data/lua-hooks/ext/luajit/src/lj_iropt.h +9 -9
  161. data/lua-hooks/ext/luajit/src/lj_jit.h +67 -9
  162. data/lua-hooks/ext/luajit/src/lj_lex.c +1 -1
  163. data/lua-hooks/ext/luajit/src/lj_lex.h +1 -1
  164. data/lua-hooks/ext/luajit/src/lj_lib.c +1 -1
  165. data/lua-hooks/ext/luajit/src/lj_lib.h +1 -1
  166. data/lua-hooks/ext/luajit/src/lj_load.c +1 -1
  167. data/lua-hooks/ext/luajit/src/lj_mcode.c +11 -10
  168. data/lua-hooks/ext/luajit/src/lj_mcode.h +1 -1
  169. data/lua-hooks/ext/luajit/src/lj_meta.c +1 -1
  170. data/lua-hooks/ext/luajit/src/lj_meta.h +1 -1
  171. data/lua-hooks/ext/luajit/src/lj_obj.c +1 -1
  172. data/lua-hooks/ext/luajit/src/lj_obj.h +7 -3
  173. data/lua-hooks/ext/luajit/src/lj_opt_dce.c +1 -1
  174. data/lua-hooks/ext/luajit/src/lj_opt_fold.c +84 -17
  175. data/lua-hooks/ext/luajit/src/lj_opt_loop.c +1 -1
  176. data/lua-hooks/ext/luajit/src/lj_opt_mem.c +3 -3
  177. data/lua-hooks/ext/luajit/src/lj_opt_narrow.c +24 -22
  178. data/lua-hooks/ext/luajit/src/lj_opt_sink.c +11 -6
  179. data/lua-hooks/ext/luajit/src/lj_opt_split.c +11 -2
  180. data/lua-hooks/ext/luajit/src/lj_parse.c +9 -7
  181. data/lua-hooks/ext/luajit/src/lj_parse.h +1 -1
  182. data/lua-hooks/ext/luajit/src/lj_profile.c +1 -1
  183. data/lua-hooks/ext/luajit/src/lj_profile.h +1 -1
  184. data/lua-hooks/ext/luajit/src/lj_record.c +201 -117
  185. data/lua-hooks/ext/luajit/src/lj_record.h +1 -1
  186. data/lua-hooks/ext/luajit/src/lj_snap.c +72 -26
  187. data/lua-hooks/ext/luajit/src/lj_snap.h +1 -1
  188. data/lua-hooks/ext/luajit/src/lj_state.c +6 -6
  189. data/lua-hooks/ext/luajit/src/lj_state.h +2 -2
  190. data/lua-hooks/ext/luajit/src/lj_str.c +1 -1
  191. data/lua-hooks/ext/luajit/src/lj_str.h +1 -1
  192. data/lua-hooks/ext/luajit/src/lj_strfmt.c +7 -3
  193. data/lua-hooks/ext/luajit/src/lj_strfmt.h +1 -1
  194. data/lua-hooks/ext/luajit/src/lj_strfmt_num.c +4 -3
  195. data/lua-hooks/ext/luajit/src/lj_strscan.c +1 -1
  196. data/lua-hooks/ext/luajit/src/lj_strscan.h +1 -1
  197. data/lua-hooks/ext/luajit/src/lj_tab.c +1 -2
  198. data/lua-hooks/ext/luajit/src/lj_tab.h +1 -1
  199. data/lua-hooks/ext/luajit/src/lj_target.h +3 -3
  200. data/lua-hooks/ext/luajit/src/lj_target_arm.h +1 -1
  201. data/lua-hooks/ext/luajit/src/lj_target_arm64.h +239 -7
  202. data/lua-hooks/ext/luajit/src/lj_target_mips.h +111 -22
  203. data/lua-hooks/ext/luajit/src/lj_target_ppc.h +1 -1
  204. data/lua-hooks/ext/luajit/src/lj_target_x86.h +21 -4
  205. data/lua-hooks/ext/luajit/src/lj_trace.c +63 -18
  206. data/lua-hooks/ext/luajit/src/lj_trace.h +2 -1
  207. data/lua-hooks/ext/luajit/src/lj_traceerr.h +1 -1
  208. data/lua-hooks/ext/luajit/src/lj_udata.c +1 -1
  209. data/lua-hooks/ext/luajit/src/lj_udata.h +1 -1
  210. data/lua-hooks/ext/luajit/src/lj_vm.h +5 -1
  211. data/lua-hooks/ext/luajit/src/lj_vmevent.c +1 -1
  212. data/lua-hooks/ext/luajit/src/lj_vmevent.h +1 -1
  213. data/lua-hooks/ext/luajit/src/lj_vmmath.c +1 -1
  214. data/lua-hooks/ext/luajit/src/ljamalg.c +1 -1
  215. data/lua-hooks/ext/luajit/src/lua.h +9 -1
  216. data/lua-hooks/ext/luajit/src/luaconf.h +3 -7
  217. data/lua-hooks/ext/luajit/src/luajit.c +69 -54
  218. data/lua-hooks/ext/luajit/src/luajit.h +4 -4
  219. data/lua-hooks/ext/luajit/src/lualib.h +1 -1
  220. data/lua-hooks/ext/luajit/src/msvcbuild.bat +12 -4
  221. data/lua-hooks/ext/luajit/src/vm_arm.dasc +1 -1
  222. data/lua-hooks/ext/luajit/src/vm_arm64.dasc +255 -32
  223. data/lua-hooks/ext/luajit/src/vm_mips.dasc +26 -23
  224. data/lua-hooks/ext/luajit/src/vm_mips64.dasc +5062 -0
  225. data/lua-hooks/ext/luajit/src/vm_ppc.dasc +1 -1
  226. data/lua-hooks/ext/luajit/src/vm_x64.dasc +24 -25
  227. data/lua-hooks/ext/luajit/src/vm_x86.dasc +77 -4
  228. data/lua-hooks/libluahooks.darwin.a +0 -0
  229. data/lua-hooks/libluahooks.linux.a +0 -0
  230. data/lua-hooks/options.mk +1 -1
  231. metadata +37 -77
  232. data/lua-hooks/ext/all.c +0 -69
  233. data/lua-hooks/ext/libinjection/COPYING +0 -37
  234. data/lua-hooks/ext/libinjection/libinjection.h +0 -65
  235. data/lua-hooks/ext/libinjection/libinjection_html5.c +0 -847
  236. data/lua-hooks/ext/libinjection/libinjection_html5.h +0 -54
  237. data/lua-hooks/ext/libinjection/libinjection_sqli.c +0 -2301
  238. data/lua-hooks/ext/libinjection/libinjection_sqli.h +0 -295
  239. data/lua-hooks/ext/libinjection/libinjection_sqli_data.h +0 -9349
  240. data/lua-hooks/ext/libinjection/libinjection_xss.c +0 -531
  241. data/lua-hooks/ext/libinjection/libinjection_xss.h +0 -21
  242. data/lua-hooks/ext/libinjection/lualib.c +0 -145
  243. data/lua-hooks/ext/libinjection/module.mk +0 -5
  244. data/lua-hooks/ext/lpeg/HISTORY +0 -96
  245. data/lua-hooks/ext/lpeg/lpcap.c +0 -537
  246. data/lua-hooks/ext/lpeg/lpcap.h +0 -56
  247. data/lua-hooks/ext/lpeg/lpcode.c +0 -1014
  248. data/lua-hooks/ext/lpeg/lpcode.h +0 -40
  249. data/lua-hooks/ext/lpeg/lpeg-128.gif +0 -0
  250. data/lua-hooks/ext/lpeg/lpeg.html +0 -1445
  251. data/lua-hooks/ext/lpeg/lpprint.c +0 -244
  252. data/lua-hooks/ext/lpeg/lpprint.h +0 -36
  253. data/lua-hooks/ext/lpeg/lptree.c +0 -1303
  254. data/lua-hooks/ext/lpeg/lptree.h +0 -82
  255. data/lua-hooks/ext/lpeg/lptypes.h +0 -149
  256. data/lua-hooks/ext/lpeg/lpvm.c +0 -364
  257. data/lua-hooks/ext/lpeg/lpvm.h +0 -58
  258. data/lua-hooks/ext/lpeg/makefile +0 -55
  259. data/lua-hooks/ext/lpeg/module.mk +0 -6
  260. data/lua-hooks/ext/lpeg/re.html +0 -498
  261. data/lua-hooks/ext/lua-cmsgpack/.gitignore +0 -13
  262. data/lua-hooks/ext/lua-cmsgpack/CMakeLists.txt +0 -45
  263. data/lua-hooks/ext/lua-cmsgpack/README.md +0 -115
  264. data/lua-hooks/ext/lua-cmsgpack/lua_cmsgpack.c +0 -970
  265. data/lua-hooks/ext/lua-cmsgpack/module.mk +0 -2
  266. data/lua-hooks/ext/lua-cmsgpack/test.lua +0 -570
  267. data/lua-hooks/ext/lua-snapshot/LICENSE +0 -7
  268. data/lua-hooks/ext/lua-snapshot/Makefile +0 -12
  269. data/lua-hooks/ext/lua-snapshot/README.md +0 -18
  270. data/lua-hooks/ext/lua-snapshot/dump.lua +0 -15
  271. data/lua-hooks/ext/lua-snapshot/module.mk +0 -2
  272. data/lua-hooks/ext/lua-snapshot/snapshot.c +0 -462
  273. data/lua-hooks/ext/luautf8/README.md +0 -152
  274. data/lua-hooks/ext/luautf8/lutf8lib.c +0 -1274
  275. data/lua-hooks/ext/luautf8/module.mk +0 -2
  276. data/lua-hooks/ext/luautf8/unidata.h +0 -3064
  277. data/lua-hooks/ext/module.mk +0 -15
  278. data/lua-hooks/ext/modules.h +0 -17
  279. data/lua-hooks/ext/perf/luacpu.c +0 -114
  280. data/lua-hooks/ext/perf/lualoadavg.c +0 -40
  281. data/lua-hooks/ext/perf/luameminfo.c +0 -38
  282. data/lua-hooks/ext/perf/luaoslib.c +0 -203
  283. data/lua-hooks/ext/perf/module.mk +0 -5
  284. data/lua-hooks/ext/sha1/luasha1.c +0 -74
  285. data/lua-hooks/ext/sha1/module.mk +0 -5
  286. data/lua-hooks/ext/sha1/sha1.c +0 -145
  287. data/lua-hooks/ext/sha2/luasha256.c +0 -77
  288. data/lua-hooks/ext/sha2/module.mk +0 -5
  289. data/lua-hooks/ext/sha2/sha256.c +0 -196
  290. data/lua-hooks/ext/sysutils/lua_utils.c +0 -56
  291. data/lua-hooks/ext/sysutils/module.mk +0 -2
@@ -0,0 +1,22 @@
1
+ require_relative 'template_rendering'
2
+ require_relative 'fragment_caching'
3
+ require_relative 'cache_store'
4
+
5
+ module Immunio
6
+ XSS_HOOKS = %w[template_render_done template_render_var]
7
+
8
+ # Hook into rendering process of Rails.
9
+ Plugin.load('ActionView', feature: 'xss', hooks: XSS_HOOKS) do |plugin|
10
+ ActionView::TemplateRenderer.send :include, TemplateRendererHooks
11
+ ActionView::Template.send :include, TemplateHooks
12
+
13
+ if Rails::VERSION::MAJOR < 5
14
+ ActionController::Caching::Fragments.send(:include, FragmentCachingHooks)
15
+ else
16
+ AbstractController::Caching.send(:include, FragmentCachingHooks)
17
+ ActiveSupport::Cache::Store.send(:include, CacheStoreHooks)
18
+ end
19
+
20
+ plugin.loaded! Rails.version
21
+ end
22
+ end
@@ -0,0 +1,29 @@
1
+ require_relative 'template'
2
+
3
+ module Immunio
4
+ # Hook for the `ActiveSupport::Hash#to_query`.
5
+ # Use case: building a url within a decorator that renders a partial with an interpolation.
6
+ module ActiveSupportHooks
7
+ extend ActiveSupport::Concern
8
+
9
+ included do
10
+ Immunio::Utils.alias_method_chain self, :to_query, :immunio
11
+ end
12
+
13
+ def to_query_with_immunio(namespace = nil)
14
+ escaped_string = to_query_without_immunio(namespace)
15
+ Request.time "plugin", "#{Module.nesting[0]}::#{__method__}" do
16
+ # Our markers got escaped, so un-unescaped them back.
17
+ escaped_string.gsub!(
18
+ Immunio::Template::ENCODED_IMMUNIO_TOKENS_RE,
19
+ "{immunio-\\1:\\2:\\3}\\4{/immunio-\\1:\\2:\\3}")
20
+ end
21
+ escaped_string
22
+ end
23
+ end
24
+ end
25
+
26
+ ActiveSupport.on_load(:after_initialize) do
27
+ # Wait for ActiveSupport core ext to load
28
+ Hash.send :include, Immunio::ActiveSupportHooks
29
+ end
@@ -0,0 +1,24 @@
1
+ module Immunio
2
+ module CacheStoreHooks
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ Immunio::Utils.alias_method_chain self, :write, :immunio
7
+ end
8
+
9
+ # Rails 5 adds CollectionCaching. When used in the context of
10
+ # rendering a collection of items with a partial template, we
11
+ # need to remove our markers before writing to the cache store.
12
+ # See this blog post for more:
13
+ # http://blog.bigbinary.com/2016/03/09/rails-5-makes-partial-redering-from-cache-substantially-faster.html
14
+ def write_with_immunio(name, value, options = nil)
15
+ Request.time "plugin", "#{Module.nesting[0]}::#{__method__}" do
16
+ Template.remove_all_markers! value if value.is_a? String
17
+
18
+ Request.pause "plugin", "#{Module.nesting[0]}::#{__method__}" do
19
+ write_without_immunio(name, value, options)
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,38 @@
1
+ module Immunio
2
+ module ErubiHooks
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ Immunio::Utils.alias_method_chain self, :add_expression, :immunio
7
+ end
8
+
9
+ def add_expression_with_immunio(indicator, code)
10
+ # Wrap expressions in the templates to track their rendered value.
11
+ # Do not wrap expressions with blocks, eg.: <%= form_tag do %>
12
+ # TODO should we support blocks?
13
+ Request.time "plugin", "#{Module.nesting[0]}::#{__method__}" do
14
+ unless code =~ ActionView::Template::Handlers::ERB::Erubi::BLOCK_EXPR
15
+ # escape unless we see the == indicator
16
+ escape = !(indicator == '==')
17
+ code = Immunio::Template.generate_render_var_code(code, escape)
18
+ end
19
+
20
+ Request.pause "plugin", "#{Module.nesting[0]}::#{__method__}" do
21
+ add_expression_without_immunio(indicator, code)
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+
28
+ if Gem::Version.new(Rails.version) >= Gem::Version.new('5.1')
29
+ Immunio::Plugin.load(
30
+ 'Erubi',
31
+ feature: 'xss',
32
+ hooks: Immunio::XSS_HOOKS) do |plugin|
33
+
34
+ ActionView::Template::Handlers::ERB::Erubi.send :include, Immunio::ErubiHooks
35
+
36
+ plugin.loaded! Rails.version
37
+ end
38
+ end
@@ -0,0 +1,39 @@
1
+ module Immunio
2
+ # Hooks for the ERB template engine.
3
+ # (Default one used in Rails < 5.1).
4
+ module ErubisHooks
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ Immunio::Utils.alias_method_chain self, :add_expr, :immunio
9
+ end
10
+
11
+ def add_expr_with_immunio(src, code, indicator)
12
+ # Wrap expressions in the templates to track their rendered value.
13
+ # Do not wrap expressions with blocks, eg.: <%= form_tag do %>
14
+ # TODO should we support blocks?
15
+ Request.time "plugin", "#{Module.nesting[0]}::#{__method__}" do
16
+ unless code =~ ActionView::Template::Handlers::Erubis::BLOCK_EXPR
17
+ # escape unless we see the == indicator
18
+ escape = !(indicator == '==')
19
+ code = Immunio::Template.generate_render_var_code(code, escape)
20
+ end
21
+ Request.pause "plugin", "#{Module.nesting[0]}::#{__method__}" do
22
+ add_expr_without_immunio(src, code, indicator)
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+
29
+ if Gem::Version.new(Rails.version) < Gem::Version.new('5.1')
30
+ Immunio::Plugin.load(
31
+ 'Erubis',
32
+ feature: 'xss',
33
+ hooks: Immunio::XSS_HOOKS) do |plugin|
34
+
35
+ ActionView::Template::Handlers::Erubis.send :include, Immunio::ErubisHooks
36
+
37
+ plugin.loaded! Rails.version
38
+ end
39
+ end
@@ -0,0 +1,29 @@
1
+ module Immunio
2
+ # Hook for `ActionController::Caching::Fragments` responsible for
3
+ # handling the `<% cache do %>...` in templates.
4
+ module FragmentCachingHooks
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ Immunio::Utils.alias_method_chain self, :write_fragment, :immunio
9
+ end
10
+
11
+ def write_fragment_with_immunio(key, content, options = nil)
12
+ return content unless cache_configured?
13
+
14
+ template = Template.current
15
+ if template
16
+ # We're rendering a template.
17
+ # Defer caching 'till we get the escaped content from the hook handler.
18
+ content = Template.mark_and_defer_fragment_write(key, content, options)
19
+ else
20
+ # Not rendering a template. Ignore.
21
+ # Shouldn't happen. But, just to be safe in case fragment caching
22
+ # is used in the controller for something else.
23
+ content = write_fragment_without_immunio(key, content, options)
24
+ end
25
+
26
+ content
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,46 @@
1
+ module Immunio
2
+ # Hooks for the HAML template engine.
3
+ module HamlHooks
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ Immunio::Utils.alias_method_chain self, :push_script, :immunio
8
+ end
9
+
10
+ def push_script_with_immunio(code, opts = {}, &block)
11
+ # Wrap expressions in the templates to track their rendered value.
12
+ # Do not wrap expressions with blocks, eg.: `= form_tag do`
13
+ # TODO should we support blocks?
14
+ Request.time "plugin", "#{Module.nesting[0]}::#{__method__}" do
15
+ block_expr = if Rails::VERSION::MAJOR == 5 && Rails::VERSION::MINOR > 0
16
+ ActionView::Template::Handlers::ERB::Erubi::BLOCK_EXPR
17
+ else
18
+ ActionView::Template::Handlers::Erubis::BLOCK_EXPR
19
+ end
20
+
21
+ if code !~ block_expr
22
+ # escape if we're told to by HAML
23
+ code = Immunio::Template.generate_render_var_code(code, opts[:escape_html])
24
+ end
25
+
26
+ Request.pause "plugin", "#{Module.nesting[0]}::#{__method__}" do
27
+ push_script_without_immunio(code, opts, &block)
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+
34
+ ActiveSupport.on_load(:after_initialize) do
35
+ # Wait after Rails initialization to patch custom template engines.
36
+ Immunio::Plugin.load(
37
+ 'Haml',
38
+ feature: 'xss',
39
+ hooks: Immunio::XSS_HOOKS) do |plugin|
40
+
41
+ if defined? Haml::Compiler
42
+ Haml::Compiler.send :include, Immunio::HamlHooks
43
+ plugin.loaded! Haml::VERSION
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,42 @@
1
+ module Immunio
2
+ # Hook for Slim template engine.
3
+ module SlimHooks
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ Immunio::Utils.alias_method_chain self, :on_slim_output, :immunio
8
+ end
9
+
10
+ def on_slim_output_with_immunio(escape, code, content)
11
+ # Allow Slim to insert "do" if judged appropriate
12
+ result = on_slim_output_without_immunio(escape, code, content)
13
+ code = result[3]
14
+
15
+ # Wrap expressions in the templates to track their rendered value.
16
+ # Do not wrap expressions with blocks, eg.: `= form_tag do`
17
+ Request.time "plugin", "#{Module.nesting[0]}::#{__method__}" do
18
+ unless code =~ Slim::DoInserter::BLOCK_REGEX
19
+ # Escape if we're told to by Slim
20
+ code = Immunio::Template.generate_render_var_code(code, escape)
21
+ end
22
+ end
23
+
24
+ result[3] = code
25
+ result
26
+ end
27
+ end
28
+ end
29
+
30
+ ActiveSupport.on_load(:after_initialize) do
31
+ # Wait after Rails initialization to patch custom template engines.
32
+ Immunio::Plugin.load(
33
+ 'Slim',
34
+ feature: 'xss',
35
+ hooks: Immunio::XSS_HOOKS) do |plugin|
36
+
37
+ if defined? Slim::DoInserter
38
+ Slim::DoInserter.send :include, Immunio::SlimHooks
39
+ plugin.loaded! Slim::VERSION
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,431 @@
1
+ # Hook into ActionView rendering to inject Immunio's hooks.
2
+ require 'securerandom'
3
+ require 'ripper'
4
+ require 'digest/sha1'
5
+
6
+ module Immunio
7
+ # Renders templates by filtering them through Immunio's hook handlers.
8
+ class Template
9
+ CHECKSUM_CACHE = Hash.new do |cache, template_id|
10
+ template = ObjectSpace._id2ref(template_id)
11
+
12
+ if template.respond_to?(:source) && !template.source.nil?
13
+ finalizer = Immunio::Template.finalize_template(template_id)
14
+ ObjectSpace.define_finalizer(template, finalizer)
15
+ cache[template_id] = Digest::SHA1.hexdigest(template.source).freeze
16
+ end
17
+ end
18
+
19
+ attr_accessor :vars
20
+
21
+ def initialize(template)
22
+ @template = template
23
+ @next_var_id = 0
24
+ @next_template_id = 0
25
+ @vars = {}
26
+ @scheduled_fragments_writes = []
27
+ end
28
+
29
+ def id
30
+ (@template.respond_to?(:virtual_path) && @template.virtual_path) ||
31
+ (@template.respond_to?(:source) && @template.source)
32
+ end
33
+
34
+ def ==(other)
35
+ self.class === other && id == other.id
36
+ end
37
+
38
+ def is_text?
39
+ @template.formats.first == :text
40
+ end
41
+
42
+ def template_sha
43
+ CHECKSUM_CACHE[@template.object_id]
44
+ end
45
+
46
+ # Generate the next var unique ID to be used in a template.
47
+ def next_var_id
48
+ id = @next_var_id
49
+ @next_var_id += 1
50
+ id
51
+ end
52
+
53
+ def next_template_id
54
+ id = @next_template_id
55
+ @next_template_id += 1
56
+ id
57
+ end
58
+
59
+ def get_nonce
60
+ # Generate a two byte CSRNG nonce to make our substitutions unpreictable
61
+ # Why only 2 bytes? The nonce is per render, so the odds of guessing it are very low
62
+ # and entropy is finite so we don't want to drain the random pool unnecessarily
63
+ @nonce ||= SecureRandom.hex(2)
64
+ end
65
+
66
+ def mark_and_defer_fragment_write(key, content, options)
67
+ id = @scheduled_fragments_writes.size
68
+ nonce = Template.get_nonce
69
+ @scheduled_fragments_writes << [key, content, options]
70
+ "{immunio-fragment:#{id}:#{nonce}}#{content}{/immunio-fragment:#{id}:#{nonce}}"
71
+ end
72
+
73
+ def render(context)
74
+ load_source context
75
+ # Don't handle templates with no source (inline text templates).
76
+ unless has_source?
77
+ rendered = yield
78
+ rendered.instance_variable_set("@__immunio_processed", true) unless rendered.frozen?
79
+ return rendered
80
+ end
81
+
82
+ begin
83
+ root = true if rendering_stack.length == 0
84
+
85
+ rendering_stack.push self
86
+ # Calculate SHA1 of this template.
87
+ template_sha
88
+ Immunio.logger.debug {"ActionView rendering template with sha #{@template_sha}, root: #{root}"}
89
+ rendered = yield
90
+ rendered.instance_variable_set("@__immunio_processed", true) unless rendered.frozen?
91
+
92
+ if root
93
+ # This is the root template. Let ActionView render it, and then look
94
+ # for XSS.
95
+
96
+ # If the rendered result isn't a string, or a string-like, then let's
97
+ # skip it for safety sake.
98
+ unless rendered.respond_to? :to_str
99
+ unless $__immunio_av_rendered_non_string
100
+ Immunio.logger.warn { "ActionView rendered #{@template.inspect} to a non-string-like value: #{rendered.inspect}. This rendering will not be analyzed for XSS. Further warnings will be suppressed." }
101
+ $__immunio_av_rendered_non_string = true
102
+ end
103
+ return rendered
104
+ end
105
+
106
+ rendered = rendered.to_str
107
+
108
+ result = run_hook!("template_render_done", {
109
+ content_type: Mime::Type.lookup_by_extension(@template.formats.first).to_s,
110
+ rendered: rendered,
111
+ vars: @vars
112
+ })
113
+
114
+ # We use the return value from the hook handler if present.
115
+ rendered = result["rendered"] || rendered.dup
116
+
117
+ remove_var_markers! rendered
118
+
119
+ # If some fragments were marked to be cached, commit their content to cache.
120
+ write_and_remove_fragments! context, rendered
121
+
122
+ rendered.html_safe
123
+ else
124
+ # This is a partial template. Just render it.
125
+ rendered
126
+ end
127
+ ensure
128
+ top_template = rendering_stack.pop
129
+ unless top_template == self
130
+ raise Error, "Unexpected Immunio::Template on rendering stack. Expected #{id}, got #{top_template.try :id}."
131
+ end
132
+ end
133
+ end
134
+
135
+ ENCODED_IMMUNIO_TOKENS_RE = Regexp.compile(/(?:{|%7b)immunio-(var|fragment)(?::|%3a)(\d+)(?::|%3a)([0-9a-f]{1,4})(?:}|%7d)(.*?)(?:{|%7b)(?:\/|%2f)immunio-\1(?::|%3a)\2(?::|%3a)\3(?:}|%7d)/i)
136
+
137
+ private
138
+
139
+ class << self
140
+ def finalize_template(id)
141
+ proc { CHECKSUM_CACHE.delete(id) if CHECKSUM_CACHE.has_key?(id) }
142
+ end
143
+
144
+ def current
145
+ rendering_stack.last
146
+ end
147
+
148
+ def next_var_id
149
+ rendering_stack.first.next_var_id
150
+ end
151
+
152
+ def vars
153
+ rendering_stack.first.vars
154
+ end
155
+
156
+ def get_nonce
157
+ rendering_stack.first.get_nonce
158
+ end
159
+
160
+ # Save fragment info to the root template only
161
+ def mark_and_defer_fragment_write(*args)
162
+ rendering_stack.first.mark_and_defer_fragment_write(*args)
163
+ end
164
+
165
+ # Stack of the templates currently being rendered.
166
+ def rendering_stack
167
+ Thread.current["immunio.rendering_stack"] ||= []
168
+ end
169
+
170
+ def wrap_code(code, handler, options = {})
171
+ wrap_method = {
172
+ 'ActionView::Template::Handlers::ERB' => :wrap_code_for_erb,
173
+ 'Haml::Plugin' => :wrap_code_for_haml,
174
+ 'Slim::RailsTemplate' => :wrap_code_for_slim
175
+ }[handler]
176
+
177
+ send wrap_method, code, options
178
+ end
179
+
180
+ def wrap_code_for_erb(code, options)
181
+ modifier = options[:escape] ? '=' : '=='
182
+ "<%#{modifier} #{code} %>"
183
+ end
184
+
185
+ def wrap_code_for_haml(code, options)
186
+ modifier = options[:escape] ? '=' : '!='
187
+ "#{modifier} #{code}"
188
+ end
189
+
190
+ def wrap_code_for_slim(code, options)
191
+ modifier = options[:escape] ? '=' : '=='
192
+ "#{modifier} #{code}"
193
+ end
194
+
195
+ def decode_immunio_tokens(rendered)
196
+ # Look for URI or JS encoded immunio tokens in the rendering and decode them
197
+ # WebConsole incompatibility: `rendered` can be of type `Mime::Type` Which
198
+ # doesn't respond to `gsub!`.
199
+ if rendered.respond_to?(:gsub!)
200
+ was_html_safe = rendered.html_safe?
201
+ was_frozen = rendered.frozen?
202
+
203
+ if was_frozen
204
+ # This is not an airtight solution. Object#dup does not copy methods
205
+ # defined on the instance, and may be overridden by subclasses to do
206
+ # things that would cause problems for us. But most likely there is no
207
+ # problem with using dup. We can't use Object#clone because the clone
208
+ # retains the frozen status of the original, preventing us from
209
+ # modifying the string contents.
210
+ rendered = rendered.dup
211
+ end
212
+
213
+ rendered.gsub! ENCODED_IMMUNIO_TOKENS_RE, "{immunio-\\1:\\2:\\3}\\4{/immunio-\\1:\\2:\\3}"
214
+
215
+ rendered.instance_variable_set(:@html_safe, true) if was_html_safe
216
+ rendered.freeze if was_frozen
217
+ end
218
+
219
+ rendered
220
+ end
221
+
222
+ def mark_var(content, code, template_id, template_sha, file, line, escape, is_text, handler)
223
+ id = Template.next_var_id
224
+ nonce = Template.get_nonce
225
+
226
+ # NOTE: What happens here is pretty funky to preserve the html_safe SafeBuffer behaviour in ruby.
227
+ # If escaped is true we directly concatenate the content between two SafeBuffers. This will cause
228
+ # escaping if content is not itself a SafeBuffer.
229
+ # Otherwise we explicitly convert to a string, and convert that to a SafeBuffer to ensure that
230
+ # for instance no escaping is performed on the contents of a <%== %> Erubis interpolation.
231
+ rendering =
232
+ if escape && !is_text
233
+ # explicitly convert (w/ escapes) and mark safe things that aren't String (SafeBuffer is_a String also)
234
+ # `to_s` is used to render any object passed to a template.
235
+ # It is called internally when appending to ActionView::OutputBuffer.
236
+ # We force rendering to get the actual string.
237
+ # This has no impact if `rendered` is already a string.
238
+ content = content.to_s.html_safe unless content.is_a? String
239
+
240
+ # As a failsafe, just return the content if it already contains our markers. This can occur when
241
+ # a helper calls render partial to generate a component of a page. Both render calls are root level
242
+ # templates from our perspective.
243
+ if content =~ /\{immunio-var:\d+:#{nonce}\}/ then
244
+ # don't add markers.
245
+ Immunio.logger.debug {"WARNING: ActionView not marking interpolation which already contains markers: \"#{content}\""}
246
+ return content
247
+ end
248
+
249
+ "{immunio-var:#{id}:#{nonce}}".html_safe + content + "{/immunio-var:#{id}:#{nonce}}".html_safe
250
+ else
251
+ content = "" if content.nil?
252
+
253
+ # See comment above
254
+ if (content.respond_to? :=~) &&
255
+ (content =~ /\{immunio-var:\d+:#{nonce}\}/)
256
+ # don't add markers.
257
+ Immunio.logger.debug {"WARNING: ActionView not marking interpolation which already contains markers: \"#{content}\""}
258
+ return content.html_safe
259
+ end
260
+
261
+ "{immunio-var:#{id}:#{nonce}}".html_safe + content.to_s.html_safe + "{/immunio-var:#{id}:#{nonce}}".html_safe
262
+ end
263
+
264
+ # If we got here, the interpolation has been wrapped in our markers and we
265
+ # need to record send data about it to the hook
266
+ Template.vars[id.to_s] = {
267
+ template_sha: template_sha,
268
+ template_id: template_id.to_s,
269
+ nonce: nonce,
270
+ code: wrap_code(code, handler, escape: escape),
271
+ file: file,
272
+ line: line
273
+ }
274
+
275
+ rendering
276
+ end
277
+
278
+ def render_var(code, rendered, template_id, template_sha, file, line, escape, is_text, handler)
279
+ rendered = decode_immunio_tokens rendered
280
+
281
+ if rendered.instance_variable_get("@__immunio_processed") then
282
+ # Ignore buffers marked as __immunio_processed in render as these are full templates or partials
283
+ return rendered
284
+ elsif code =~ /yield( .*)?/
285
+ # Ignore yielded blocks inside layouts
286
+ return rendered
287
+ end
288
+ rendered = mark_var rendered, code, template_id, template_sha, file, line, escape, is_text, handler
289
+ rendered.html_safe
290
+ end
291
+
292
+ def remove_comment(code)
293
+ *, last_line = code.rpartition("\n")
294
+
295
+ comment = Ripper.slice(last_line, "comment")
296
+
297
+ if comment
298
+ code = code.sub(Regexp.new(Regexp.escape(comment) + "\\Z"), "")
299
+ end
300
+
301
+ code
302
+ end
303
+
304
+ # Generate code injected in templates to wrap everything inside `<%= ... %>`.
305
+ def generate_render_var_code(code, escape)
306
+ template = Template.current
307
+ if template
308
+ template_id = template.next_template_id
309
+
310
+ handler = template.instance_variable_get(:@template).handler
311
+ handler_name = if handler.is_a? Class
312
+ handler.name
313
+ else
314
+ handler.class.name
315
+ end
316
+
317
+ "(__immunio_result = (#{remove_comment(code)}); Immunio::Template.render_var(#{code.strip.inspect}, __immunio_result, #{template_id}, '#{template.template_sha}', __FILE__, __LINE__, #{!!escape}, #{template.is_text?}, '#{handler_name}'))"
318
+ else
319
+ code
320
+ end
321
+ end
322
+
323
+ def remove_all_markers!(input)
324
+ input.gsub!(/\{\/?immunio-(fragment|var):\d+:[a-zA-Z0-9]+\}/, "")
325
+ end
326
+ end
327
+
328
+ # End of private class methods
329
+
330
+ def has_source?
331
+ @template.respond_to?(:source) && !@template.source.nil?
332
+ end
333
+
334
+ def compiled?
335
+ @template.instance_variable_get :@compiled
336
+ end
337
+
338
+ def load_source(context)
339
+ return if !@template.respond_to?(:source) || !@template.source.nil?
340
+
341
+ # @template is a virtual template that doesn't contain the source. We need
342
+ # to try to load the source. But, the virtual template doesn't know the
343
+ # original format of the source template file.
344
+ #
345
+ # First, try to load it using the Rails defaults (usually "html" and
346
+ # "txt"). If that doesn't work, try to use the original format from the
347
+ # virtual template.
348
+ #
349
+ # Though one might think the format from the virtual template would always
350
+ # work, unfortunately the format from the template refers to the "type" of
351
+ # the template, which may or may not be the same as the format of the
352
+ # lookup context, which specifies the file extension of the template. Ugh,
353
+ # naming... For example, the lookup context format may be "txt" while the
354
+ # template format is "text".
355
+ #
356
+ # Astute readers may note that there's the possibility the template
357
+ # extension is not in the Rails default list of lookup formats, and also
358
+ # does not match the template type. We are just going to leave that for
359
+ # another day, and hope that day never comes...
360
+ begin
361
+ refreshed = Immunio::IOHooks.paused { @template.refresh(context) }
362
+ rescue
363
+ begin
364
+ old_formats = context.lookup_context.formats
365
+ context.lookup_context.formats = @template.formats
366
+ refreshed = Immunio::IOHooks.paused { @template.refresh(context) }
367
+ rescue
368
+ Immunio.logger.warn { "Failed to refresh template source from #{@template} using contexts #{old_formats} and #{@template.formats}" }
369
+ ensure
370
+ context.lookup_context.formats = old_formats
371
+ end
372
+ end
373
+
374
+ return if refreshed.nil?
375
+
376
+ @template.instance_variable_set :@source, refreshed.source
377
+ end
378
+
379
+ def rendering_stack
380
+ self.class.rendering_stack
381
+ end
382
+
383
+ def run_hook!(name, meta={})
384
+ default_meta = {
385
+ template_sha: template_sha,
386
+ name: (@template.respond_to?(:virtual_path) && @template.virtual_path) || nil,
387
+ origin: @template.identifier,
388
+ nonce: Template.get_nonce
389
+ }
390
+ Immunio.run_hook! "action_view", name, default_meta.merge(meta)
391
+ end
392
+
393
+ def write_and_remove_fragments!(context, content)
394
+ # Rails tests do use the context as the view context sometimes.
395
+ if context.is_a? ActionController::Base
396
+ controller = context
397
+ elsif context.respond_to? :controller
398
+ controller = context.controller
399
+ else
400
+ # Some rails unit tests don't have a controller...
401
+ remove_all_markers! content
402
+ return
403
+ end
404
+
405
+ # Iterate to handle nested fragments. Child fragments have lower ids than their parents.
406
+ nonce = Template.get_nonce
407
+ @scheduled_fragments_writes.each_with_index do |(key, _, options), id|
408
+ # Remove the markers ...
409
+ content.sub!(/\{immunio-fragment:#{id}:#{nonce}\}(.*)\{\/immunio-fragment:#{id}:#{nonce}\}/m) do
410
+ # The escaped content inside the markers ($1), is written to cache.
411
+ output = $1
412
+ remove_all_markers! output
413
+ controller.write_fragment_without_immunio key, output, options
414
+ output
415
+ end
416
+ end
417
+ # To be extra safe strip all markers from content
418
+ remove_all_markers! content
419
+ end
420
+
421
+ def remove_var_markers!(input)
422
+ nonce = Template.get_nonce
423
+ # TODO is this the fastest way to remove the markers? Needs benchmarking ...
424
+ input.gsub!(/\{\/?immunio-var:\d+:#{nonce}\}/, "")
425
+ end
426
+
427
+ def remove_all_markers!(input)
428
+ self.class.remove_all_markers!(input)
429
+ end
430
+ end
431
+ end