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

Enforce limit on number of devices per user #35515

Open
wants to merge 8 commits into
base: master
Choose a base branch
from

Conversation

gherceg
Copy link
Contributor

@gherceg gherceg commented Dec 12, 2024

Product Description

Technical Summary

https://dimagi.atlassian.net/browse/SAAS-16355

This returns a 403 if a user is attempting to restore from a new device id after exceeding the device limit. If they have used the device within the last 24 hours, they will be allowed to use it even if the device limit is exceeded.

The investigation done in this ticket highlighted that the distribution of device counts per user is mostly made up of 5 or below (taken from one random day):

1: 20301
2-5: 2624
6-10: 144
11-50: 74
Over 50: 4

It seems reasonable to set a very conservative device limit to start since the user experience when hitting this error isn't going to be great until the mobile team is able to handle this error specifically.

Feature Flag

Safety Assurance

Safety story

Automated test coverage

QA Plan

Rollback instructions

  • This PR can be reverted after deploy with no further considerations

Labels & Review

  • Risk label is set correctly
  • The set of people pinged as reviewers is appropriate for the level of risk of the change

@gherceg gherceg force-pushed the gh/devices-per-user branch from 53dc172 to 6d87fb4 Compare December 12, 2024 20:22
Admins can trigger restores from HQ without a device_id
@gherceg gherceg force-pushed the gh/devices-per-user branch from c164e3a to 2af1f45 Compare December 12, 2024 21:24
@gherceg gherceg changed the title [WIP] Enforce limit on number of devices per user Enforce limit on number of devices per user Dec 12, 2024
@gherceg gherceg marked this pull request as ready for review December 12, 2024 22:03
Copy link
Contributor

@snopoke snopoke left a comment

Choose a reason for hiding this comment

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

Thanks for this @gherceg. Do you have a sense whether blocking the restore is the best option or whether we should also block any other endpoints like phone_keys or app_install? I think we can't block app install because it's unauthenticated right?

Is the logic for blocking sync that you really use a new device until you've done an initial sync?

@@ -0,0 +1 @@
DEVICES_PER_USER = 100
Copy link
Contributor

Choose a reason for hiding this comment

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

How about making this a setting to that it can be changed without a code deploy and 3rd parties can configure their own limits.

On the topic of 3rd parties, this change probably warrants a changelog entry.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah we had talked about potentially creating a new SQL model to update values like this quickly, but settings seems perfectly fine for now, and definitely better than a constant. Moved to settings in 93e48ec.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

And agreed on the changelog entry!

corehq/apps/ota/tests/test_utils.py Outdated Show resolved Hide resolved
if device_id.startswith("WebAppsLogin"):
return True

end_time = datetime.now()
Copy link
Contributor

Choose a reason for hiding this comment

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

Should this use utcnow() or whatever the acceptable equivalent is these days?

Aside: I find it annoying that utcnow() is deprecated. It's so easy to remember.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah right. I believe it is now datetime.now(timezone.utc) based on these docs. See f90aa81

Copy link
Contributor

Choose a reason for hiding this comment

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

In Django world you can also use django.utils.timezone.now()



def can_login_on_device(user_id, device_id):
if not device_id or device_id.startswith("WebAppsLogin"):
Copy link
Contributor

Choose a reason for hiding this comment

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

Can device ids be set by the submitting device? In other words, would it be possible for someone to make their mobile device(s) ids start with WebAppsLogin or be empty and exempt themselves from the limit? Do we care?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah good question that I do not know the answer to off the top of my head. I can dig more into this one and get back to you.

Copy link
Contributor

@snopoke snopoke Dec 19, 2024

Choose a reason for hiding this comment

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

The official CC Mobile app doesn't allow changing the device ID. Forms submitted by other means can set it to whatever they want. This makes me wonder if we need to account for API submitted forms (ignoring them)?

@gherceg
Copy link
Contributor Author

gherceg commented Dec 17, 2024

Do you have a sense whether blocking the restore is the best option or whether we should also block any other endpoints like phone_keys or app_install? I think we can't block app install because it's unauthenticated right?

Is the logic for blocking sync that you really use a new device until you've done an initial sync?

I don't have a great sense of what the best option to enforce this is, and a large part of my reasoning here is simply because it is what I'm most familiar with. I'm definitely open to alternative approaches.

My logic was going off of the assumption that a restore is an inevitable part of both preparing a new device for use as well as existing devices syncing with the server. However, if my understanding is correct, this doesn't actually limit the number of devices that can submit forms against HQ from a specific user which seems like a fundamental issue.

Does it seem fair to say that what we really want to do is limit all mobile endpoints to X devices per user per day?

@snopoke
Copy link
Contributor

snopoke commented Dec 19, 2024

Do you have a sense whether blocking the restore is the best option or whether we should also block any other endpoints like phone_keys or app_install? I think we can't block app install because it's unauthenticated right?
Is the logic for blocking sync that you really use a new device until you've done an initial sync?

I don't have a great sense of what the best option to enforce this is, and a large part of my reasoning here is simply because it is what I'm most familiar with. I'm definitely open to alternative approaches.

My logic was going off of the assumption that a restore is an inevitable part of both preparing a new device for use as well as existing devices syncing with the server. However, if my understanding is correct, this doesn't actually limit the number of devices that can submit forms against HQ from a specific user which seems like a fundamental issue.

Does it seem fair to say that what we really want to do is limit all mobile endpoints to X devices per user per day?

Keeping it at restores for now seems fine to me.

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