immunio 1.1.18 → 1.1.19

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6055543c258054ef2deee718998ada2e1ee72b22
4
- data.tar.gz: cd78217a6233a81e01126f5a15f523e89325150f
3
+ metadata.gz: f0cf95fe27e81261056bdc9388cb78021e3f3e33
4
+ data.tar.gz: 91d07872cd32dbc236299020a62337c1296691ce
5
5
  SHA512:
6
- metadata.gz: a361784ac3f389ebbfe6c9e5511ebf422ab171a54a28f72fc30eeb8efab108b63ddc78ea2e2b912358a7c876dcd79b7f390cea9e96bbb42db11881e1123961e3
7
- data.tar.gz: 3811d95d95a73a07e0635061a110a3564e043fab77bfc5cb76c895fb927f7f07def36e445441246143f1b4054d53e146cf4311002d929491db5099009c6b327c
6
+ metadata.gz: c4d6a75b2a7d974ccd9cfc3e3e7c6744f72330ae6f4f23c926021ba002635a4bf807b32e8b15be17c39a70d3cba90a4f4da67c4ab003c70b466e7240b152e9e8
7
+ data.tar.gz: fd8e3009626ddbb2a97b1b72ce542f37f5df6d6b7f59f291738de125ec6c8ee312926791dbcf5eda634198a718ca6f107a0daf1f5e771322c23d054950f0d13a
@@ -19,8 +19,12 @@ module Immunio
19
19
  # Calculate context hashes and a stack trace. Additional data, in the form
20
20
  # of a String, may be provided to mix into the strict context hash.
21
21
  def self.context(additional_data=nil)
