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

Max number of devices in new session #1115

Conversation

Evan-M
Copy link
Collaborator

@Evan-M Evan-M commented Mar 19, 2018

Additional refactoring, per discussion in #1109.

See: #1109 (review) and #1109 (comment)

@MaicolBen
Copy link
Collaborator

@Evan-M You need to rebase

 * There was prior discussion around removing this line of code, inside
   lynndylanhurley#990.
   See: lynndylanhurley#990 (comment)

 * While line in question _is_ superfluous, removing it was blocked by a
   bad test.  This test was corrected in the previous commit (9ebc5bd).
 * Previous version featured an `Enumerable#min_by` loop _inside_ a
   `while` loop, resulting in `O(n^2)` complexity.

 * Instead, break things into two separate loops, and skip altogether if
   they aren't even necessary.
@Evan-M Evan-M force-pushed the max_number_of_devices_in_new_session branch from 3b63cfe to 04afcda Compare March 22, 2018 20:43
@Evan-M
Copy link
Collaborator Author

Evan-M commented Mar 22, 2018

@MaicolBen rebased.

@resource.create_new_auth_token
# REVIEW: The following line _should_ be safe to remove;
# the generated token does not get used anywhere.
# @resource.create_new_auth_token
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

update_auth_header should use this, but if you say so, we can remove it

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather confusingly, there are two methods with that name.
the model concern:

def update_auth_header(token, client_id='default')
headers = build_auth_header(token, client_id)
clean_old_tokens
save!
headers
end

and the controller concern:
def update_auth_header
# cannot save object if model has invalid params
return unless defined?(@resource) && @resource && @resource.valid? && @client_id
# Generate new client_id with existing authentication
@client_id = nil unless @used_auth_by_token
if @used_auth_by_token && !DeviseTokenAuth.change_headers_on_each_request
# should not append auth header if @resource related token was
# cleared by sign out in the meantime
return if @resource.reload.tokens[@client_id].nil?
auth_header = @resource.build_auth_header(@token, @client_id)
# update the response header
response.headers.merge!(auth_header)
else
ensure_pristine_resource do
# Lock the user record during any auth_header updates to ensure
# we don't have write contention from multiple threads
@resource.with_lock do
# should not append auth header if @resource related token was
# cleared by sign out in the meantime
return if @used_auth_by_token && @resource.tokens[@client_id].nil?
# determine batch request status after request processing, in case
# another processes has updated it during that processing
@is_batch_request = is_batch_request?(@resource, @client_id)
auth_header = {}
# extend expiration of batch buffer to account for the duration of
# this request
if @is_batch_request
auth_header = @resource.extend_batch_buffer(@token, @client_id)
# Do not return token for batch requests to avoid invalidated
# tokens returned to the client in case of race conditions.
# Use a blank string for the header to still be present and
# being passed in a XHR response in case of
# 304 Not Modified responses.
auth_header[DeviseTokenAuth.headers_names[:"access-token"]] = ' '
auth_header[DeviseTokenAuth.headers_names[:"expiry"]] = ' '
# update Authorization response header with new token
else
auth_header = @resource.create_new_auth_token(@client_id)
end
# update the response header
response.headers.merge!(auth_header)
end # end lock
end # end ensure_pristine_resource
end
end

I'll assume you mean the one in the controller concern (the same file as this change)...

Regardless, I'm not sure I understand what you mean. This is inside a conditional block for the use case of when DeviseTokenAuth.enable_standard_devise_support = true and the user has already authenticated with Devise in the session via Warden. There is no need for an auth token in that case, so why would we create one here?

# to expedite tests! (Default is 10)
DeviseTokenAuth.max_number_of_devices = 5

# @max_devices = DeviseTokenAuth.max_number_of_devices
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove the commented line, or is this documentation?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is cruft and I didn't mean to leave it in the commit! 😆

# Add a new device (and token) ahead of the next iteration
@resource.create_new_auth_token

# refute_equal initial_tokens, @resource.reload.tokens
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why this refute is commented?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I actually meant to remove it. While the test still passes with it uncommented (along with line 423 above), it really doesn't add anything to the test here. We've already asserted that the number of concurrent tokens/devices is correct; if anything the addition of this test will make the test more brittle.

post :create, params: @user_session_params
end

oldest_token, _ = @existing_user.reload.tokens \
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no need for , _

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is purely convention, although I used it incorrectly...

https://github.com/bbatsov/ruby-style-guide#trailing-underscore-variables

It should either be:

oldest_token, = \
  @existing_user.reload.tokens \
    .min_by { |cid, v| v[:expiry] || v["expiry"] } # => [ <"client_id">, {...<token>...} ]

or

oldest_client_id, _oldest_token = \ 
  @existing_user.reload.tokens \
    .min_by { |cid, v| v[:expiry] || v["expiry"] } # => [ <"client_id">, {...<token>...} ]

If you really truly think I should remove the , _ entirely, I will add a comment that an array is returned by #min_by.

On a different note, I've been itching to create an issue to get rubocop setup on this repo, so that stylistic issues like this are a non-issue.

Copy link
Collaborator

@MaicolBen MaicolBen Mar 22, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right, thank you for the long explanation, and if you enable rubocop, there will be tons of issues, that's why we have Code Climate that analyzes only the differences. I will create an issue for it 😄

EDIT: the issue is #1124

@zachfeldman
Copy link
Contributor

Tests pass. Merging away!

@zachfeldman zachfeldman merged commit a9c7ea6 into lynndylanhurley:master Mar 23, 2018
@Evan-M Evan-M deleted the max_number_of_devices_in_new_session branch March 23, 2018 16:53
@Evan-M Evan-M mentioned this pull request Mar 26, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants