From 1e5a2082dccaaa46ebf6dcbb005fa23e71f2ee0e Mon Sep 17 00:00:00 2001 From: Jyrki Gadinger Date: Fri, 21 Feb 2025 17:05:57 +0100 Subject: [PATCH] enforce readonly on create/update endpoints --- app/controllers/ajax/answer_controller.rb | 2 + app/controllers/ajax/comment_controller.rb | 2 + app/controllers/ajax/list_controller.rb | 1 + app/controllers/ajax/question_controller.rb | 2 + app/controllers/answer_controller.rb | 1 + app/controllers/application_controller.rb | 25 +++++++++++ app/controllers/inbox_controller.rb | 2 + app/controllers/reactions_controller.rb | 1 + app/controllers/relationships_controller.rb | 1 + .../settings/profile_controller.rb | 1 + .../settings/profile_picture_controller.rb | 1 + app/controllers/settings/theme_controller.rb | 1 + app/controllers/subscriptions_controller.rb | 1 + bin/rails | 0 bin/rake | 0 bin/setup | 0 config/locales/errors.en.yml | 2 + lib/errors.rb | 41 +++++++++---------- 18 files changed, 63 insertions(+), 21 deletions(-) mode change 100644 => 100755 bin/rails mode change 100644 => 100755 bin/rake mode change 100644 => 100755 bin/setup diff --git a/app/controllers/ajax/answer_controller.rb b/app/controllers/ajax/answer_controller.rb index 3674e887..7a12ea1c 100644 --- a/app/controllers/ajax/answer_controller.rb +++ b/app/controllers/ajax/answer_controller.rb @@ -5,6 +5,8 @@ require "cgi" class Ajax::AnswerController < AjaxController include SocialHelper + before_action :not_readonly!, except: %i[destroy] + def create params.require :id params.require :answer diff --git a/app/controllers/ajax/comment_controller.rb b/app/controllers/ajax/comment_controller.rb index c7264464..057e3aca 100644 --- a/app/controllers/ajax/comment_controller.rb +++ b/app/controllers/ajax/comment_controller.rb @@ -1,4 +1,6 @@ class Ajax::CommentController < AjaxController + before_action :not_readonly!, except: %i[destroy] + def create params.require :answer params.require :comment diff --git a/app/controllers/ajax/list_controller.rb b/app/controllers/ajax/list_controller.rb index 8da0266d..123a074d 100644 --- a/app/controllers/ajax/list_controller.rb +++ b/app/controllers/ajax/list_controller.rb @@ -2,6 +2,7 @@ class Ajax::ListController < AjaxController before_action :authenticate_user! + before_action :not_readonly!, except: %i[destroy] def create params.require :name diff --git a/app/controllers/ajax/question_controller.rb b/app/controllers/ajax/question_controller.rb index e2094fda..416ba99a 100644 --- a/app/controllers/ajax/question_controller.rb +++ b/app/controllers/ajax/question_controller.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true class Ajax::QuestionController < AjaxController + before_action :not_readonly!, except: %i[destroy] + def create params.require :question params.require :anonymousQuestion diff --git a/app/controllers/answer_controller.rb b/app/controllers/answer_controller.rb index 917501e5..0ff5ca86 100644 --- a/app/controllers/answer_controller.rb +++ b/app/controllers/answer_controller.rb @@ -2,6 +2,7 @@ class AnswerController < ApplicationController before_action :authenticate_user!, only: %i[pin unpin] + before_action :not_readonly!, except: %i[show] include TurboStreamable diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index cfd2fcc6..07d6a091 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -78,4 +78,29 @@ class ApplicationController < ActionController::Base Sentry.set_user({ ip_address: request.remote_ip }) end end + + # use this as a before_action to avoid anything happening when the site is in + # read-only mode + # + # useful only in: `AjaxController`s, or `TurboStreamable`s as the exception + # is rescued there + def not_readonly! + return unless Retrospring::Config.readonly? + + raise Errors::ReadOnlyMode + end + + # use this as a before_action to avoid anything happening when the site is in + # read-only mode + # + # useful anywhere else `not_readonly!` can't be used. it sets the error + # flash appropriately and renders the view given in `view_name` + def not_readonly_flash!(view_name) + return unless Retrospring::Config.readonly? + + flash[:error] = t("errors.read_only_mode") + render view_name + + false + end end diff --git a/app/controllers/inbox_controller.rb b/app/controllers/inbox_controller.rb index 26d4113c..32e71195 100644 --- a/app/controllers/inbox_controller.rb +++ b/app/controllers/inbox_controller.rb @@ -18,6 +18,8 @@ class InboxController < ApplicationController end def create + return redirect_to inbox_path if Retrospring::Config.readonly? + question = Question.create!(content: QuestionGenerator.generate, author_is_anonymous: true, author_identifier: "justask", diff --git a/app/controllers/reactions_controller.rb b/app/controllers/reactions_controller.rb index b1914e46..26cc8c85 100644 --- a/app/controllers/reactions_controller.rb +++ b/app/controllers/reactions_controller.rb @@ -4,6 +4,7 @@ class ReactionsController < ApplicationController include TurboStreamable before_action :authenticate_user!, only: %w[create destroy] + before_action :not_readonly!, except: %i[index] turbo_stream_actions :create, :destroy diff --git a/app/controllers/relationships_controller.rb b/app/controllers/relationships_controller.rb index e9965f79..58edd17f 100644 --- a/app/controllers/relationships_controller.rb +++ b/app/controllers/relationships_controller.rb @@ -4,6 +4,7 @@ class RelationshipsController < ApplicationController include TurboStreamable before_action :authenticate_user! + before_action :not_readonly! turbo_stream_actions :create, :destroy diff --git a/app/controllers/settings/profile_controller.rb b/app/controllers/settings/profile_controller.rb index 81344ca3..00c4840a 100644 --- a/app/controllers/settings/profile_controller.rb +++ b/app/controllers/settings/profile_controller.rb @@ -2,6 +2,7 @@ class Settings::ProfileController < ApplicationController before_action :authenticate_user! + before_action -> { not_readonly_flash!(:edit) }, only: %i[update] def edit; end diff --git a/app/controllers/settings/profile_picture_controller.rb b/app/controllers/settings/profile_picture_controller.rb index 68359fe7..2d2c3e39 100644 --- a/app/controllers/settings/profile_picture_controller.rb +++ b/app/controllers/settings/profile_picture_controller.rb @@ -2,6 +2,7 @@ class Settings::ProfilePictureController < ApplicationController before_action :authenticate_user! + before_action -> { not_readonly_flash!("settings/profile/edit") }, only: %i[update] def update user_attributes = params.require(:user).permit(:show_foreign_themes, :profile_picture_x, :profile_picture_y, :profile_picture_w, :profile_picture_h, diff --git a/app/controllers/settings/theme_controller.rb b/app/controllers/settings/theme_controller.rb index 94c87192..77938658 100644 --- a/app/controllers/settings/theme_controller.rb +++ b/app/controllers/settings/theme_controller.rb @@ -4,6 +4,7 @@ class Settings::ThemeController < ApplicationController include ThemeHelper before_action :authenticate_user! + before_action -> { not_readonly_flash!(:edit) }, only: %i[update destroy] def edit; end diff --git a/app/controllers/subscriptions_controller.rb b/app/controllers/subscriptions_controller.rb index 87049981..1bb92e57 100644 --- a/app/controllers/subscriptions_controller.rb +++ b/app/controllers/subscriptions_controller.rb @@ -4,6 +4,7 @@ class SubscriptionsController < ApplicationController include TurboStreamable before_action :authenticate_user! + before_action :not_readonly! turbo_stream_actions :create, :destroy diff --git a/bin/rails b/bin/rails old mode 100644 new mode 100755 diff --git a/bin/rake b/bin/rake old mode 100644 new mode 100755 diff --git a/bin/setup b/bin/setup old mode 100644 new mode 100755 diff --git a/config/locales/errors.en.yml b/config/locales/errors.en.yml index 7b260eff..45074717 100644 --- a/config/locales/errors.en.yml +++ b/config/locales/errors.en.yml @@ -23,6 +23,8 @@ en: blocking_self: "You cannot block yourself" muting_self: "You cannot mute yourself" + read_only_mode: "The website is in read-only mode." + not_found: "That does not exist" user_not_found: "User not found" diff --git a/lib/errors.rb b/lib/errors.rb index 5e2586c8..55954fc7 100644 --- a/lib/errors.rb +++ b/lib/errors.rb @@ -20,9 +20,23 @@ module Errors end class BadRequest < Base - def status - 400 - end + def status = 400 + end + + class NotAuthorized < Base + def status = 401 + end + + class Forbidden < Base + def status = 403 + end + + class NotFound < Base + def status = 404 + end + + class MethodNotAllowed < Base + def status = 405 end class InvalidBanDuration < BadRequest @@ -31,12 +45,6 @@ module Errors class QuestionTooLong < BadRequest end - class Forbidden < Base - def status - 403 - end - end - class SelfAction < Forbidden end @@ -46,18 +54,6 @@ module Errors class FollowingSelf < SelfAction end - class NotFound < Base - def status - 404 - end - end - - class NotAuthorized < Base - def status - 401 - end - end - class UserNotFound < NotFound end @@ -125,4 +121,7 @@ module Errors class MutingSelf < SelfAction end + + class ReadOnlyMode < MethodNotAllowed + end end