22
- # We can filter out at least the top two frames
23
- stack = caller(2).join "\n"
22
+ # Filter out agent stack frames. This includes string class_evals in `io`.
23
+ filtered_stack_frames = caller.reject do |frame|
24
+ frame =~ /lib\/immunio|^\(eval\):\d+:.+`.+_with_immunio'$/
25
+ end
26
+
27
+ stack = filtered_stack_frames.join "\n"
24
28
 
25
29
  cache_key = Digest::SHA1.hexdigest stack
26
30
 
@@ -38,13 +42,12 @@ module Immunio
38
42
 
39
43
  # drop the top frame as it's us, but retain the rest. Immunio frames
40
44
  # are filtered by the Gem regex.
41
- locations = caller(1).map do |frame|
45
+ locations = filtered_stack_frames.map do |frame|
42
46
  frame = frame.split(":", 3)
43
47
  { path: frame[0], line: frame[1], label: frame[2] }
44
48
  end
45
49
 
46
50
  locations.each do |frame|
47
-
48
51
  # Filter frame names from template rendering to remove generated random bits
49
52
  template_match = RAILS_TEMPLATE_FILTER.match(frame[:label])
50
53
  frame[:label] = template_match[1] + template_match[3] if template_match
@@ -10,12 +10,12 @@ module Immunio
10
10
  alias_method :lookup_without_immunio, :[]
11
11
  alias_method :[], :lookup_with_immunio
12
12
  end
13
-
14
13
  end
15
14
 
16
15
  def lookup_with_immunio(name)
17
16
  Request.time "plugin", "#{Module.nesting[0]}::#{__method__}" do
18
- raw_cookie_value = @parent_jar[name]
17
+ cookie_name = (Rails::VERSION::MAJOR > 4) ? name.to_s : name
18
+ raw_cookie_value = @parent_jar[cookie_name]
19
19
 
20
20
  cookie_value = Request.pause(
21
21
  'plugin',
@@ -27,7 +27,7 @@ module Immunio
27
27
  Immunio.run_hook!(
28
28
  'action_dispatch',
29
29
  'bad_cookie',
30
- key: name,
30
+ key: cookie_name,
31
31
  value: raw_cookie_value)
32
32
  end
33
33
 
@@ -135,6 +135,10 @@ Immunio::Plugin.load(
135
135
  if defined? UpgradeLegacyEncryptedCookieJar
136
136
  UpgradeLegacyEncryptedCookieJar.send :include, Immunio::CookieHooks
137
137
  end
138
+
139
+ if defined? PermanentCookieJar
140
+ PermanentCookieJar.send :include, Immunio::CookieHooks
141
+ end
138
142
  end
139
143
 
140
144
  plugin.loaded! ActionPack::VERSION::STRING
@@ -30,7 +30,8 @@ module Immunio
30
30
  end
31
31
 
32
32
  def id
33
- (@template.respond_to?(:virtual_path) && @template.virtual_path) || (@template.respond_to?(:source) && @template.source)
33
+ (@template.respond_to?(:virtual_path) && @template.virtual_path) ||
34
+ (@template.respond_to?(:source) && @template.source)
34
35
  end
35
36
 
36
37
  def ==(other)
@@ -146,7 +147,8 @@ module Immunio
146
147
  content = "" if content.nil?
147
148
 
148
149
  # See comment above
149
- if content =~ /\{immunio-var:\d+:#{nonce}\}/ then
150
+ if (content.respond_to? :=~) &&
151
+ (content =~ /\{immunio-var:\d+:#{nonce}\}/)
150
152
  # don't add markers.
151
153
  Immunio.logger.debug {"WARNING: ActionView not marking interpolation which already contains markers: \"#{content}\""}
152
154
  return content.html_safe
@@ -349,61 +351,68 @@ module Immunio
349
351
  end
350
352
 
351
353
  private
352
- def rendering_stack
353
- self.class.rendering_stack
354
- end
355
354
 
356
- def run_hook!(name, meta={})
357
- default_meta = {
358
- template_sha: template_sha,
359
- name: (@template.respond_to?(:virtual_path) && @template.virtual_path) || nil,
360
- origin: @template.identifier,
361
- nonce: Template.get_nonce
362
- }
363
- Immunio.run_hook! "action_view", name, default_meta.merge(meta)
364
- end
355
+ def rendering_stack
356
+ self.class.rendering_stack
357
+ end
365
358
 
366
- def write_and_remove_fragments!(context, content)
367
- # Rails tests do use the context as the view context sometimes.
368
- if context.is_a? ActionController::Base
369
- controller = context
370
- elsif context.respond_to? :controller
371
- controller = context.controller
372
- else
373
- # Some rails unit tests don't have a controller...
374
- remove_all_markers! content
375
- return
376
- end
359
+ def run_hook!(name, meta={})
360
+ default_meta = {
361
+ template_sha: template_sha,
362
+ name: (@template.respond_to?(:virtual_path) && @template.virtual_path) || nil,
363
+ origin: @template.identifier,
364
+ nonce: Template.get_nonce
365
+ }
366
+ Immunio.run_hook! "action_view", name, default_meta.merge(meta)
367
+ end
377
368
 
378
- # Iterate to handle nested fragments. Child fragments have lower ids than their parents.
379
- nonce = Template.get_nonce
380
- @scheduled_fragments_writes.each_with_index do |(key, _, options), id|
381
- # Remove the markers ...
382
- content.sub!(/\{immunio-fragment:#{id}:#{nonce}\}(.*)\{\/immunio-fragment:#{id}:#{nonce}\}/m) do
383
- # The escaped content inside the markers ($1), is written to cache.
384
- output = $1
385
- remove_all_markers! output
386
- controller.write_fragment_without_immunio key, output, options
387
- output
388
- end
389
- end
390
- # To be extra safe strip all markers from content
369
+ def write_and_remove_fragments!(context, content)
370
+ # Rails tests do use the context as the view context sometimes.
371
+ if context.is_a? ActionController::Base
372
+ controller = context
373
+ elsif context.respond_to? :controller
374
+ controller = context.controller
375
+ else
376
+ # Some rails unit tests don't have a controller...
391
377
  remove_all_markers! content
378
+ return
392
379
  end
393
380
 
394
- def remove_var_markers!(input)
395
- nonce = Template.get_nonce
396
- # TODO is this the fastest way to remove the markers? Needs benchmarking ...
397
- input.gsub!(/\{\/?immunio-var:\d+:#{nonce}\}/, "")
381
+ # Iterate to handle nested fragments. Child fragments have lower ids than their parents.
382
+ nonce = Template.get_nonce
383
+ @scheduled_fragments_writes.each_with_index do |(key, _, options), id|
384
+ # Remove the markers ...
385
+ content.sub!(/\{immunio-fragment:#{id}:#{nonce}\}(.*)\{\/immunio-fragment:#{id}:#{nonce}\}/m) do
386
+ # The escaped content inside the markers ($1), is written to cache.
387
+ output = $1
388
+ remove_all_markers! output
389
+ controller.write_fragment_without_immunio key, output, options
390
+ output
391
+ end
398
392
  end
393
+ # To be extra safe strip all markers from content
394
+ remove_all_markers! content
395
+ end
399
396
 
397
+ def remove_var_markers!(input)
398
+ nonce = Template.get_nonce
399
+ # TODO is this the fastest way to remove the markers? Needs benchmarking ...
400
+ input.gsub!(/\{\/?immunio-var:\d+:#{nonce}\}/, "")
401
+ end
402
+
403
+ def remove_all_markers!(input)
404
+ self.class.remove_all_markers!(input)
405
+ end
406
+
407
+ class << self
400
408
  def remove_all_markers!(input)
401
409
  input.gsub!(/\{\/?immunio-(fragment|var):\d+:[a-zA-Z0-9]+\}/, "")
402
410
  end
411
+ end
403
412
  end
404
413
 
405
414
  # Hooks for the ERB template engine.
406
- # (Default one used in Rails).
415
+ # (Default one used in Rails < 5).
407
416
  module ErubisHooks
408
417
  extend ActiveSupport::Concern
409
418
 
@@ -428,6 +437,30 @@ module Immunio
428
437
  end
429
438
  end
430
439
 
440
+ module ErubiHooks
441
+ extend ActiveSupport::Concern
442
+
443
+ included do
444
+ Immunio::Utils.alias_method_chain self, :add_expression, :immunio
445
+ end
446
+
447
+ def add_expression_with_immunio(indicator, code)
448
+ # Wrap expressions in the templates to track their rendered value.
449
+ # Do not wrap expressions with blocks, eg.: <%= form_tag do %>
450
+ # TODO should we support blocks?
451
+ Request.time "plugin", "#{Module.nesting[0]}::#{__method__}" do
452
+ unless code =~ ActionView::Template::Handlers::ERB::Erubi::BLOCK_EXPR
453
+ # escape unless we see the == indicator
454
+ escape = !(indicator == '==')
455
+ code = Immunio::Template.generate_render_var_code(code, escape)
456
+ end
457
+ Request.pause "plugin", "#{Module.nesting[0]}::#{__method__}" do
458
+ add_expression_without_immunio(indicator, code)
459
+ end
460
+ end
461
+ end
462
+ end
463
+
431
464
  # Hooks for the HAML template engine.
432
465
  module HamlHooks
433
466
  extend ActiveSupport::Concern
@@ -439,7 +472,13 @@ module Immunio
439
472
  def push_script_with_immunio(code, opts = {}, &block)
440
473
  # Wrap expressions in the templates to track their rendered value.
441
474
  Request.time "plugin", "#{Module.nesting[0]}::#{__method__}" do
442
- if code !~ ActionView::Template::Handlers::Erubis::BLOCK_EXPR
475
+ block_expr = if Rails::VERSION::MAJOR == 5 && Rails::VERSION::MINOR > 0
476
+ ActionView::Template::Handlers::ERB::Erubi::BLOCK_EXPR
477
+ else
478
+ ActionView::Template::Handlers::Erubis::BLOCK_EXPR
479
+ end
480
+
481
+ if code !~ block_expr
443
482
  # escape if we're told to by HAML
444
483
  code = Immunio::Template.generate_render_var_code(code, opts[:escape_html])
445
484
  end
@@ -519,6 +558,29 @@ module Immunio
519
558
  end
520
559
  end
521
560
 
561
+ module CacheStoreHooks
562
+ extend ActiveSupport::Concern
563
+
564
+ included do
565
+ Immunio::Utils.alias_method_chain self, :write, :immunio
566
+ end
567
+
568
+ # Rails 5 adds CollectionCaching. When used in the context of
569
+ # rendering a collection of items with a partial template, we
570
+ # need to remove our markers before writing to the cache store.
571
+ # See this blog post for more:
572
+ # http://blog.bigbinary.com/2016/03/09/rails-5-makes-partial-redering-from-cache-substantially-faster.html
573
+ def write_with_immunio(name, value, options = nil)
574
+ Request.time "plugin", "#{Module.nesting[0]}::#{__method__}" do
575
+ Template.remove_all_markers! value if value.is_a? String
576
+
577
+ Request.pause "plugin", "#{Module.nesting[0]}::#{__method__}" do
578
+ write_without_immunio(name, value, options)
579
+ end
580
+ end
581
+ end
582
+ end
583
+
522
584
  # Hook for the `ActiveSupport::Hash#to_query`.
