]> git.openstreetmap.org Git - rails.git/commitdiff
Merge pull request #4800 from AntonKhorev/welcome-stack
authorAndy Allan <git@gravitystorm.co.uk>
Wed, 15 May 2024 16:43:25 +0000 (17:43 +0100)
committerGitHub <noreply@github.com>
Wed, 15 May 2024 16:43:25 +0000 (17:43 +0100)
Stack welcome page columns on small screens

18 files changed:
Gemfile
Gemfile.lock
app/controllers/application_controller.rb
app/controllers/changesets_controller.rb
app/controllers/concerns/pagination_methods.rb
app/controllers/errors_controller.rb
app/controllers/notes_controller.rb
app/views/errors/bad_request.html.erb [new file with mode: 0644]
config/brakeman.ignore [new file with mode: 0644]
config/locales/en.yml
config/routes.rb
test/controllers/changesets_controller_test.rb
test/controllers/diary_entries_controller_test.rb
test/controllers/errors_controller_test.rb
test/controllers/notes_controller_test.rb
test/controllers/traces_controller_test.rb
test/controllers/user_blocks_controller_test.rb
test/controllers/users_controller_test.rb

diff --git a/Gemfile b/Gemfile
index 04395b49a6d1b760c15574b8043c436cf5e924ba..75387b5d5e3b5c8db060e427ca352e834c6b6014 100644 (file)
--- a/Gemfile
+++ b/Gemfile
@@ -63,6 +63,7 @@ gem "oauth-plugin", ">= 0.5.1"
 gem "openstreetmap-deadlock_retry", ">= 1.3.1", :require => "deadlock_retry"
 gem "rack-cors"
 gem "rails-i18n", "~> 7.0.0"
+gem "rails_param"
 gem "rinku", ">= 2.0.6", :require => "rails_rinku"
 gem "strong_migrations"
 gem "validates_email_format_of", ">= 1.5.1"
index 087e19f45d708642b40c45355264f184dc6645d5..14beee830f5a12ad1b8b2f8fde27d9d61b79ac68 100644 (file)
@@ -458,6 +458,9 @@ GEM
     rails-i18n (7.0.9)
       i18n (>= 0.7, < 2)
       railties (>= 6.0.0, < 8)
+    rails_param (1.3.1)
+      actionpack (>= 3.2.0)
+      activesupport (>= 3.2.0)
     railties (7.1.3.2)
       actionpack (= 7.1.3.2)
       activesupport (= 7.1.3.2)
@@ -672,6 +675,7 @@ DEPENDENCIES
   rails (~> 7.1.0)
   rails-controller-testing
   rails-i18n (~> 7.0.0)
+  rails_param
   rinku (>= 2.0.6)
   rotp
   rtlcss
index 5d69a5fc8c1fb54c16f7b382b059096bce4122ad..f5accc3c44d2d65654105a828d5ccc0fc6e94b64 100644 (file)
@@ -10,6 +10,8 @@ class ApplicationController < ActionController::Base
   rescue_from CanCan::AccessDenied, :with => :deny_access
   check_authorization
 
+  rescue_from RailsParam::InvalidParameterError, :with => :invalid_parameter
+
   before_action :fetch_body
   around_action :better_errors_allow_inline, :if => proc { Rails.env.development? }
 
@@ -310,6 +312,17 @@ class ApplicationController < ActionController::Base
     end
   end
 
+  def invalid_parameter(_exception)
+    if request.get?
+      respond_to do |format|
+        format.html { redirect_to :controller => "/errors", :action => "bad_request" }
+        format.any { head :bad_request }
+      end
+    else
+      head :bad_request
+    end
+  end
+
   # extract authorisation credentials from headers, returns user = nil if none
   def auth_data
     if request.env.key? "X-HTTP_AUTHORIZATION" # where mod_rewrite might have put it
index 6a80f260ad05f99128a631558c2adac886f49b2a..19ec9c91ef5967a53661817e5f1966c08ae0400e 100644 (file)
@@ -18,6 +18,8 @@ class ChangesetsController < ApplicationController
   ##
   # list non-empty changesets in reverse chronological order
   def index
