enforce readonly on create/update endpoints

This commit is contained in:
Jyrki Gadinger 2025-02-21 17:05:57 +01:00 committed by Andreas Nedbal
parent e2122a4add
commit 1e5a2082dc
18 changed files with 63 additions and 21 deletions

View file

@ -5,6 +5,8 @@ require "cgi"
class Ajax::AnswerController < AjaxController class Ajax::AnswerController < AjaxController
include SocialHelper include SocialHelper
before_action :not_readonly!, except: %i[destroy]
def create def create
params.require :id params.require :id
params.require :answer params.require :answer

View file

@ -1,4 +1,6 @@
class Ajax::CommentController < AjaxController class Ajax::CommentController < AjaxController
before_action :not_readonly!, except: %i[destroy]
def create def create
params.require :answer params.require :answer
params.require :comment params.require :comment

View file

@ -2,6 +2,7 @@
class Ajax::ListController < AjaxController class Ajax::ListController < AjaxController
before_action :authenticate_user! before_action :authenticate_user!
before_action :not_readonly!, except: %i[destroy]
def create def create
params.require :name params.require :name

View file

@ -1,6 +1,8 @@
# frozen_string_literal: true # frozen_string_literal: true
class Ajax::QuestionController < AjaxController class Ajax::QuestionController < AjaxController
before_action :not_readonly!, except: %i[destroy]
def create def create
params.require :question params.require :question
params.require :anonymousQuestion params.require :anonymousQuestion

View file

@ -2,6 +2,7 @@
class AnswerController < ApplicationController class AnswerController < ApplicationController
before_action :authenticate_user!, only: %i[pin unpin] before_action :authenticate_user!, only: %i[pin unpin]
before_action :not_readonly!, except: %i[show]
include TurboStreamable include TurboStreamable

View file

@ -78,4 +78,29 @@ class ApplicationController < ActionController::Base
Sentry.set_user({ ip_address: request.remote_ip }) Sentry.set_user({ ip_address: request.remote_ip })
end end
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 end

View file

@ -18,6 +18,8 @@ class InboxController < ApplicationController
end end
def create def create
return redirect_to inbox_path if Retrospring::Config.readonly?
question = Question.create!(content: QuestionGenerator.generate, question = Question.create!(content: QuestionGenerator.generate,
author_is_anonymous: true, author_is_anonymous: true,
author_identifier: "justask", author_identifier: "justask",

View file

@ -4,6 +4,7 @@ class ReactionsController < ApplicationController
include TurboStreamable include TurboStreamable
before_action :authenticate_user!, only: %w[create destroy] before_action :authenticate_user!, only: %w[create destroy]
before_action :not_readonly!, except: %i[index]
turbo_stream_actions :create, :destroy turbo_stream_actions :create, :destroy

View file

@ -4,6 +4,7 @@ class RelationshipsController < ApplicationController
include TurboStreamable include TurboStreamable
before_action :authenticate_user! before_action :authenticate_user!
before_action :not_readonly!
turbo_stream_actions :create, :destroy turbo_stream_actions :create, :destroy

View file

@ -2,6 +2,7 @@
class Settings::ProfileController < ApplicationController class Settings::ProfileController < ApplicationController
before_action :authenticate_user! before_action :authenticate_user!
before_action -> { not_readonly_flash!(:edit) }, only: %i[update]
def edit; end def edit; end

View file

@ -2,6 +2,7 @@
class Settings::ProfilePictureController < ApplicationController class Settings::ProfilePictureController < ApplicationController
before_action :authenticate_user! before_action :authenticate_user!
before_action -> { not_readonly_flash!("settings/profile/edit") }, only: %i[update]
def update def update
user_attributes = params.require(:user).permit(:show_foreign_themes, :profile_picture_x, :profile_picture_y, :profile_picture_w, :profile_picture_h, user_attributes = params.require(:user).permit(:show_foreign_themes, :profile_picture_x, :profile_picture_y, :profile_picture_w, :profile_picture_h,

View file

@ -4,6 +4,7 @@ class Settings::ThemeController < ApplicationController
include ThemeHelper include ThemeHelper
before_action :authenticate_user! before_action :authenticate_user!
before_action -> { not_readonly_flash!(:edit) }, only: %i[update destroy]
def edit; end def edit; end

View file

@ -4,6 +4,7 @@ class SubscriptionsController < ApplicationController
include TurboStreamable include TurboStreamable
before_action :authenticate_user! before_action :authenticate_user!
before_action :not_readonly!
turbo_stream_actions :create, :destroy turbo_stream_actions :create, :destroy

0
bin/rails Normal file → Executable file
View file

0
bin/rake Normal file → Executable file
View file

0
bin/setup Normal file → Executable file
View file

View file

@ -23,6 +23,8 @@ en:
blocking_self: "You cannot block yourself" blocking_self: "You cannot block yourself"
muting_self: "You cannot mute yourself" muting_self: "You cannot mute yourself"
read_only_mode: "The website is in read-only mode."
not_found: "That does not exist" not_found: "That does not exist"
user_not_found: "User not found" user_not_found: "User not found"

View file

@ -20,9 +20,23 @@ module Errors
end end
class BadRequest < Base class BadRequest < Base
def status def status = 400
400
end 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 end
class InvalidBanDuration < BadRequest class InvalidBanDuration < BadRequest
@ -31,12 +45,6 @@ module Errors
class QuestionTooLong < BadRequest class QuestionTooLong < BadRequest
end end
class Forbidden < Base
def status
403
end
end
class SelfAction < Forbidden class SelfAction < Forbidden
end end
@ -46,18 +54,6 @@ module Errors
class FollowingSelf < SelfAction class FollowingSelf < SelfAction
end end
class NotFound < Base
def status
404
end
end
class NotAuthorized < Base
def status
401
end
end
class UserNotFound < NotFound class UserNotFound < NotFound
end end
@ -125,4 +121,7 @@ module Errors
class MutingSelf < SelfAction class MutingSelf < SelfAction
end end
class ReadOnlyMode < MethodNotAllowed
end
end end