523
585
  # Use case: building a url within a decorator that renders a partial with an interpolation.
524
586
  module ActiveSupportHooks
@@ -539,18 +601,32 @@ module Immunio
539
601
  escaped_string
540
602
  end
541
603
  end
604
+
605
+ XSS_HOOKS = %w[template_render_done template_render_var]
542
606
  end
543
607
 
544
608
  # Load the plugins
545
609
 
546
- Immunio::Plugin.load(
547
- 'Erubis',
548
- feature: 'xss',
549
- hooks: %w( template_render_done template_render_var )) do |plugin|
610
+ if Rails::VERSION::MAJOR == 5 && Rails::VERSION::MINOR > 0
611
+ Immunio::Plugin.load(
612
+ 'Erubi',
613
+ feature: 'xss',
614
+ hooks: Immunio::XSS_HOOKS) do |plugin|
550
615
 
551
- ActionView::Template::Handlers::Erubis.send :include, Immunio::ErubisHooks
616
+ ActionView::Template::Handlers::ERB::Erubi.send :include, Immunio::ErubiHooks
552
617
 
553
- plugin.loaded! Rails.version
618
+ plugin.loaded! Rails.version
619
+ end
620
+ else
621
+ Immunio::Plugin.load(
622
+ 'Erubis',
623
+ feature: 'xss',
624
+ hooks: Immunio::XSS_HOOKS) do |plugin|
625
+
626
+ ActionView::Template::Handlers::Erubis.send :include, Immunio::ErubisHooks
627
+
628
+ plugin.loaded! Rails.version
629
+ end
554
630
  end
