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

fix: prevent registering device with empty identifier existing BQ tasks #392

Merged
merged 2 commits into from Oct 11, 2023

Conversation

levibostian
Copy link
Member

@levibostian levibostian commented Oct 6, 2023

Quick bug fix for customer to prevent /api/v1/customers//devices/ (empty profile identifier) requests from being made.

@levibostian levibostian requested a review from a team October 6, 2023 16:12
@github-actions
Copy link

github-actions bot commented Oct 6, 2023

Sample app builds 📱

Below you will find the list of the latest versions of the sample apps. It's recommended to always download the latest builds of the sample apps to accurately test the pull request.


  • CocoaPods-FCM: levi/empty-identifier-registerdevice (1697029485)
  • APN-UIKit: levi/empty-identifier-registerdevice (1697029448)

Comment on lines +95 to +97
// If a HTTP request is made to register device token with an empty identifier, either (1) a 302 will occur or (2) a "devices" profile will be created in a CIO workspace. Neither are ideal.
// The SDK has logic to prevent *new* register device tasks being added to the BQ if identifier is empty but existing tasks in the BQ will still occur.
// This logic is to clear those tasks from the BQ.
Copy link
Member Author

Choose a reason for hiding this comment

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

Hopefully, this comment explains why this PR was made and why this change is needed.

If you are thinking, "BQ tasks expire after 3 days. These tasks should be deleted?". For registering push tokens, these tasks never expire.

This group start requirement can be removed because Track API will return a 200 if you try to delete a device token for a device that does not exist. However, you cannot modify a BQ task once it's in the BQ. Therefore, this bug would not be fixed by making group start nil for register device token.

@levibostian levibostian marked this pull request as draft October 6, 2023 16:18
@levibostian levibostian removed the request for review from a team October 6, 2023 16:19
@codecov
Copy link

codecov bot commented Oct 6, 2023

Codecov Report

Merging #392 (fe3ea42) into main (b0f309f) will decrease coverage by 0.55%.
The diff coverage is 100.00%.

@@            Coverage Diff             @@
##             main     #392      +/-   ##
==========================================
- Coverage   60.07%   59.52%   -0.55%     
==========================================
  Files         119      119              
  Lines        4556     4566      +10     
==========================================
- Hits         2737     2718      -19     
- Misses       1819     1848      +29     
Files Coverage Δ
Sources/Common/Background Queue/QueueRunner.swift 69.07% <100.00%> (+2.40%) ⬆️
Sources/Common/Extensions/ResultExtensions.swift 100.00% <100.00%> (ø)

... and 5 files with indirect coverage changes

@levibostian levibostian marked this pull request as ready for review October 6, 2023 16:34
@levibostian levibostian requested a review from a team October 6, 2023 16:34
// The SDK has logic to prevent *new* register device tasks being added to the BQ if identifier is empty but existing tasks in the BQ will still occur.
// This logic is to clear those tasks from the BQ.
if taskData.profileIdentifier.isBlankOrEmpty() {
return onComplete(.success(()))
Copy link
Contributor

Choose a reason for hiding this comment

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

is there a reason, we return success for this task, which will eventually also delete instead of just deleting?

The register device token is blocked by the Identify task, so it should run in the first place, but in case if identify task has been run and was faulty e.g. empty identifier then why not just delete this task?

Copy link
Member Author

Choose a reason for hiding this comment

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

is there a reason, we return success for this task, which will eventually also delete instead of just deleting?

You are correct. The reason for returning success is to tell the BQ to delete the task.

but in case if identify task has been run and was faulty e.g. empty identifier

I am not sure if it would be faulty? The problem that we have been experiencing is HTTP requests with empty identifier ID for this register device endpoint. I don't recall the SDK having issues with identifying a profile with the API with an empty identifier. Therefore, I don't think we need to modify identify profile BQ tasks?


Are you suggesting that we modify the solution to a SDK migration where we iterate the BQ and delete tasks from it?

Assuming that is what your comment is suggesting...From my experience building BQs, I have learned that BQ code gets complex quickly when you begin modifying tasks that are already in the BQ. An approach I have found to be less complex is to do the modify logic when that BQ task is executing. Therfore, that's where this solution comes from. When the BQ task runs, tell the BQ to delete it.

Copy link
Contributor

Choose a reason for hiding this comment

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

I was suggesting, something like this?

if taskData.profileIdentifier.isBlankOrEmpty()
queuStore.delete(taskID)
return

Copy link
Member Author

Choose a reason for hiding this comment

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

Ah, I see.

I would not recommend using the code inside of this function since the queue runner will then fail when it attempts to delete the task from the queue storage. By returning success here, we are telling the queue storage to delete it for us.

A 1 time SDK data migration would be the approach that I would suggest as an alternative solution to this PR. I hesitate because of my suggestion to not modify BQ tasks once they are in the BQ and prefer solutions like this. But, technically, a migration would work here.


// MARK: registerPushToken

func test_registerPushToken_givenIdentifierEmpty_expectHttpRequestNotMade_expectBQDeletesTask() {
Copy link
Contributor

Choose a reason for hiding this comment

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

can we have a test for the failure of the result as well?

Copy link
Member Author

Choose a reason for hiding this comment

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

I assume you're suggesting adding a test for when the endpoint returns back a 401, 500, or some other HTTP failure?

Assuming that is what you're saying, the logic for this endpoint is identical to all other endpoints in how to handle HTTP failures. Therfore, I find a test like that to be not as valuable because it's duplicated logic for all endpoints.

Copy link
Contributor

Choose a reason for hiding this comment

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

The Result class seems to be added for this PR, and codecov also points out that the failure variable isn't tested for this class. So even if the logic might be similar for other endpoints, we still would have not tested this newly added class.

Copy link
Member Author

Choose a reason for hiding this comment

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

Ah, good call-out.

I added a function to Swift's built-in Result class. Looking at the diff, I do see that I didn't name the file correctly and I did not write tests for the added function.

I just pushed a commit taking care of those things. Thanks for bringing that up.

Copy link
Contributor

@Shahroz16 Shahroz16 left a comment

Choose a reason for hiding this comment

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

Approving as these aren't blockers but rather different approaches.


// MARK: registerPushToken

func test_registerPushToken_givenIdentifierEmpty_expectHttpRequestNotMade_expectBQDeletesTask() {
Copy link
Contributor

Choose a reason for hiding this comment

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

The Result class seems to be added for this PR, and codecov also points out that the failure variable isn't tested for this class. So even if the logic might be similar for other endpoints, we still would have not tested this newly added class.

// The SDK has logic to prevent *new* register device tasks being added to the BQ if identifier is empty but existing tasks in the BQ will still occur.
// This logic is to clear those tasks from the BQ.
if taskData.profileIdentifier.isBlankOrEmpty() {
return onComplete(.success(()))
Copy link
Contributor

Choose a reason for hiding this comment

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

I was suggesting, something like this?

if taskData.profileIdentifier.isBlankOrEmpty()
queuStore.delete(taskID)
return

@levibostian levibostian merged commit 867619f into main Oct 11, 2023
10 checks passed
@levibostian levibostian deleted the levi/empty-identifier-registerdevice branch October 11, 2023 13:24
github-actions bot pushed a commit that referenced this pull request Oct 11, 2023
## [2.8.3](2.8.2...2.8.3) (2023-10-11)

### Bug Fixes

* prevent registering device with empty identifier existing BQ tasks ([#392](#392)) ([867619f](867619f))
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.

None yet

2 participants