+    param! :max_id, Integer, :min => 1
+
     @params = params.permit(:display_name, :bbox, :friends, :nearby, :max_id, :list)
 
     if request.format == :atom && @params[:max_id]
index 3dc9f52aad3057726c69435227ec381a3fe808f0..79ab10bfb1a6c9bb8c47937406b2d29952df9c70 100644 (file)
@@ -6,6 +6,9 @@ module PaginationMethods
   ##
   # limit selected items to one page, get ids of first item before/after the page
   def get_page_items(items, includes: [], limit: 20)
+    param! :before, Integer, :min => 1
+    param! :after, Integer, :min => 1
+
     id_column = "#{items.table_name}.id"
     page_items = if params[:before]
                    items.where("#{id_column} < ?", params[:before]).order(:id => :desc)
index ee1fcca6f8892ea346c1cacd3161eebc9c56983c..605403348a07ecacc543ae4c9ecfdc2eabe759ab 100644 (file)
@@ -5,6 +5,13 @@ class ErrorsController < ApplicationController
 
   before_action :set_locale
 
+  def bad_request
+    respond_to do |format|
+      format.html { render :status => :bad_request }
+      format.any { render :status => :bad_request, :plain => "" }
+    end
+  end
+
   def forbidden
     respond_to do |format|
       format.html { render :status => :forbidden }
index 97efc3eda8128f79bbd0a870b347cebc0c384501..26d27692e5cd5804386aca35191e68e26bbd7dbe 100644 (file)
@@ -16,6 +16,8 @@ class NotesController < ApplicationController
   ##
   # Display a list of notes by a specified user
   def index
+    param! :page, Integer, :min => 1
+
     @params = params.permit(:display_name)
     @title = t ".title", :user => @user.display_name
     @page = (params[:page] || 1).to_i
diff --git a/app/views/errors/bad_request.html.erb b/app/views/errors/bad_request.html.erb
new file mode 100644 (file)
index 0000000..036517b
--- /dev/null
@@ -0,0 +1,3 @@
+<h1><%= t ".title" %></h1>
+<p><%= t ".description" %></p>
+<%= render :partial => "contact" %>
diff --git a/config/brakeman.ignore b/config/brakeman.ignore
new file mode 100644 (file)
index 0000000..b8fed1d
--- /dev/null
@@ -0,0 +1,29 @@
+{
+  "ignored_warnings": [
+    {
+      "warning_type": "HTTP Verb Confusion",
+      "warning_code": 118,
+      "fingerprint": "9567bbac855c6ec5552572700ec809d7c1d77f59953e6725aeca54fee5091674",
+      "check_name": "VerbConfusion",
+      "message": "Potential HTTP verb confusion. `HEAD` is routed like `GET` but `request.get?` will return `false`",
+      "file": "app/controllers/application_controller.rb",
+      "line": 312,
+      "link": "https://brakemanscanner.org/docs/warning_types/http_verb_confusion/",
+      "code": "if request.get? then\n  respond_to do\n   format.html do\n   redirect_to(:controller => \"/errors\", :action => \"bad_request\")\n   end\n  format.any do\n   head(:bad_request)\n   end\n   end\nelse\n  head(:bad_request)\nend",
+      "render_path": null,
+      "location": {
+        "type": "method",
+        "class": "ApplicationController",
+        "method": "invalid_parameter"
+      },
+      "user_input": "request.get?",
+      "confidence": "Weak",
+      "cwe_id": [
+        352
+      ],
+      "note": ""
+    }
+  ],
+  "updated": "2024-04-11 10:07:03 +0100",
+  "brakeman_version": "6.1.2"
+}
index fdd3077ac2403ef01b462b3b16bd808021f18e28..647cf66f2c6194560b76fc40d765cfaac82496b3 100644 (file)
@@ -633,6 +633,9 @@ en:
       contact_url_title: Various contact channels explained
       contact: contact
       contact_the_community_html: Feel free to %{contact_link} the OpenStreetMap community if you have found a broken link / bug. Make a note of the exact URL of your request.