555
631
 
556
632
  ActiveSupport.on_load(:after_initialize) do
@@ -558,7 +634,7 @@ ActiveSupport.on_load(:after_initialize) do
558
634
  Immunio::Plugin.load(
559
635
  'Haml',
560
636
  feature: 'xss',
561
- hooks: %w( template_render_done template_render_var )) do |plugin|
637
+ hooks: Immunio::XSS_HOOKS) do |plugin|
562
638
 
563
639
  if defined? Haml::Compiler
564
640
  Haml::Compiler.send :include, Immunio::HamlHooks
@@ -574,7 +650,7 @@ end
574
650
  Immunio::Plugin.load(
575
651
  'ActionView',
576
652
  feature: 'xss',
577
- hooks: %w( template_render_done template_render_var )) do |plugin|
653
+ hooks: Immunio::XSS_HOOKS) do |plugin|
578
654
 
579
655
  ActionView::TemplateRenderer.send :include, Immunio::TemplateRendererHooks
580
656
  ActionView::Template.send :include, Immunio::TemplateHooks
@@ -585,6 +661,7 @@ Immunio::Plugin.load(
585
661
  Immunio::FragmentCachingHooks)
586
662
  else
587
663
  AbstractController::Caching.send(:include, Immunio::FragmentCachingHooks)
