]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-7758 Rails flash feature should not use HTTP session
authorJulien Lancelot <julien.lancelot@sonarsource.com>
Thu, 21 Jul 2016 08:01:28 +0000 (10:01 +0200)
committerJulien Lancelot <julien.lancelot@sonarsource.com>
Fri, 9 Sep 2016 08:10:51 +0000 (10:10 +0200)
server/sonar-web/src/main/webapp/WEB-INF/app/controllers/application_controller.rb
server/sonar-web/src/main/webapp/WEB-INF/app/controllers/sessions_controller.rb
server/sonar-web/src/main/webapp/WEB-INF/app/views/layouts/_footer.html.erb
server/sonar-web/src/main/webapp/WEB-INF/app/views/sessions/_form.html.erb
server/sonar-web/src/main/webapp/WEB-INF/gems/gems/actionpack-2.3.15/lib/action_controller/base.rb
server/sonar-web/src/main/webapp/WEB-INF/gems/gems/actionpack-2.3.15/lib/action_controller/flash.rb
server/sonar-web/src/main/webapp/WEB-INF/lib/authenticated_system.rb
server/sonar-web/src/main/webapp/WEB-INF/lib/cookie_flash.rb [new file with mode: 0644]

index 0f19befb9b9d74f94ffabab177e2a60552373f7f..dc1cba4fc8b7bdcf1b489ac5561ee3dc9275f6a3 100644 (file)
@@ -21,6 +21,7 @@ class ApplicationController < ActionController::Base
 
   include AuthenticatedSystem
   include NeedAuthorization::Helper
+  include CookieFlash
 
   before_filter :check_database_version, :set_i18n, :check_authentication
 
index 51e8fda5ae0483a538b6e033755ef53daea4484a..f688c3551db36995c8f0586244619e79415ce86d 100644 (file)
@@ -32,8 +32,8 @@ class SessionsController < ApplicationController
     if logged_in?
       self.current_user.on_logout
     end
-    flash[:notice]=message('session.flash_notice.logged_out')
-    reset_session
+    cookies.delete 'JWT-SESSION'
+    cookies.delete 'XSRF-TOKEN'
     redirect_to(home_path)
   end
 
index c5dbab53411d3ddedff9f56b7d9febc73638b297..cccfd95447c8b0edf42846e7cd1e916ae9ffcfca 100644 (file)
@@ -8,13 +8,21 @@
 </div>
 <!--<![endif]-->
 
-<% if flash[:notice] || flash[:warning] || flash[:error] %>
+<% if cookies['flash'] %>
   <script>
-    <% if flash[:notice] %>info('<%= escape_javascript(flash[:notice])-%>');<% end %>
-    <% if flash[:warning] %>warning('<%= escape_javascript(flash[:warning])-%>');<% end %>
-    <% if flash[:error] %>error('<%= escape_javascript(flash[:error])-%>');<% end %>
+    var data = JSON.parse(unescape('<%= escape_javascript(cookies['flash']) -%>'));
+    if (data['notice']) {
+      info(data['notice'].toString().replace(/\+/g, ' '));
+    }
+    if (data['warning']) {
+      warning(data['warning'].toString().replace(/\+/g, ' '));
+    }
+    if (data['error']) {
+      error(data['error'].toString().replace(/\+/g, ' '));
+    }
   </script>
 <% end %>
+<% cookies.delete 'flash' %>
 
 <script src="<%= ApplicationController.root_context -%>/js/bundles/main.js?v=<%= sonar_version -%>"></script>
 <%= yield :extra_script -%>
index 3cb6a3187e018694849812d5d8f8055a373a87e0..9a5399f6e988a8e05016c77dadcbe8265413e2b4 100644 (file)
   <input type="hidden" name="return_to_anchor" value="<%= h @return_to_anchor %>">
 
   <div class="alert alert-danger alert-authentication-failed hidden"><%= message('session.flash_notice.authentication_failed') %></div>
-  <% if flash[:loginerror] %>
-    <div class="alert alert-danger alert-flash"> <%= flash[:loginerror] %></div>
-  <% end %>
-  <% if flash[:notice] %>
-    <div class="alert alert-info alert-flash"><%= flash[:notice] %></div>
-  <% end %>
+  <div class="hidden" id="messages-panel">
+    <div class="alert alert-danger alert-flash hidden" id="error">
+      <span id="errormsg"></span>
+    </div>
+    <div class="alert alert-info alert-flash hidden" id="info">
+      <span id="infomsg"></span>
+    </div>
+  </div>
 
   <div class="big-spacer-bottom">
     <label for="login" class="login-label"><%= message('login') %></label>
         401: null
       }
     });
