From 69017298e8394d80436bedba86c2b9ab089bf5fe Mon Sep 17 00:00:00 2001
From: Osama Sayegh <asooomaasoooma90@gmail.com>
Date: Thu, 18 Feb 2021 17:48:15 +0300
Subject: [PATCH] FIX: Limit post read time to the max integer value (#12126)

Some users somehow manage to keep a topic open for a very long time that it causes the post read time to exceed the max integer value (2^31 - 1) which causes errors when we try to update the read time in the database to values above the integer limit.

This PR will cap posts read time at 2^31 - 1 to prevent these errors.
---
 app/models/post_timing.rb               |  2 +-
 spec/requests/topics_controller_spec.rb | 23 +++++++++++++++++++++++
 2 files changed, 24 insertions(+), 1 deletion(-)

diff --git a/app/models/post_timing.rb b/app/models/post_timing.rb
index 8251d429074..7fbe31b8f81 100644
--- a/app/models/post_timing.rb
+++ b/app/models/post_timing.rb
@@ -165,7 +165,7 @@ class PostTiming < ActiveRecord::Base
     if join_table.length > 0
       sql = <<~SQL
       UPDATE post_timings t
-      SET msecs = t.msecs + x.msecs
+      SET msecs = LEAST(t.msecs::bigint + x.msecs, 2^31 - 1)
       FROM (#{join_table.join(" UNION ALL ")}) x
       WHERE x.topic_id = t.topic_id AND
             x.post_number = t.post_number AND
diff --git a/spec/requests/topics_controller_spec.rb b/spec/requests/topics_controller_spec.rb
index dbeb2dc91b2..4714d4d44b8 100644
--- a/spec/requests/topics_controller_spec.rb
+++ b/spec/requests/topics_controller_spec.rb
@@ -3057,6 +3057,29 @@ RSpec.describe TopicsController do
       expect(post_timing.user).to eq(user)
       expect(post_timing.msecs).to eq(2)
     end
+
+    it 'caps post read time at the max integer value (2^31 - 1)' do
+      PostTiming.create!(
+        topic_id: post_1.topic.id,
+        post_number: post_1.post_number,
+        user_id: user.id,
+        msecs: 2**31 - 10
+      )
+      sign_in(user)
+
+      post "/topics/timings.json", params: {
+        topic_id: topic.id,
+        topic_time: 5,
+        timings: { post_1.post_number => 100 }
+      }
+
+      expect(response.status).to eq(200)
+      post_timing = PostTiming.first
+
+      expect(post_timing.topic).to eq(topic)
+      expect(post_timing.user).to eq(user)
+      expect(post_timing.msecs).to eq(2**31 - 1)
+    end
   end
 
   describe '#timer' do