664
+ ActiveSupport::Cache::Store.send(:include, Immunio::CacheStoreHooks)
588
665
  end
589
666
 
590
667
  plugin.loaded! Rails.version
@@ -15,21 +15,37 @@ module Immunio
15
15
 
16
16
  IGNORED_TYPES = [TrueClass, FalseClass, NilClass, Fixnum, Bignum, Float].freeze
17
17
 
18
- def quote_with_immunio(value, column = nil)
19
- Request.time "plugin", "#{Module.nesting[0]}::#{__method__}" do
20
- if column
21
- column_name = column.name
22
- else
23
- column_name = nil
24
- end
18
+ if Rails::VERSION::MAJOR == 5 && Rails::VERSION::MINOR > 0
19
+ # Passing a column to `quote` has been deprecated in 5.0.
20
+ def quote_with_immunio(value)
21
+ Request.time "plugin", "#{Module.nesting[0]}::#{__method__}" do
22
+ # Ignored empty strings and values that can't contain injections.
23
+ unless value.blank? || IGNORED_TYPES.include?(value.class)
24
+ QueryTracker.instance.add_param nil, value.to_s, object_id
25
+ end
25
26
 
26
- # Ignored empty strings and values that can't contain injections.
27
- unless value.blank? || IGNORED_TYPES.include?(value.class)
28
- QueryTracker.instance.add_param column_name, value.to_s, object_id
27
+ Request.pause "plugin", "#{Module.nesting[0]}::#{__method__}" do
28
+ quote_without_immunio(value)
29
+ end
29
30
  end
31
+ end
32
+ else
33
+ def quote_with_immunio(value, column = nil)
34
+ Request.time "plugin", "#{Module.nesting[0]}::#{__method__}" do
35
+ if column
36
+ column_name = column.name
37
+ else
38
+ column_name = nil
39
+ end
40
+
41
+ # Ignored empty strings and values that can't contain injections.
42
+ unless value.blank? || IGNORED_TYPES.include?(value.class)
43
+ QueryTracker.instance.add_param column_name, value.to_s, object_id
44
+ end
30
45
 
31
- Request.pause "plugin", "#{Module.nesting[0]}::#{__method__}" do
32
- quote_without_immunio(value, column)
46
+ Request.pause "plugin", "#{Module.nesting[0]}::#{__method__}" do
47
+ quote_without_immunio(value, column)
48
+ end
33
49
  end
34
50
  end
35
51
  end
@@ -629,21 +645,26 @@ module Immunio
629
645
  # When using the activerecord-sqlserver-adapter gem, the "column" is
630
646
  # the actual param name.
631
647
  name = column.respond_to?(:name) ? column.name : column.to_s
632
- params[name] = value.to_s
648
+
649
+ # Some AR tests (sqlite3 in particular) initialize a QueryAttribute
650
+ # with a nil `name`. This guards againt passing a nil key to Lua.
651
+ params[name] = value.to_s if name
633
652
  end
634
653
  end
635
654
 
636
655
  strict_context, loose_context, stack = Immunio::Context.context context_data
637
656
 
638
657
  # Send in additional_context_data for debugging purposes