+
+    <% if cookies['flash'] %>
+      var data = JSON.parse(unescape('<%= escape_javascript(cookies['flash']) -%>'));
+      if (data['loginerror']) {
+        error(data['loginerror'].toString().replace(/\+/g, ' '));
+      }
+      if (data['info']) {
+        info(data['info'].toString().replace(/\+/g, ' '));
+      }
+      <% cookies.delete 'flash' %>
+    <% end %>
+
   })(window.jQuery);
 </script>
+
index 3cc1d0619391a6ccb35d9dbac3a85d9b5dd38e6d..41a8a64ad26e9bbd7f8514731698d947dafe21b2 100644 (file)
@@ -1241,9 +1241,6 @@ module ActionController #:nodoc:
 
       # Resets the session by clearing out all the objects stored within and initializing a new session object.
       def reset_session #:doc:
-        cookies.delete 'JWT-SESSION'
-        cookies.delete 'XSRF-TOKEN'
-
         request.reset_session
         @_session = request.session
       end
index e15d0d80e765b3a830e046639a56f1910f0971c2..a47b8b5476e304197738e6d23c0509b680a310d7 100644 (file)
@@ -127,7 +127,7 @@ module ActionController #:nodoc:
 
       def store(session, key = "flash")
         return if self.empty?
-        session[key] = self
+        raise "Session are disabled"
       end
 
       private
@@ -181,7 +181,7 @@ module ActionController #:nodoc:
         # to put a new one.
         def flash #:doc:
           if !defined?(@_flash)
-            @_flash = session["flash"] || FlashHash.new
+            @_flash = FlashHash.new
             @_flash.sweep
           end
 
index 83ac2b912c44ff5a6ebe546a2b2cd69060e00e89..f60edd6088bdd6855426229e1337e70aedfbcff9 100644 (file)
@@ -78,6 +78,7 @@ module AuthenticatedSystem
         if logged_in?
           flash[:loginerror]='You are not authorized to access this page. Please log in with more privileges and try again.'
         end
+        write_flash_to_cookie
         redirect_to url_for :controller => '/sessions', :action => 'new'
       end
       # format.any doesn't work in rails version < http://dev.rubyonrails.org/changeset/8987
diff --git a/server/sonar-web/src/main/webapp/WEB-INF/lib/cookie_flash.rb b/server/sonar-web/src/main/webapp/WEB-INF/lib/cookie_flash.rb
new file mode 100644 (file)
index 0000000..1a0c928
--- /dev/null
@@ -0,0 +1,59 @@
+require 'json'
+
+module CookieFlash
+
+  def self.included(base)
+    #base must define around_action or around_filter, as in Rails
+
+    around_method = if base.respond_to?(:around_action)
+      :around_action
+    else
+      :around_filter
+    end
+
+    base.send around_method, :write_flash_to_cookie
+  end
+
+  def write_flash_to_cookie
+    yield if block_given?
+
+    if !flash.empty?
+      cookies['flash'] = { :value => cookie_flash(flash, cookies)}
+      #  because flashes are only removed from cookies when they are used.
+      flash.clear
+    end
+  end
+
+  # @parameters
+  #   cookies -
+  #     There might be crusty flash from a previous request, or set elsewhere, already in the cookie.
+  #     Pull it out and parse it so we can preserve it.
+  #   flash -
+  #     This is the fresh, super-stacked (by stackable_flash gem) FlashHash from the current request.
+  #     Needs to be added to the cookie flash.
+  def cookie_flash(flash, cookies)
+    cflash = (JSON.parse(cookies['flash']) if cookies['flash']) || {} rescue {}
+
+    flash.each do |key, value| # key like :notice, or :error, or :sticky
+      # When stacking we won't be escaping anything here, because will be array, not string
+      value = ERB::Util.html_escape(value) if value.kind_of?(String) && !value.html_safe? # Since v0.3.0 only escaping strings
+      skey = key.to_s
+      # This allows any data type to be stored in the cookie; important for using an array as the value with
+      # stackable_flash
+      # The cookie flash will generally be set to a value stacked according to the :stack_with_proc of stackable_flash
+      # But when there is already a value for the cookie when we get here, we need to join them somehow.
+      stacked_value = value.respond_to?(:stack) ? value.stack : value
+      if cflash[skey].kind_of?(Array) # Just because it could be an array
+        if stacked_value.kind_of?(Array)
+          cflash[skey] += stacked_value
+        else
+          cflash[skey] << stacked_value
+        end
+      else
+        cflash[skey] = stacked_value
+      end
+    end
+    # I have forgotten why the gsub + matters, so NOTE: to future self: document weird shit.
+    cflash.to_json.gsub("+", "%2B")
+  end
+end