+    bad_request:
+      title: Bad request
+      description: The operation you requested on the OpenStreetMap server is not valid (HTTP 400)
     forbidden:
       title: Forbidden
       description: The operation you requested on the OpenStreetMap server is only available to administrators (HTTP 403)
index 8271e7e4dba1b95f05b4027af56a5d5cc0aac605..c44064ba325c7f975f6af0c3f6e26bef823492db 100644 (file)
@@ -347,6 +347,7 @@ OpenStreetMap::Application.routes.draw do
   resources :redactions
 
   # errors
+  match "/400", :to => "errors#bad_request", :via => :all
   match "/403", :to => "errors#forbidden", :via => :all
   match "/404", :to => "errors#not_found", :via => :all
   match "/500", :to => "errors#internal_server_error", :via => :all
index 3d264181c4cde89bb6e65dea54d6291d4351bb5a..a486e4b5ee87f98f955fe1de82d5647ec93d4cc1 100644 (file)
@@ -92,6 +92,15 @@ class ChangesetsControllerTest < ActionDispatch::IntegrationTest
     check_index_result(changesets.last(20))
   end
 
+  ##
+  # This should report an error
+  def test_index_invalid_xhr
+    %w[-1 0 fred].each do |id|
+      get history_path(:format => "html", :list => "1", :max_id => id)
+      assert_redirected_to :controller => :errors, :action => :bad_request
+    end
+  end
+
   ##
   # This should display the last 20 changesets closed in a specific area
   def test_index_bbox
index 2b10402fa04cd14d159e3d3c76749cb42f758aab..d13a50163ea8bc59e15af03885e25385379ac71a 100644 (file)
@@ -590,6 +590,17 @@ class DiaryEntriesControllerTest < ActionDispatch::IntegrationTest
     assert_select "li.page-item.disabled span.page-link", :text => "Newer Entries", :count => 1
   end
 
+  def test_index_invalid_paged
+    # Try some invalid paged accesses
+    %w[-1 0 fred].each do |id|
+      get diary_entries_path(:before => id)
+      assert_redirected_to :controller => :errors, :action => :bad_request
+
+      get diary_entries_path(:after => id)
+      assert_redirected_to :controller => :errors, :action => :bad_request
+    end
+  end
+
   def test_rss
     create(:language, :code => "de")
     create(:diary_entry, :language_code => "en")
@@ -899,6 +910,18 @@ class DiaryEntriesControllerTest < ActionDispatch::IntegrationTest
     assert_response :not_found
   end
 
+  def test_comments_invalid_paged
+    user = create(:user)
+
+    %w[-1 0 fred].each do |id|
+      get diary_comments_path(:display_name => user.display_name, :before => id)
+      assert_redirected_to :controller => :errors, :action => :bad_request
+
+      get diary_comments_path(:display_name => user.display_name, :after => id)
+      assert_redirected_to :controller => :errors, :action => :bad_request
+    end
+  end
+
   def test_subscribe_page
     user = create(:user)
     other_user = create(:user)
index 9f8ccee56d66acc34b147625b643af81698df178..253cbbdc0bf795463afd2061ee610c789b11b663 100644 (file)
@@ -2,6 +2,10 @@ require "test_helper"
 
 class ErrorsControllerTest < ActionDispatch::IntegrationTest
   def test_routes
+    assert_routing(
+      { :path => "/400", :method => :get },
+      { :controller => "errors", :action => "bad_request" }
+    )
     assert_routing(
       { :path => "/403", :method => :get },
       { :controller => "errors", :action => "forbidden" }
@@ -16,6 +20,11 @@ class ErrorsControllerTest < ActionDispatch::IntegrationTest
     )
   end
 
+  def test_bad_request
+    get "/400"
+    assert_response :bad_request
+  end
+
   def test_forbidden
     get "/403"
     assert_response :forbidden
index a543342698648aad26dc1991a42fcc3f0ab2330f..4092ad7326599cfe964b7adc97d8790a57f7570e 100644 (file)
@@ -83,6 +83,15 @@ class NotesControllerTest < ActionDispatch::IntegrationTest
     assert_select "table.note_list tbody tr", :count => 10
   end
 