639
- Immunio.run_hook! "active_record", "sql_execute", sql: payload[:sql],
640
- connection_uuid: connection_id.to_s,
641
- params: params,
642
- modifiers: modifiers,
643
- context_key: strict_context,
644
- loose_context_key: loose_context,
645
- stack: stack,
646
- additional_context_data: context_data
658
+ Immunio.run_hook! "active_record",
659
+ "sql_execute",
660
+ sql: payload[:sql],
661
+ connection_uuid: connection_id.to_s,
662
+ params: params,
663
+ modifiers: modifiers,
664
+ context_key: strict_context,
665
+ loose_context_key: loose_context,
666
+ stack: stack,
667
+ additional_context_data: context_data
647
668
 
648
669
  reset relation_id
649
670
  end
@@ -673,13 +694,18 @@ module Immunio
673
694
  extend ActiveSupport::Concern
674
695
 
675
696
  included do
676
- Immunio::Utils.alias_method_chain self, :log, :immunio if method_defined? :log
697
+ # As of Rails 5.1, :log is now private
698
+ if method_defined?(:log) || private_instance_methods.include?(:log)
699
+ Immunio::Utils.alias_method_chain self, :log, :immunio
700
+ end
677
701
  end
678
702
 
679
703
  def log_with_immunio(sql, name = "SQL", binds = [], *args)
680
- QueryTracker.instance.call sql: sql,
681
- connection_id: object_id,
682
- binds: binds
704
+ # Some rails tests (in particular postresql) call :log with nil `sql`.
705
+ QueryTracker.instance.call(
706
+ sql: sql,
707
+ connection_id: object_id,
708
+ binds: binds) if sql
683
709
 
684
710
  # Log and execute the query
685
711
  log_without_immunio(sql, name, binds, *args) { yield }
@@ -211,6 +211,9 @@ module Immunio
211
211
  :where!,
212
212
  :build_where
213
213
  ]
214
+
215
+ # Prevent infinite recursion!
216
+ self.methods_to_wrap.delete :merge
214
217
  end
215
218
 
216
219
  self.methods_to_wrap.each do |method|
@@ -267,13 +270,13 @@ module Immunio
267
270
 
268
271
  # When a statement is executed, push the original relation onto the
269
272
  # connection relation stack.
270
- def execute_with_immunio(*args)
273
+ def execute_with_immunio(*args, &block)
271
274
  Request.time "plugin", "Immunio::RelationTracking" do
272
275
  QueryTracker.instance.push_relation @__immunio_relation
273
276
  end
274
277
 
275
278
  begin
276
- execute_without_immunio(*args)
279
+ execute_without_immunio(*args, &block)
277
280
  ensure
278
281
  Request.time "plugin", "Immunio::RelationTracking" do
279
282
  QueryTracker.instance.pop_relation @__immunio_relation
@@ -300,60 +303,111 @@ module Immunio
300
303
  module HasManyThroughAssociationHooks
301
304
  extend ActiveSupport::Concern
302
305
 
303
- private
306
+ private
307
+
304
308
  # One off, non-ActiveRecord::Relation method that under one condition
305
309
  # executes a query in Rails 4.1 and up. Unfortunately, wrapping won't work
306
310
  # as the relation used to generate the query is a temporary relation that is
307
311
  # created in the method. The easiest way to deal with it, though very hacky,
308
312
  # is to copy the method from upstream Rails and push the temporary relation
309
313
  # onto the stack for the connection right before the query is executed.
310
- def delete_records_with_immunio(records, method, *args)
311
- scope = through_association.scope
314
+ if Rails::VERSION::MAJOR == 4 && Rails::VERSION::MINOR >= 1
315
+ def delete_records_with_immunio(records, method, *args)
316
+ scope = through_association.scope
312
317
 
313
- unless method == :destroy && !scope.klass.primary_key
314
- return delete_records_without_immunio(records, method, *args)
315
- end
318
+ unless method == :destroy && !scope.klass.primary_key
319
+ return delete_records_without_immunio(records, method, *args)
320
+ end
316
321
 
