Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Track system language #109

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 4 additions & 2 deletions app/controllers/devise_recognisable/sessions_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ def check_for_authentication_token
sign_in_ip: request.location.ip,
sign_in_at: Time.now,
user_agent: request.user_agent,
accept_header: request.headers["HTTP_ACCEPT"]
accept_header: request.headers["HTTP_ACCEPT"],
accept_language: request.headers["Accept-Language"].first
PatMiekina marked this conversation as resolved.
Show resolved Hide resolved
)
redirect_to after_sign_in_path_for(resource)
end
Expand All @@ -69,7 +70,8 @@ def store_recognisable_details
sign_in_ip: request.location.ip,
sign_in_at: Time.now,
user_agent: request.user_agent,
accept_header: request.headers["HTTP_ACCEPT"]
accept_header: request.headers["HTTP_ACCEPT"],
accept_language: request.headers["Accept-Language"]
)
end
end
17 changes: 14 additions & 3 deletions app/lib/devise_recognisable/guard.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ class DeviseRecognisable::Guard
MAX_LEVENSHTEIN_DISTANCE = Rails.env.test? ? 10 : 0

@@required_scores = {
relaxed: 2,
normal: 3,
strict: 4
relaxed: 3,
normal: 4,
strict: 5
}

def self.with(previous_sessions)
Expand Down Expand Up @@ -61,6 +61,9 @@ def calculate_score_for(session)
# Is the request's Accept header different to the previous sign in?
score += 1 if session.accept_header == @request.headers["HTTP_ACCEPT"]

# Is the request's Accept-Language header different to the previous sign in?
score += 1 if session.accept_language == @request.headers["Accept-Language"]

return score
end

Expand Down Expand Up @@ -165,6 +168,14 @@ def failures
}
end

# Is the request's Accept-Language header different to the previous sign in?
unless @closest_match[:session].accept_language == @request.headers["Accept-Language"]
failures[:failures][:accept_language] = {
request_value: @request.headers["Accept-Language"],
session_value: @closest_match[:session].accept_language
}
end

return failures
end

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ class CreateRecognisableSessions < <%= "ActiveRecord::Migration[#{ActiveRecord::
t.<%= ip_column %> :sign_in_ip
t.string :user_agent
t.string :accept_header
t.string :accept_language
t.datetime :sign_in_at
end
add_index :recognisable_sessions, [:recognisable_type, :recognisable_id], :name => 'recognisable_index'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ def change
t.string :sign_in_ip
t.string :user_agent
t.string :accept_header
t.string :accept_language
t.datetime :sign_in_at
end
add_index :recognisable_sessions, [:recognisable_type, :recognisable_id], :name => 'recognisable_index'
Expand Down
1 change: 1 addition & 0 deletions spec/dummy-app/db/schema.rb

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

41 changes: 37 additions & 4 deletions spec/dummy-app/spec/features/sign_in_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,19 @@

let!(:user_agent) { 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36' }
let!(:accept_header) { 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' }
let!(:accept_language) { 'en' }
PatMiekina marked this conversation as resolved.
Show resolved Hide resolved
let!(:recognisable_session_values) {{
recognisable_id: user.id,
recognisable_type: 'User',
user_agent: user_agent,
accept_header: accept_header
accept_header: accept_header,
accept_language: accept_language
}}

before do
Capybara.current_session.driver.header('User-Agent', user_agent)
Capybara.current_session.driver.header('Accept', accept_header)
Capybara.current_session.driver.header('Accept-Language', accept_language)
end

context 'as a user that has no last_sign_in_ip' do
Expand Down Expand Up @@ -169,7 +172,7 @@
:session_value=>new_ip,
:comparison_result=>:complete_mismatch
}},
:score=>2,
:score=>3,
:user_id=>1,
:user_type=>"User"
), "Unrecognised request")
Expand Down Expand Up @@ -224,7 +227,7 @@
:session_value=>new_ip,
:comparison_result=>:complete_mismatch
}},
:score=>2,
:score=>3,
:user_id=>1,
:user_type=>"User"
), "Unrecognised request")
Expand Down Expand Up @@ -297,6 +300,7 @@
context 'from a device with a different Accept header value' do
let!(:recognisable_session) { FactoryBot.create :recognisable_session, recognisable_session_values }
let!(:new_accept_header) { 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8' }


before do
recognisable_session.update!(accept_header: new_accept_header)
Expand All @@ -321,14 +325,43 @@
end
end

context 'from a device with a different Accept-Language header value' do
let!(:recognisable_session) { FactoryBot.create :recognisable_session, recognisable_session_values }
let!(:new_accept_language) { 'fr' }
PatMiekina marked this conversation as resolved.
Show resolved Hide resolved

before do
recognisable_session.update!(accept_header: new_accept_language)
visit '/'
click_link 'Log in'
fill_in 'Email', with: user.email
fill_in 'Password', with: user.password
click_button 'Log in'
end

it 'does not log the user in' do
expect(page).to have_content I18n.t('devise.sessions.send_new_ip_instructions')
expect(page).to_not have_content('Home sweet home')
end

context 'visiting the link in the email' do
it 'logs the user in' do
open_email(user.email, with_subject: I18n.t('devise.mailer.new_ip.subject'))
visit_in_email('Log in')
expect(page).to have_content('Home sweet home')
end
end
end

context 'with multiple different RecognisableSessions' do
let!(:different_user_agent) { 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/605.1.15 (KHTML, like Gecko)' }
let!(:different_accept_header) { 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8' }
let!(:different_accept_language) { 'fr' }
PatMiekina marked this conversation as resolved.
Show resolved Hide resolved
let!(:different_recognisable_session_values) {{
recognisable_id: user.id,
recognisable_type: 'User',
user_agent: different_user_agent,
accept_header: different_accept_header
accept_header: different_accept_header,
accept_language: different_accept_language
}}

before do
Expand Down