Store client header in session to persist across redirects

This commit is contained in:
Eugene Burmakin 2025-09-21 13:51:26 +02:00
parent 5347232376
commit 20c2bc34cd
2 changed files with 36 additions and 8 deletions

View file

@ -5,7 +5,7 @@ class ApplicationController < ActionController::Base
rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized
before_action :unread_notifications, :set_self_hosted_status
before_action :unread_notifications, :set_self_hosted_status, :store_client_header
protected
@ -40,14 +40,17 @@ class ApplicationController < ActionController::Base
end
def after_sign_in_path_for(resource)
payload = { api_key: resource.api_key, exp: 5.minutes.from_now.to_i }
# Check both current request header and stored session value
client_type = request.headers['X-Dawarich-Client'] || session[:dawarich_client]
token = Subscription::EncodeJwtToken.new(
payload, ENV['AUTH_JWT_SECRET_KEY']
).call
case request.headers['X-Dawarich-Client']
case client_type
when 'ios'
payload = { api_key: resource.api_key, exp: 5.minutes.from_now.to_i }
token = Subscription::EncodeJwtToken.new(
payload, ENV['AUTH_JWT_SECRET_KEY']
).call
ios_success_path(token:)
else
super
@ -60,6 +63,12 @@ class ApplicationController < ActionController::Base
@self_hosted = DawarichSettings.self_hosted?
end
def store_client_header
return unless request.headers['X-Dawarich-Client']
session[:dawarich_client] = request.headers['X-Dawarich-Client']
end
def user_not_authorized
redirect_back fallback_location: root_path,
alert: 'You are not authorized to perform this action.',

View file

@ -72,7 +72,10 @@ RSpec.describe 'Authentication', type: :request do
# Make a login request with the iOS client header (user NOT pre-signed in)
post user_session_path, params: {
user: { email: user.email, password: 'password123' }
}, headers: { 'X-Dawarich-Client' => 'ios' }
}, headers: {
'X-Dawarich-Client' => 'ios',
'Accept' => 'text/html'
}
# Should redirect to iOS success endpoint after successful login
# The redirect will include a token parameter generated by after_sign_in_path_for
@ -80,6 +83,22 @@ RSpec.describe 'Authentication', type: :request do
expect(response.location).to include('token=')
end
it 'does not redirect to iOS success path when using turbo_stream format' do
# This test demonstrates the issue: when iOS app sends turbo_stream format,
# it doesn't get the iOS-specific redirect behavior
post user_session_path, params: {
user: { email: user.email, password: 'password123' }
}, headers: {
'X-Dawarich-Client' => 'ios',
'Accept' => 'text/vnd.turbo-stream.html'
}
# With turbo_stream format, it doesn't redirect at all (no location header)
# This demonstrates why iOS authentication fails when using turbo_stream
expect(response.location).to be_nil
expect(response.status).to eq(200) # Returns turbo_stream response instead of redirect
end
it 'returns JSON response with JWT token for iOS success endpoint' do
# Generate a test JWT token using the same service as the controller
payload = { api_key: user.api_key, exp: 5.minutes.from_now.to_i }