FIX: during concurrent emails generation renderer should not be reused

FIX: during concurrent emails generation renderer should not be reused

Our instance used for template rendering needs a lock to ensure there is no race condition where rendering happens on 2 threads at the same time.

This can lead to local poisoning which can cause unexpected results in emails

diff --git a/app/mailers/user_notifications.rb b/app/mailers/user_notifications.rb
index de8ac56..28e154f 100644
--- a/app/mailers/user_notifications.rb
+++ b/app/mailers/user_notifications.rb
@@ -589,7 +589,7 @@ class UserNotifications < ActionMailer::Base
       end
 
       unless translation_override_exists
-        html = UserNotificationRenderer.instance.render(
+        html = UserNotificationRenderer.render(
           template: 'email/notification',
           format: :html,
           locals: { context_posts: context_posts,
diff --git a/app/services/user_notification_renderer.rb b/app/services/user_notification_renderer.rb
index edf1171..64bb497 100644
--- a/app/services/user_notification_renderer.rb
+++ b/app/services/user_notification_renderer.rb
@@ -5,9 +5,15 @@ class UserNotificationRenderer < ActionView::Base
   include UserNotificationsHelper
   include EmailHelper
 
-  def self.instance
-    @instance ||= UserNotificationRenderer.with_view_paths(
-      Rails.configuration.paths["app/views"]
-    )
+  LOCK = Mutex.new
+
+  def self.render(*args)
+    LOCK.synchronize do
+      @instance ||= UserNotificationRenderer.with_view_paths(
+        Rails.configuration.paths["app/views"]
+      )
+      @instance.render(*args)
+    end
   end
+
 end
diff --git a/lib/email/message_builder.rb b/lib/email/message_builder.rb
index 654c4ae..df76f91 100644
--- a/lib/email/message_builder.rb
+++ b/lib/email/message_builder.rb
@@ -94,7 +94,7 @@ module Email
         html_override.gsub!("%{respond_instructions}", "")
       end
 
-      html = UserNotificationRenderer.instance.render(
+      html = UserNotificationRenderer.render(
         template: 'layouts/email_template',
         format: :html,
         locals: { html_body: html_override.html_safe }
diff --git a/lib/email/renderer.rb b/lib/email/renderer.rb
index 2f9203b..feeb63c 100644
--- a/lib/email/renderer.rb
+++ b/lib/email/renderer.rb
@@ -18,7 +18,7 @@ module Email
       style = if @message.html_part
         Email::Styles.new(@message.html_part.body.to_s, @opts)
       else
-        unstyled = UserNotificationRenderer.instance.render(
+        unstyled = UserNotificationRenderer.render(
           template: 'layouts/email_template',
           format: :html,
           locals: { html_body: PrettyText.cook(text).html_safe }

GitHub sha: 5aaf7e33

4 Likes