317
- # From here on down, copied from upstream Rails 4.2. Verified to work on
318
- # Rails 4.1, too.
319
- ensure_not_nested
322
+ # From here on down, copied from upstream Rails 4.2. Verified to work on
323
+ # Rails 4.1, too.
324
+ ensure_not_nested
320
325
 
321
- scope.where! construct_join_attributes(*records)
326
+ scope.where! construct_join_attributes(*records)
322
327
 
323
- scope.each do |record|
324
- record.run_callbacks :destroy
325
- end
328
+ scope.each do |record|
329
+ record.run_callbacks :destroy
330
+ end
326
331
 
327
- arel = scope.arel
332
+ arel = scope.arel
328
333
 
329
- stmt = Arel::DeleteManager.new arel.engine
330
- stmt.from scope.klass.arel_table
331
- stmt.wheres = arel.constraints
334
+ stmt = Arel::DeleteManager.new arel.engine
335
+ stmt.from scope.klass.arel_table
336
+ stmt.wheres = arel.constraints
332
337
 
333
- Request.time "plugin", "Immunio::RelationTracking" do
334
- QueryTracker.instance.push_relation scope
338
+ Request.time "plugin", "Immunio::RelationTracking" do
339
+ QueryTracker.instance.push_relation scope
340
+ end
341
+
342
+ begin
343
+ count = scope.klass.connection.delete(stmt, 'SQL', scope.bind_values)
344
+ ensure
345
+ Request.time "plugin", "Immunio::RelationTracking" do
346
+ QueryTracker.instance.pop_relation scope
347
+ end
348
+ end
349
+
350
+ delete_through_records(records)
351
+
352
+ if source_reflection.options[:counter_cache] && method != :destroy
353
+ counter = source_reflection.counter_cache_column
354
+ klass.decrement_counter counter, records.map(&:id)
355
+ end
356
+
357
+ if through_reflection.collection? && update_through_counter?(method)
358
+ update_counter(-count, through_reflection)
359
+ end
360
+
361
+ update_counter(-count)
335
362
  end
363
+ end
364
+
365
+ if Rails::VERSION::MAJOR == 5
366
+ def delete_records_with_immunio(records, method)
367
+ scope = through_association.scope
368
+
369
+ unless method == :destroy && !scope.klass.primary_key
370
+ return delete_records_without_immunio(records, method)
371
+ end
372
+
373
+ # From here on down, copied from upstream Rails 5.1.
374
+ ensure_not_nested
375
+
376
+ scope.where! construct_join_attributes(*records)
377
+
378
+ scope.each(&:_run_destroy_callbacks)
379
+
380
+ arel = scope.arel
381
+
382
+ stmt = Arel::DeleteManager.new
383
+ stmt.from scope.klass.arel_table
384
+ stmt.wheres = arel.constraints
336
385
 
337
- begin
338
- count = scope.klass.connection.delete(stmt, 'SQL', scope.bind_values)
339
- ensure
340
386
  Request.time "plugin", "Immunio::RelationTracking" do
341
- QueryTracker.instance.pop_relation scope
387
+ QueryTracker.instance.push_relation scope
342
388
  end
343
- end
344
389
 
345
- delete_through_records(records)
390
+ begin
391
+ count = scope.klass.connection.delete(stmt, "SQL", scope.bound_attributes)
392
+ ensure
393
+ Request.time "plugin", "Immunio::RelationTracking" do
394
+ QueryTracker.instance.pop_relation scope
395
+ end
396
+ end
346
397
 
347
- if source_reflection.options[:counter_cache] && method != :destroy
348
- counter = source_reflection.counter_cache_column
349
- klass.decrement_counter counter, records.map(&:id)
350
- end
398
+ delete_through_records(records)
351
399
 
352
- if through_reflection.collection? && update_through_counter?(method)
353
- update_counter(-count, through_reflection)
354
- end
400
+ if source_reflection.options[:counter_cache] && method != :destroy
401
+ counter = source_reflection.counter_cache_column
402
+ klass.decrement_counter counter, records.map(&:id)
403
+ end
355
404
 
