1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242
|
# frozen-string-literal: true
module Rodauth
Feature.define(:json, :Json) do
translatable_method :json_not_accepted_error_message, 'Unsupported Accept header. Must accept "application/json" or compatible content type'
translatable_method :json_non_post_error_message, 'non-POST method used in JSON API'
auth_value_method :json_accept_regexp, /(?:(?:\*|\bapplication)\/\*|\bapplication\/(?:vnd\.api\+)?json\b)/i
auth_value_method :json_check_accept?, true
auth_value_method :json_request_content_type_regexp, /\bapplication\/(?:vnd\.api\+)?json\b/i
auth_value_method :json_response_content_type, 'application/json'
auth_value_method :json_response_custom_error_status?, true
auth_value_method :json_response_error_status, 400
auth_value_method :json_response_error_key, "error"
auth_value_method :json_response_field_error_key, "field-error"
auth_value_method :json_response_success_key, "success"
translatable_method :non_json_request_error_message, 'Only JSON format requests are allowed'
auth_value_methods(
:only_json?,
:use_json?,
)
auth_methods(
:json_request?,
:json_response_error?
)
auth_private_methods :json_response_body
def set_field_error(field, message)
return super unless use_json?
json_response[json_response_field_error_key] = [field, message]
end
def set_error_flash(message)
return super unless use_json?
json_response[json_response_error_key] = message
end
def set_redirect_error_flash(message)
return super unless use_json?
json_response[json_response_error_key] = message
end
def set_notice_flash(message)
return super unless use_json?
json_response[json_response_success_key] = message if include_success_messages?
end
def set_notice_now_flash(message)
return super unless use_json?
json_response[json_response_success_key] = message if include_success_messages?
end
def json_request?
return @json_request if defined?(@json_request)
@json_request = request.content_type =~ json_request_content_type_regexp
end
def use_json?
json_request? || only_json?
end
def view(page, title)
return super unless use_json?
return_json_response
end
def json_response_error?
!!json_response[json_response_error_key]
end
private
def check_csrf?
return false if use_json?
super
end
def _set_otp_unlock_info
if use_json?
json_response[:num_successes] = otp_unlock_num_successes
json_response[:required_successes] = otp_unlock_auths_required
json_response[:next_attempt_after] = otp_unlock_next_auth_attempt_after.to_i
end
end
def after_otp_unlock_auth_success
super if defined?(super)
if otp_locked_out?
_set_otp_unlock_info
json_response[:deadline] = otp_unlock_deadline.to_i
end
end
def after_otp_unlock_auth_failure
super if defined?(super)
_set_otp_unlock_info
end
def after_otp_unlock_not_yet_available
super if defined?(super)
_set_otp_unlock_info
end
def before_two_factor_manage_route
super if defined?(super)
if use_json?
json_response[:setup_links] = two_factor_setup_links.sort.map{|_,link| link}
json_response[:remove_links] = two_factor_remove_links.sort.map{|_,link| link}
json_response[json_response_success_key] ||= "" if include_success_messages?
return_json_response
end
end
def before_two_factor_auth_route
super if defined?(super)
if use_json?
json_response[:auth_links] = two_factor_auth_links.sort.map{|_,link| link}
json_response[json_response_success_key] ||= "" if include_success_messages?
return_json_response
end
end
def before_view_recovery_codes
super if defined?(super)
if use_json?
json_response[:codes] = recovery_codes
json_response[json_response_success_key] ||= "" if include_success_messages?
end
end
def before_webauthn_setup_route
super if defined?(super)
if use_json? && !param_or_nil(webauthn_setup_param)
cred = new_webauthn_credential
json_response[webauthn_setup_param] = cred.as_json
json_response[webauthn_setup_challenge_param] = cred.challenge
json_response[webauthn_setup_challenge_hmac_param] = compute_hmac(cred.challenge)
end
end
def before_webauthn_auth_route
super if defined?(super)
if use_json? && !param_or_nil(webauthn_auth_param)
cred = webauthn_credential_options_for_get
json_response[webauthn_auth_param] = cred.as_json
json_response[webauthn_auth_challenge_param] = cred.challenge
json_response[webauthn_auth_challenge_hmac_param] = compute_hmac(cred.challenge)
end
end
def before_webauthn_login_route
super if defined?(super)
if use_json? && !param_or_nil(webauthn_auth_param) && webauthn_login_options?
cred = webauthn_credential_options_for_get
json_response[webauthn_auth_param] = cred.as_json
json_response[webauthn_auth_challenge_param] = cred.challenge
json_response[webauthn_auth_challenge_hmac_param] = compute_hmac(cred.challenge)
end
end
def before_webauthn_remove_route
super if defined?(super)
if use_json? && !param_or_nil(webauthn_remove_param)
json_response[webauthn_remove_param] = account_webauthn_usage
end
end
def before_otp_setup_route
super if defined?(super)
if use_json? && otp_keys_use_hmac? && !param_or_nil(otp_setup_raw_param)
_otp_tmp_key(otp_new_secret)
json_response[otp_setup_param] = otp_user_key
json_response[otp_setup_raw_param] = otp_key
end
end
def before_rodauth
if json_request?
if json_check_accept? && (accept = request.env['HTTP_ACCEPT']) && accept !~ json_accept_regexp
response.status = 406
json_response[json_response_error_key] = json_not_accepted_error_message
_return_json_response
end
unless request.post?
response.status = 405
set_response_header('allow', 'POST')
json_response[json_response_error_key] = json_non_post_error_message
return_json_response
end
elsif only_json?
response.status = json_response_error_status
return_response non_json_request_error_message
end
super
end
def redirect(_)
return super unless use_json?
return_json_response
end
def return_json_response
_return_json_response
end
def _return_json_response
response.status ||= json_response_error_status if json_response_error?
response.headers[convert_response_header_key('content-type')] ||= json_response_content_type
return_response _json_response_body(json_response)
end
def include_success_messages?
!json_response_success_key.nil?
end
def _json_response_body(hash)
request.send(:convert_to_json, hash)
end
def json_response
@json_response ||= {}
end
def set_redirect_error_status(status)
if use_json? && json_response_custom_error_status?
response.status = status
end
end
def set_response_error_status(status)
if use_json? && !json_response_custom_error_status?
status = json_response_error_status
end
super
end
end
end
|