+  def test_index_invalid_paged
+    user = create(:user)
+
+    %w[-1 0 fred].each do |page|
+      get user_notes_path(user, :page => page)
+      assert_redirected_to :controller => :errors, :action => :bad_request
+    end
+  end
+
   def test_empty_page
     user = create(:user)
     get user_notes_path(user)
index 73966641eb8641f346c25429bba0cd233f5421c0..972cbb3c32be43e42978e19f27c74c633464ac97 100644 (file)
@@ -322,6 +322,17 @@ class TracesControllerTest < ActionDispatch::IntegrationTest
     assert_select "li.page-item a.page-link", :text => "Older Traces", :count => 2
   end
 
+  def test_index_invalid_paged
+    # Try some invalid paged accesses
+    %w[-1 0 fred].each do |id|
+      get traces_path(:before => id)
+      assert_redirected_to :controller => :errors, :action => :bad_request
+
+      get traces_path(:after => id)
+      assert_redirected_to :controller => :errors, :action => :bad_request
+    end
+  end
+
   # Check the RSS feed
   def test_rss
     user = create(:user)
index a7ab02c75fb9afa5011f8a1b275e743df1d3d677..97f5171335d4910fd27e53fda34bc6ea8dc8e2f5 100644 (file)
@@ -115,6 +115,18 @@ class UserBlocksControllerTest < ActionDispatch::IntegrationTest
     check_no_page_link "Older Blocks"
   end
 
+  ##
+  # test the index action with invalid pages
+  def test_index_invalid_paged
+    %w[-1 0 fred].each do |id|
+      get user_blocks_path(:before => id)
+      assert_redirected_to :controller => :errors, :action => :bad_request
+
+      get user_blocks_path(:after => id)
+      assert_redirected_to :controller => :errors, :action => :bad_request
+    end
+  end
+
   ##
   # test the show action
   def test_show
@@ -560,6 +572,20 @@ class UserBlocksControllerTest < ActionDispatch::IntegrationTest
     check_no_page_link "Older Blocks"
   end
 
+  ##
+  # test the blocks_on action with invalid pages
+  def test_blocks_on_invalid_paged
+    user = create(:user)
+
+    %w[-1 0 fred].each do |id|
+      get user_blocks_on_path(user, :before => id)
+      assert_redirected_to :controller => :errors, :action => :bad_request
+
+      get user_blocks_on_path(user, :after => id)
+      assert_redirected_to :controller => :errors, :action => :bad_request
+    end
+  end
+
   ##
   # test the blocks_by action
   def test_blocks_by
@@ -628,6 +654,20 @@ class UserBlocksControllerTest < ActionDispatch::IntegrationTest
     check_no_page_link "Older Blocks"
   end
 
+  ##
+  # test the blocks_by action with invalid pages
+  def test_blocks_by_invalid_paged
+    user = create(:moderator_user)
+
+    %w[-1 0 fred].each do |id|
+      get user_blocks_by_path(user, :before => id)
+      assert_redirected_to :controller => :errors, :action => :bad_request
+
+      get user_blocks_by_path(user, :after => id)
+      assert_redirected_to :controller => :errors, :action => :bad_request
+    end
+  end
+
   private
 
   def check_user_blocks_table(user_blocks)
index c5566e65db4ae534015fa97331fba7c6f2c7fd05..cff52cff25a24fc2ff3ccf251c3b533b6ba94ce5 100644 (file)
@@ -558,6 +558,18 @@ class UsersControllerTest < ActionDispatch::IntegrationTest
     check_no_page_link "Older Users"
   end
 
+  def test_index_get_invalid_paginated
+    session_for(create(:administrator_user))
+
+    %w[-1 0 fred].each do |id|
+      get users_path(:before => id)
+      assert_redirected_to :controller => :errors, :action => :bad_request
+
+      get users_path(:after => id)
+      assert_redirected_to :controller => :errors, :action => :bad_request
+    end
+  end
+
   private
 
   def check_no_page_link(name)