dmails, emails: refactor to use Rails signed_id.
Refactor email verification links and Dmail share links to use the new Rails signed_id mechanism, rather than our own handrolled mechanism. For Dmail share links, we have to override some Rails internal methods so that our old links still work. For email verification links, this will invalidate existing links, but this isn't a huge deal since these links are short-lived anyway. https://api.rubyonrails.org/classes/ActiveRecord/SignedId.html https://api.rubyonrails.org/classes/ActiveRecord/SignedId/ClassMethods.html
This commit is contained in:
@@ -99,6 +99,8 @@ class ApplicationController < ActionController::Base
|
||||
render_error_page(401, exception, template: "sessions/new")
|
||||
when ActionController::InvalidAuthenticityToken, ActionController::UnpermittedParameters, ActionController::InvalidCrossOriginRequest
|
||||
render_error_page(403, exception)
|
||||
when ActiveSupport::MessageVerifier::InvalidSignature # raised by `find_signed!`
|
||||
render_error_page(403, exception, template: "static/access_denied", message: "Access denied")
|
||||
when User::PrivilegeError, Pundit::NotAuthorizedError
|
||||
render_error_page(403, exception, template: "static/access_denied", message: "Access denied")
|
||||
when ActiveRecord::RecordNotFound
|
||||
|
||||
@@ -20,7 +20,11 @@ class DmailsController < ApplicationController
|
||||
end
|
||||
|
||||
def show
|
||||
@dmail = authorize Dmail.find(params[:id])
|
||||
if params[:key].present?
|
||||
@dmail = Dmail.find_signed!(params[:key], purpose: "dmail_link")
|
||||
else
|
||||
@dmail = authorize Dmail.find(params[:id])
|
||||
end
|
||||
|
||||
if request.format.html? && @dmail.owner == CurrentUser.user
|
||||
@dmail.update!(is_read: true)
|
||||
|
||||
@@ -48,8 +48,7 @@ class EmailsController < ApplicationController
|
||||
|
||||
if @email_address.blank?
|
||||
redirect_to edit_user_email_path(@user)
|
||||
elsif params[:email_verification_key].present?
|
||||
authorize @email_address
|
||||
elsif params[:email_verification_key].present? && @email_address == EmailAddress.find_signed!(params[:email_verification_key], purpose: "verify")
|
||||
@email_address.verify!
|
||||
flash[:notice] = "Email address verified"
|
||||
redirect_to @email_address.user
|
||||
|
||||
@@ -109,16 +109,20 @@ class Dmail < ApplicationRecord
|
||||
end
|
||||
|
||||
concerning :AuthorizationMethods do
|
||||
def verifier
|
||||
@verifier ||= Danbooru::MessageVerifier.new(:dmail_link)
|
||||
class_methods do
|
||||
# XXX hack so that rails' signed_id mechanism works with our pre-existing dmail keys.
|
||||
# https://github.com/rails/rails/blob/main/activerecord/lib/active_record/signed_id.rb
|
||||
def signed_id_verifier_secret
|
||||
Rails.application.key_generator.generate_key("dmail_link")
|
||||
end
|
||||
|
||||
def combine_signed_id_purposes(purpose)
|
||||
purpose
|
||||
end
|
||||
end
|
||||
|
||||
def key
|
||||
verifier.generate(id)
|
||||
end
|
||||
|
||||
def valid_key?(key)
|
||||
id == verifier.verified(key)
|
||||
signed_id(purpose: "dmail_link")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -69,17 +69,7 @@ class EmailAddress < ApplicationRecord
|
||||
end
|
||||
end
|
||||
|
||||
concerning :VerificationMethods do
|
||||
def verifier
|
||||
@verifier ||= Danbooru::MessageVerifier.new(:email_verification_key)
|
||||
end
|
||||
|
||||
def verification_key
|
||||
verifier.generate(id)
|
||||
end
|
||||
|
||||
def valid_key?(key)
|
||||
id == verifier.verified(key)
|
||||
end
|
||||
def verification_key
|
||||
signed_id(purpose: "verify")
|
||||
end
|
||||
end
|
||||
|
||||
@@ -17,7 +17,7 @@ class DmailPolicy < ApplicationPolicy
|
||||
|
||||
def show?
|
||||
return true if user.is_owner?
|
||||
!user.is_anonymous? && (record.owner_id == user.id || record.valid_key?(request.params[:key]))
|
||||
!user.is_anonymous? && record.owner_id == user.id
|
||||
end
|
||||
|
||||
def reportable?
|
||||
|
||||
@@ -13,11 +13,7 @@ class EmailAddressPolicy < ApplicationPolicy
|
||||
end
|
||||
|
||||
def verify?
|
||||
if request.params[:email_verification_key].present?
|
||||
record.valid_key?(request.params[:email_verification_key])
|
||||
else
|
||||
record.user_id == user.id
|
||||
end
|
||||
record.user_id == user.id
|
||||
end
|
||||
|
||||
def send_confirmation?
|
||||
|
||||
Reference in New Issue
Block a user