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.
- checksums.yaml +4 -4
- data/README.md +13 -5
- data/ext/immunio/Rakefile +14 -6
- data/lib/immunio/context.rb +2 -0
- data/lib/immunio/plugins/action_view.rb +7 -668
- data/lib/immunio/plugins/action_view/action_view.rb +22 -0
- data/lib/immunio/plugins/action_view/active_support_hash.rb +29 -0
- data/lib/immunio/plugins/action_view/cache_store.rb +24 -0
- data/lib/immunio/plugins/action_view/erubi.rb +38 -0
- data/lib/immunio/plugins/action_view/erubis.rb +39 -0
- data/lib/immunio/plugins/action_view/fragment_caching.rb +29 -0
- data/lib/immunio/plugins/action_view/haml.rb +46 -0
- data/lib/immunio/plugins/action_view/slim.rb +42 -0
- data/lib/immunio/plugins/action_view/template.rb +431 -0
- data/lib/immunio/plugins/action_view/template_rendering.rb +45 -0
- data/lib/immunio/plugins/http_tracker.rb +2 -0
- data/lib/immunio/plugins/io.rb +34 -0
- data/lib/immunio/version.rb +1 -1
- data/lua-hooks/Makefile +36 -9
- data/lua-hooks/ext/luajit/COPYRIGHT +1 -1
- data/lua-hooks/ext/luajit/Makefile +22 -15
- data/lua-hooks/ext/luajit/README +2 -2
- data/lua-hooks/ext/luajit/doc/bluequad-print.css +1 -1
- data/lua-hooks/ext/luajit/doc/bluequad.css +1 -1
- data/lua-hooks/ext/luajit/doc/changes.html +69 -3
- data/lua-hooks/ext/luajit/doc/contact.html +10 -3
- data/lua-hooks/ext/luajit/doc/ext_c_api.html +2 -2
- data/lua-hooks/ext/luajit/doc/ext_ffi.html +2 -2
- data/lua-hooks/ext/luajit/doc/ext_ffi_api.html +2 -2
- data/lua-hooks/ext/luajit/doc/ext_ffi_semantics.html +3 -4
- data/lua-hooks/ext/luajit/doc/ext_ffi_tutorial.html +2 -2
- data/lua-hooks/ext/luajit/doc/ext_jit.html +3 -3
- data/lua-hooks/ext/luajit/doc/ext_profiler.html +2 -2
- data/lua-hooks/ext/luajit/doc/extensions.html +47 -20
- data/lua-hooks/ext/luajit/doc/faq.html +2 -2
- data/lua-hooks/ext/luajit/doc/install.html +74 -45
- data/lua-hooks/ext/luajit/doc/luajit.html +5 -5
- data/lua-hooks/ext/luajit/doc/running.html +3 -3
- data/lua-hooks/ext/luajit/doc/status.html +13 -8
- data/lua-hooks/ext/luajit/dynasm/dasm_arm.h +1 -1
- data/lua-hooks/ext/luajit/dynasm/dasm_arm.lua +1 -1
- data/lua-hooks/ext/luajit/dynasm/dasm_arm64.h +1 -1
- data/lua-hooks/ext/luajit/dynasm/dasm_arm64.lua +1 -1
- data/lua-hooks/ext/luajit/dynasm/dasm_mips.h +8 -5
- data/lua-hooks/ext/luajit/dynasm/dasm_mips.lua +66 -11
- data/lua-hooks/ext/luajit/dynasm/dasm_mips64.lua +12 -0
- data/lua-hooks/ext/luajit/dynasm/dasm_ppc.h +1 -1
- data/lua-hooks/ext/luajit/dynasm/dasm_ppc.lua +1 -1
- data/lua-hooks/ext/luajit/dynasm/dasm_proto.h +1 -1
- data/lua-hooks/ext/luajit/dynasm/dasm_x64.lua +1 -1
- data/lua-hooks/ext/luajit/dynasm/dasm_x86.h +1 -1
- data/lua-hooks/ext/luajit/dynasm/dasm_x86.lua +5 -1
- data/lua-hooks/ext/luajit/dynasm/dynasm.lua +2 -2
- data/lua-hooks/ext/luajit/etc/luajit.1 +1 -1
- data/lua-hooks/ext/luajit/etc/luajit.pc +1 -1
- data/lua-hooks/ext/luajit/src/Makefile +15 -11
- data/lua-hooks/ext/luajit/src/Makefile.dep +16 -16
- data/lua-hooks/ext/luajit/src/host/buildvm.c +2 -2
- data/lua-hooks/ext/luajit/src/host/buildvm.h +1 -1
- data/lua-hooks/ext/luajit/src/host/buildvm_asm.c +9 -4
- data/lua-hooks/ext/luajit/src/host/buildvm_fold.c +2 -2
- data/lua-hooks/ext/luajit/src/host/buildvm_lib.c +1 -1
- data/lua-hooks/ext/luajit/src/host/buildvm_libbc.h +14 -3
- data/lua-hooks/ext/luajit/src/host/buildvm_peobj.c +27 -3
- data/lua-hooks/ext/luajit/src/host/genlibbc.lua +1 -1
- data/lua-hooks/ext/luajit/src/host/genminilua.lua +6 -5
- data/lua-hooks/ext/luajit/src/host/minilua.c +1 -1
- data/lua-hooks/ext/luajit/src/jit/bc.lua +1 -1
- data/lua-hooks/ext/luajit/src/jit/bcsave.lua +8 -8
- data/lua-hooks/ext/luajit/src/jit/dis_arm.lua +2 -2
- data/lua-hooks/ext/luajit/src/jit/dis_arm64.lua +1216 -0
- data/lua-hooks/ext/luajit/src/jit/dis_arm64be.lua +12 -0
- data/lua-hooks/ext/luajit/src/jit/dis_mips.lua +35 -20
- data/lua-hooks/ext/luajit/src/jit/dis_mips64.lua +17 -0
- data/lua-hooks/ext/luajit/src/jit/dis_mips64el.lua +17 -0
- data/lua-hooks/ext/luajit/src/jit/dis_mipsel.lua +1 -1
- data/lua-hooks/ext/luajit/src/jit/dis_ppc.lua +2 -2
- data/lua-hooks/ext/luajit/src/jit/dis_x64.lua +1 -1
- data/lua-hooks/ext/luajit/src/jit/dis_x86.lua +7 -4
- data/lua-hooks/ext/luajit/src/jit/dump.lua +17 -12
- data/lua-hooks/ext/luajit/src/jit/p.lua +3 -2
- data/lua-hooks/ext/luajit/src/jit/v.lua +2 -2
- data/lua-hooks/ext/luajit/src/jit/zone.lua +1 -1
- data/lua-hooks/ext/luajit/src/lauxlib.h +14 -20
- data/lua-hooks/ext/luajit/src/lib_aux.c +38 -27
- data/lua-hooks/ext/luajit/src/lib_base.c +12 -5
- data/lua-hooks/ext/luajit/src/lib_bit.c +1 -1
- data/lua-hooks/ext/luajit/src/lib_debug.c +5 -5
- data/lua-hooks/ext/luajit/src/lib_ffi.c +2 -2
- data/lua-hooks/ext/luajit/src/lib_init.c +16 -16
- data/lua-hooks/ext/luajit/src/lib_io.c +6 -7
- data/lua-hooks/ext/luajit/src/lib_jit.c +14 -4
- data/lua-hooks/ext/luajit/src/lib_math.c +1 -5
- data/lua-hooks/ext/luajit/src/lib_os.c +1 -1
- data/lua-hooks/ext/luajit/src/lib_package.c +14 -23
- data/lua-hooks/ext/luajit/src/lib_string.c +1 -5
- data/lua-hooks/ext/luajit/src/lib_table.c +21 -1
- data/lua-hooks/ext/luajit/src/lj.supp +3 -3
- data/lua-hooks/ext/luajit/src/lj_alloc.c +174 -83
- data/lua-hooks/ext/luajit/src/lj_api.c +97 -18
- data/lua-hooks/ext/luajit/src/lj_arch.h +54 -22
- data/lua-hooks/ext/luajit/src/lj_asm.c +172 -53
- data/lua-hooks/ext/luajit/src/lj_asm.h +1 -1
- data/lua-hooks/ext/luajit/src/lj_asm_arm.h +19 -16
- data/lua-hooks/ext/luajit/src/lj_asm_arm64.h +2022 -0
- data/lua-hooks/ext/luajit/src/lj_asm_mips.h +564 -158
- data/lua-hooks/ext/luajit/src/lj_asm_ppc.h +19 -18
- data/lua-hooks/ext/luajit/src/lj_asm_x86.h +578 -92
- data/lua-hooks/ext/luajit/src/lj_bc.c +1 -1
- data/lua-hooks/ext/luajit/src/lj_bc.h +1 -1
- data/lua-hooks/ext/luajit/src/lj_bcdump.h +1 -1
- data/lua-hooks/ext/luajit/src/lj_bcread.c +1 -1
- data/lua-hooks/ext/luajit/src/lj_bcwrite.c +1 -1
- data/lua-hooks/ext/luajit/src/lj_buf.c +1 -1
- data/lua-hooks/ext/luajit/src/lj_buf.h +1 -1
- data/lua-hooks/ext/luajit/src/lj_carith.c +1 -1
- data/lua-hooks/ext/luajit/src/lj_carith.h +1 -1
- data/lua-hooks/ext/luajit/src/lj_ccall.c +172 -7
- data/lua-hooks/ext/luajit/src/lj_ccall.h +21 -5
- data/lua-hooks/ext/luajit/src/lj_ccallback.c +71 -17
- data/lua-hooks/ext/luajit/src/lj_ccallback.h +1 -1
- data/lua-hooks/ext/luajit/src/lj_cconv.c +4 -2
- data/lua-hooks/ext/luajit/src/lj_cconv.h +1 -1
- data/lua-hooks/ext/luajit/src/lj_cdata.c +7 -5
- data/lua-hooks/ext/luajit/src/lj_cdata.h +1 -1
- data/lua-hooks/ext/luajit/src/lj_clib.c +5 -5
- data/lua-hooks/ext/luajit/src/lj_clib.h +1 -1
- data/lua-hooks/ext/luajit/src/lj_cparse.c +11 -6
- data/lua-hooks/ext/luajit/src/lj_cparse.h +1 -1
- data/lua-hooks/ext/luajit/src/lj_crecord.c +70 -14
- data/lua-hooks/ext/luajit/src/lj_crecord.h +1 -1
- data/lua-hooks/ext/luajit/src/lj_ctype.c +1 -1
- data/lua-hooks/ext/luajit/src/lj_ctype.h +8 -8
- data/lua-hooks/ext/luajit/src/lj_debug.c +1 -1
- data/lua-hooks/ext/luajit/src/lj_debug.h +1 -1
- data/lua-hooks/ext/luajit/src/lj_def.h +6 -9
- data/lua-hooks/ext/luajit/src/lj_dispatch.c +3 -3
- data/lua-hooks/ext/luajit/src/lj_dispatch.h +2 -1
- data/lua-hooks/ext/luajit/src/lj_emit_arm.h +5 -4
- data/lua-hooks/ext/luajit/src/lj_emit_arm64.h +419 -0
- data/lua-hooks/ext/luajit/src/lj_emit_mips.h +100 -20
- data/lua-hooks/ext/luajit/src/lj_emit_ppc.h +4 -4
- data/lua-hooks/ext/luajit/src/lj_emit_x86.h +116 -25
- data/lua-hooks/ext/luajit/src/lj_err.c +34 -13
- data/lua-hooks/ext/luajit/src/lj_err.h +1 -1
- data/lua-hooks/ext/luajit/src/lj_errmsg.h +1 -1
- data/lua-hooks/ext/luajit/src/lj_ff.h +1 -1
- data/lua-hooks/ext/luajit/src/lj_ffrecord.c +58 -49
- data/lua-hooks/ext/luajit/src/lj_ffrecord.h +1 -1
- data/lua-hooks/ext/luajit/src/lj_frame.h +33 -6
- data/lua-hooks/ext/luajit/src/lj_func.c +4 -2
- data/lua-hooks/ext/luajit/src/lj_func.h +1 -1
- data/lua-hooks/ext/luajit/src/lj_gc.c +16 -7
- data/lua-hooks/ext/luajit/src/lj_gc.h +1 -1
- data/lua-hooks/ext/luajit/src/lj_gdbjit.c +31 -1
- data/lua-hooks/ext/luajit/src/lj_gdbjit.h +1 -1
- data/lua-hooks/ext/luajit/src/lj_ir.c +69 -96
- data/lua-hooks/ext/luajit/src/lj_ir.h +29 -18
- data/lua-hooks/ext/luajit/src/lj_ircall.h +24 -30
- data/lua-hooks/ext/luajit/src/lj_iropt.h +9 -9
- data/lua-hooks/ext/luajit/src/lj_jit.h +67 -9
- data/lua-hooks/ext/luajit/src/lj_lex.c +1 -1
- data/lua-hooks/ext/luajit/src/lj_lex.h +1 -1
- data/lua-hooks/ext/luajit/src/lj_lib.c +1 -1
- data/lua-hooks/ext/luajit/src/lj_lib.h +1 -1
- data/lua-hooks/ext/luajit/src/lj_load.c +1 -1
- data/lua-hooks/ext/luajit/src/lj_mcode.c +11 -10
- data/lua-hooks/ext/luajit/src/lj_mcode.h +1 -1
- data/lua-hooks/ext/luajit/src/lj_meta.c +1 -1
- data/lua-hooks/ext/luajit/src/lj_meta.h +1 -1
- data/lua-hooks/ext/luajit/src/lj_obj.c +1 -1
- data/lua-hooks/ext/luajit/src/lj_obj.h +7 -3
- data/lua-hooks/ext/luajit/src/lj_opt_dce.c +1 -1
- data/lua-hooks/ext/luajit/src/lj_opt_fold.c +84 -17
- data/lua-hooks/ext/luajit/src/lj_opt_loop.c +1 -1
- data/lua-hooks/ext/luajit/src/lj_opt_mem.c +3 -3
- data/lua-hooks/ext/luajit/src/lj_opt_narrow.c +24 -22
- data/lua-hooks/ext/luajit/src/lj_opt_sink.c +11 -6
- data/lua-hooks/ext/luajit/src/lj_opt_split.c +11 -2
- data/lua-hooks/ext/luajit/src/lj_parse.c +9 -7
- data/lua-hooks/ext/luajit/src/lj_parse.h +1 -1
- data/lua-hooks/ext/luajit/src/lj_profile.c +1 -1
- data/lua-hooks/ext/luajit/src/lj_profile.h +1 -1
- data/lua-hooks/ext/luajit/src/lj_record.c +201 -117
- data/lua-hooks/ext/luajit/src/lj_record.h +1 -1
- data/lua-hooks/ext/luajit/src/lj_snap.c +72 -26
- data/lua-hooks/ext/luajit/src/lj_snap.h +1 -1
- data/lua-hooks/ext/luajit/src/lj_state.c +6 -6
- data/lua-hooks/ext/luajit/src/lj_state.h +2 -2
- data/lua-hooks/ext/luajit/src/lj_str.c +1 -1
- data/lua-hooks/ext/luajit/src/lj_str.h +1 -1
- data/lua-hooks/ext/luajit/src/lj_strfmt.c +7 -3
- data/lua-hooks/ext/luajit/src/lj_strfmt.h +1 -1
- data/lua-hooks/ext/luajit/src/lj_strfmt_num.c +4 -3
- data/lua-hooks/ext/luajit/src/lj_strscan.c +1 -1
- data/lua-hooks/ext/luajit/src/lj_strscan.h +1 -1
- data/lua-hooks/ext/luajit/src/lj_tab.c +1 -2
- data/lua-hooks/ext/luajit/src/lj_tab.h +1 -1
- data/lua-hooks/ext/luajit/src/lj_target.h +3 -3
- data/lua-hooks/ext/luajit/src/lj_target_arm.h +1 -1
- data/lua-hooks/ext/luajit/src/lj_target_arm64.h +239 -7
- data/lua-hooks/ext/luajit/src/lj_target_mips.h +111 -22
- data/lua-hooks/ext/luajit/src/lj_target_ppc.h +1 -1
- data/lua-hooks/ext/luajit/src/lj_target_x86.h +21 -4
- data/lua-hooks/ext/luajit/src/lj_trace.c +63 -18
- data/lua-hooks/ext/luajit/src/lj_trace.h +2 -1
- data/lua-hooks/ext/luajit/src/lj_traceerr.h +1 -1
- data/lua-hooks/ext/luajit/src/lj_udata.c +1 -1
- data/lua-hooks/ext/luajit/src/lj_udata.h +1 -1
- data/lua-hooks/ext/luajit/src/lj_vm.h +5 -1
- data/lua-hooks/ext/luajit/src/lj_vmevent.c +1 -1
- data/lua-hooks/ext/luajit/src/lj_vmevent.h +1 -1
- data/lua-hooks/ext/luajit/src/lj_vmmath.c +1 -1
- data/lua-hooks/ext/luajit/src/ljamalg.c +1 -1
- data/lua-hooks/ext/luajit/src/lua.h +9 -1
- data/lua-hooks/ext/luajit/src/luaconf.h +3 -7
- data/lua-hooks/ext/luajit/src/luajit.c +69 -54
- data/lua-hooks/ext/luajit/src/luajit.h +4 -4
- data/lua-hooks/ext/luajit/src/lualib.h +1 -1
- data/lua-hooks/ext/luajit/src/msvcbuild.bat +12 -4
- data/lua-hooks/ext/luajit/src/vm_arm.dasc +1 -1
- data/lua-hooks/ext/luajit/src/vm_arm64.dasc +255 -32
- data/lua-hooks/ext/luajit/src/vm_mips.dasc +26 -23
- data/lua-hooks/ext/luajit/src/vm_mips64.dasc +5062 -0
- data/lua-hooks/ext/luajit/src/vm_ppc.dasc +1 -1
- data/lua-hooks/ext/luajit/src/vm_x64.dasc +24 -25
- data/lua-hooks/ext/luajit/src/vm_x86.dasc +77 -4
- data/lua-hooks/libluahooks.darwin.a +0 -0
- data/lua-hooks/libluahooks.linux.a +0 -0
- data/lua-hooks/options.mk +1 -1
- metadata +37 -77
- data/lua-hooks/ext/all.c +0 -69
- data/lua-hooks/ext/libinjection/COPYING +0 -37
- data/lua-hooks/ext/libinjection/libinjection.h +0 -65
- data/lua-hooks/ext/libinjection/libinjection_html5.c +0 -847
- data/lua-hooks/ext/libinjection/libinjection_html5.h +0 -54
- data/lua-hooks/ext/libinjection/libinjection_sqli.c +0 -2301
- data/lua-hooks/ext/libinjection/libinjection_sqli.h +0 -295
- data/lua-hooks/ext/libinjection/libinjection_sqli_data.h +0 -9349
- data/lua-hooks/ext/libinjection/libinjection_xss.c +0 -531
- data/lua-hooks/ext/libinjection/libinjection_xss.h +0 -21
- data/lua-hooks/ext/libinjection/lualib.c +0 -145
- data/lua-hooks/ext/libinjection/module.mk +0 -5
- data/lua-hooks/ext/lpeg/HISTORY +0 -96
- data/lua-hooks/ext/lpeg/lpcap.c +0 -537
- data/lua-hooks/ext/lpeg/lpcap.h +0 -56
- data/lua-hooks/ext/lpeg/lpcode.c +0 -1014
- data/lua-hooks/ext/lpeg/lpcode.h +0 -40
- data/lua-hooks/ext/lpeg/lpeg-128.gif +0 -0
- data/lua-hooks/ext/lpeg/lpeg.html +0 -1445
- data/lua-hooks/ext/lpeg/lpprint.c +0 -244
- data/lua-hooks/ext/lpeg/lpprint.h +0 -36
- data/lua-hooks/ext/lpeg/lptree.c +0 -1303
- data/lua-hooks/ext/lpeg/lptree.h +0 -82
- data/lua-hooks/ext/lpeg/lptypes.h +0 -149
- data/lua-hooks/ext/lpeg/lpvm.c +0 -364
- data/lua-hooks/ext/lpeg/lpvm.h +0 -58
- data/lua-hooks/ext/lpeg/makefile +0 -55
- data/lua-hooks/ext/lpeg/module.mk +0 -6
- data/lua-hooks/ext/lpeg/re.html +0 -498
- data/lua-hooks/ext/lua-cmsgpack/.gitignore +0 -13
- data/lua-hooks/ext/lua-cmsgpack/CMakeLists.txt +0 -45
- data/lua-hooks/ext/lua-cmsgpack/README.md +0 -115
- data/lua-hooks/ext/lua-cmsgpack/lua_cmsgpack.c +0 -970
- data/lua-hooks/ext/lua-cmsgpack/module.mk +0 -2
- data/lua-hooks/ext/lua-cmsgpack/test.lua +0 -570
- data/lua-hooks/ext/lua-snapshot/LICENSE +0 -7
- data/lua-hooks/ext/lua-snapshot/Makefile +0 -12
- data/lua-hooks/ext/lua-snapshot/README.md +0 -18
- data/lua-hooks/ext/lua-snapshot/dump.lua +0 -15
- data/lua-hooks/ext/lua-snapshot/module.mk +0 -2
- data/lua-hooks/ext/lua-snapshot/snapshot.c +0 -462
- data/lua-hooks/ext/luautf8/README.md +0 -152
- data/lua-hooks/ext/luautf8/lutf8lib.c +0 -1274
- data/lua-hooks/ext/luautf8/module.mk +0 -2
- data/lua-hooks/ext/luautf8/unidata.h +0 -3064
- data/lua-hooks/ext/module.mk +0 -15
- data/lua-hooks/ext/modules.h +0 -17
- data/lua-hooks/ext/perf/luacpu.c +0 -114
- data/lua-hooks/ext/perf/lualoadavg.c +0 -40
- data/lua-hooks/ext/perf/luameminfo.c +0 -38
- data/lua-hooks/ext/perf/luaoslib.c +0 -203
- data/lua-hooks/ext/perf/module.mk +0 -5
- data/lua-hooks/ext/sha1/luasha1.c +0 -74
- data/lua-hooks/ext/sha1/module.mk +0 -5
- data/lua-hooks/ext/sha1/sha1.c +0 -145
- data/lua-hooks/ext/sha2/luasha256.c +0 -77
- data/lua-hooks/ext/sha2/module.mk +0 -5
- data/lua-hooks/ext/sha2/sha256.c +0 -196
- data/lua-hooks/ext/sysutils/lua_utils.c +0 -56
- 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
|