356
- update_counter(-count)
405
+ if through_reflection.collection? && update_through_counter?(method)
406
+ update_counter(-count, through_reflection)
407
+ else
408
+ update_counter(-count)
409
+ end
410
+ end
357
411
  end
358
412
 
359
413
  included do
@@ -3,23 +3,35 @@ module Immunio
3
3
  extend ActiveSupport::Concern
4
4
 
5
5
  included do
6
- if method_defined? :verify_authenticity_token
7
- Immunio::Utils.alias_method_chain self, :verify_authenticity_token, :immunio
6
+ # As of Rails 5.1, :verify_authenticity_token is now private
7
+ if method_defined?(:verify_authenticity_token) ||
8
+ private_instance_methods.include?(:verify_authenticity_token)
9
+
10
+ Immunio::Utils.alias_method_chain(
11
+ self,
12
+ :verify_authenticity_token,
13
+ :immunio
14
+ )
8
15
  end
9
16
  end
10
17
 
11
18
  protected
12
- def verify_authenticity_token_with_immunio
13
- Request.time "plugin", "#{Module.nesting[0]}::#{__method__}" do
14
- Immunio.logger.debug { "ActiveSupport checking CSRF token" }
15
19
 
16
- Immunio.run_hook! "csrf", "framework_csrf_check", valid: verified_request?
20
+ def verify_authenticity_token_with_immunio
21
+ Request.time "plugin", "#{Module.nesting[0]}::#{__method__}" do
22
+ Immunio.logger.debug { "ActiveSupport checking CSRF token" }
23
+
24
+ Immunio.run_hook!(
25
+ "csrf",
26
+ "framework_csrf_check",
27
+ valid: verified_request?
28
+ )
17
29
 
18
- Request.pause "plugin", "#{Module.nesting[0]}::#{__method__}" do
19
- verify_authenticity_token_without_immunio
20
- end
30
+ Request.pause "plugin", "#{Module.nesting[0]}::#{__method__}" do
31
+ verify_authenticity_token_without_immunio
21
32
  end
22
33
  end
34
+ end
23
35
  end
24
36
  end
25
37
 
@@ -5,7 +5,9 @@ module Immunio
5
5
  extend ActiveSupport::Concern
6
6
 
7
7
  included do
8
- Immunio::Utils.alias_method_chain self, :redirect_to, :immunio if method_defined? :redirect_to
8
+ if method_defined? :redirect_to
9
+ Immunio::Utils.alias_method_chain self, :redirect_to, :immunio
10
+ end
9
11
  end
10
12
 
11
13
  protected
@@ -135,7 +135,7 @@ module Immunio
135
135
  def run_hook(plugin, hook, meta={})
136
136
  request = Request.current
137
137
 
138
- # Hooks called outside of a request are ignored since they are triggered while the framework is loaded.
138
+ # Hooks called outside of a request are ignored since they are triggered while the framework is loaded.
139
139
  return {} unless request
140
140
 
141
141
  # Notify about the hook. This has no perf cost if there are no subscribers.
@@ -1,5 +1,5 @@
1
1
  module Immunio
2
2
  AGENT_TYPE = "agent-ruby"
3
- VERSION = "1.1.18"
3
+ VERSION = "1.1.19"
4
4
  VM_VERSION = "2.2.0"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: immunio
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.18
4
+ version: 1.1.19
5
5
  platform: ruby
6
6
  authors:
7
7
  - Immunio
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-06-18 00:00:00.000000000 Z
11
+ date: 2017-07-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -464,9 +464,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
464
464
  version: '0'
465
465
  requirements: []
466
466
  rubyforge_project:
467
- rubygems_version: 2.6.11
467
+ rubygems_version: 2.6.12
468
468
  signing_key:
469
469
  specification_version: 4
470
470
  summary: Immunio Ruby agent
471
471
  test_files: []
472
- has_rdoc: