SECURITY: prevents arbitrary method call from input (#123)

SECURITY: prevents arbitrary method call from input (#123)

diff --git a/db/post_migrate/20201111005205_move_data_to_event_dates.rb b/db/post_migrate/20201111005205_move_data_to_event_dates.rb
index 9383aa3..fac6d65 100644
--- a/db/post_migrate/20201111005205_move_data_to_event_dates.rb
+++ b/db/post_migrate/20201111005205_move_data_to_event_dates.rb
@@ -51,9 +51,12 @@ class MoveDataToEventDates < ActiveRecord::Migration[6.0]
     return [] if event.reminders.blank?
     event.reminders.split(",").map do |reminder|
       value, unit = reminder.split('.')
-      date = event.original_starts_at - value.to_i.send(unit)
+
+      allowed = ["years", "months", "weeks", "days", "hours", "minutes", "seconds"]
+      next if !allowed.include?(unit)
+      date = event.original_starts_at - value.to_i.public_send(unit)
       { description: reminder, date: date }
-    end.select { |reminder| reminder[:date] <= Time.current }.sort_by { |reminder| reminder[:date] }
+    end.compact.select { |reminder| reminder[:date] <= Time.current }.sort_by { |reminder| reminder[:date] }
   end
 
   def up
diff --git a/jobs/scheduled/monitor_event_dates.rb b/jobs/scheduled/monitor_event_dates.rb
index 7e4a62e..22f84e3 100644
--- a/jobs/scheduled/monitor_event_dates.rb
+++ b/jobs/scheduled/monitor_event_dates.rb
@@ -46,9 +46,18 @@ module Jobs
       return [] if event_date.event.reminders.blank?
       event_date.event.reminders.split(",").map do |reminder|
         value, unit = reminder.split('.')
-        date = event_date.starts_at - value.to_i.send(unit)
+
+        next if !validate_reminder_unit(unit)
+
+        date = event_date.starts_at - value.to_i.public_send(unit)
         { description: reminder, date: date }
-      end.select { |reminder| reminder[:date] <= Time.current }.sort_by { |reminder| reminder[:date] }.drop(event_date.reminder_counter)
+      end.compact.select { |reminder| reminder[:date] <= Time.current }.sort_by { |reminder| reminder[:date] }.drop(event_date.reminder_counter)
+    end
+
+    private
+
+    def validate_reminder_unit(input)
+      ActiveSupport::Duration::PARTS.any? { |part| part.to_s == input }
     end
   end
 end
diff --git a/spec/jobs/scheduled/monitor_event_dates_spec.rb b/spec/jobs/scheduled/monitor_event_dates_spec.rb
index 395b2ee..505f218 100644
--- a/spec/jobs/scheduled/monitor_event_dates_spec.rb
+++ b/spec/jobs/scheduled/monitor_event_dates_spec.rb
@@ -97,4 +97,34 @@ describe DiscourseCalendar::MonitorEventDates do
       expect(events).to include(event_name: :discourse_post_event_event_ended, params: [past_event])
     end
   end
+
+  context '#due_reminders' do
+    fab!(:invalid_event) {
+      Fabricate(
+        :event,
+        post: Fabricate(:post),
+        original_starts_at: 7.days.after,
+        original_ends_at: 7.days.after + 1.hour,
+        reminders: "1.foo"
+      )
+    }
+
+    fab!(:valid_event) {
+      Fabricate(
+        :event,
+        post: Fabricate(:post),
+        original_starts_at: 7.days.after,
+        original_ends_at: 7.days.after + 1.hour,
+        reminders: "1.minutes"
+      )
+    }
+
+    it 'doesn’t list events with invalid reminders' do
+      freeze_time (7.days.after - 1.minutes)
+      event_dates_monitor = DiscourseCalendar::MonitorEventDates.new
+
+      expect(event_dates_monitor.due_reminders(invalid_event.event_dates.first)).to be_blank
+      expect(event_dates_monitor.due_reminders(valid_event.event_dates.first).length).to eq(1)
+    end
+  end
 end

GitHub sha: 227080a2

This commit appears in #123 which was approved by davidtaylorhq and udan11. It was merged by jjaffeux.