mirror of
https://github.com/Freika/dawarich.git
synced 2026-01-09 08:47:11 -05:00
Introduce iOS authentication flow with JWT token generation
This commit is contained in:
parent
d6a3200632
commit
c0e756d085
5 changed files with 109 additions and 4 deletions
|
|
@ -39,6 +39,21 @@ class ApplicationController < ActionController::Base
|
|||
user_not_authorized
|
||||
end
|
||||
|
||||
def after_sign_in_path_for(resource)
|
||||
payload = { api_key: resource.api_key, exp: 5.minutes.from_now.to_i }
|
||||
|
||||
token = Subscription::EncodeJwtToken.new(
|
||||
payload, ENV['AUTH_JWT_SECRET_KEY']
|
||||
).call
|
||||
|
||||
case request.headers['X-Dawarich-Client']
|
||||
when 'ios'
|
||||
ios_success_path(token:)
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_self_hosted_status
|
||||
|
|
|
|||
14
app/controllers/auth/ios_controller.rb
Normal file
14
app/controllers/auth/ios_controller.rb
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Auth
|
||||
class IosController < ApplicationController
|
||||
def success
|
||||
render json: {
|
||||
success: true,
|
||||
message: 'iOS authentication successful',
|
||||
token: params[:token],
|
||||
redirect_url: root_url
|
||||
}, status: :ok
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -85,6 +85,9 @@ Rails.application.routes.draw do
|
|||
|
||||
root to: 'home#index'
|
||||
|
||||
# iOS mobile auth success endpoint
|
||||
get 'auth/ios/success', to: 'auth/ios#success', as: :ios_success
|
||||
|
||||
if SELF_HOSTED
|
||||
devise_for :users, skip: [:registrations]
|
||||
as :user do
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
{
|
||||
"webcredentials": {
|
||||
"apps": [
|
||||
"2A275P77DQ.app.dawarich.Dawarich"
|
||||
"2A275P77DQ.app.dawarich.Dawarich",
|
||||
"3DJN84WAS8.app.dawarich.Dawarich"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,9 +6,9 @@ RSpec.describe 'Authentication', type: :request do
|
|||
let(:user) { create(:user, password: 'password123') }
|
||||
|
||||
before do
|
||||
stub_request(:get, "https://api.github.com/repos/Freika/dawarich/tags")
|
||||
.with(headers: { 'Accept'=>'*/*', 'Accept-Encoding'=>/.*/,
|
||||
'Host'=>'api.github.com', 'User-Agent'=>/.*/})
|
||||
stub_request(:get, 'https://api.github.com/repos/Freika/dawarich/tags')
|
||||
.with(headers: { 'Accept' => '*/*', 'Accept-Encoding' => /.*/,
|
||||
'Host' => 'api.github.com', 'User-Agent' => /.*/ })
|
||||
.to_return(status: 200, body: '[{"name": "1.0.0"}]', headers: {})
|
||||
end
|
||||
|
||||
|
|
@ -66,4 +66,76 @@ RSpec.describe 'Authentication', type: :request do
|
|||
expect(response).to redirect_to(new_user_session_path)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'Mobile iOS Authentication' do
|
||||
it 'redirects to iOS success path when signing in with iOS client header' do
|
||||
# Sign in with iOS client header
|
||||
sign_in user
|
||||
|
||||
# Mock the after_sign_in_path_for redirect behavior
|
||||
allow_any_instance_of(ApplicationController).to receive(:after_sign_in_path_for).and_return(ios_success_path)
|
||||
|
||||
# Make a request with the iOS client header
|
||||
post user_session_path, params: {
|
||||
user: { email: user.email, password: 'password123' }
|
||||
}, headers: { 'X-Dawarich-Client' => 'ios' }
|
||||
|
||||
# Should redirect to iOS success endpoint after successful login
|
||||
expect(response).to redirect_to(ios_success_path)
|
||||
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 }
|
||||
test_token = Subscription::EncodeJwtToken.new(
|
||||
payload, ENV['AUTH_JWT_SECRET_KEY']
|
||||
).call
|
||||
|
||||
get ios_success_path, params: { token: test_token }
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(response.content_type).to include('application/json')
|
||||
|
||||
json_response = JSON.parse(response.body)
|
||||
expect(json_response['success']).to be true
|
||||
expect(json_response['message']).to eq('iOS authentication successful')
|
||||
expect(json_response['token']).to eq(test_token)
|
||||
expect(json_response['redirect_url']).to eq(root_url)
|
||||
end
|
||||
|
||||
it 'generates JWT token with correct payload for iOS authentication' do
|
||||
# Test JWT token generation directly using the same logic as after_sign_in_path_for
|
||||
payload = { api_key: user.api_key, exp: 5.minutes.from_now.to_i }
|
||||
|
||||
# Create JWT token using the same service
|
||||
token = Subscription::EncodeJwtToken.new(
|
||||
payload, ENV['AUTH_JWT_SECRET_KEY']
|
||||
).call
|
||||
|
||||
expect(token).to be_present
|
||||
|
||||
# Decode the token to verify the payload
|
||||
decoded_payload = JWT.decode(
|
||||
token,
|
||||
ENV['AUTH_JWT_SECRET_KEY'],
|
||||
true,
|
||||
{ algorithm: 'HS256' }
|
||||
).first
|
||||
|
||||
expect(decoded_payload['api_key']).to eq(user.api_key)
|
||||
expect(decoded_payload['exp']).to be_present
|
||||
end
|
||||
|
||||
it 'uses default path for non-iOS clients' do
|
||||
sign_in user
|
||||
|
||||
# Make a request without iOS client header
|
||||
post user_session_path, params: {
|
||||
user: { email: user.email, password: 'password123' }
|
||||
}
|
||||
|
||||
# Should redirect to default path (not iOS success)
|
||||
expect(response).not_to redirect_to(ios_success_path)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
Loading…
Reference in a new issue