Repository navigation
Conversation
…re-instant-2330 # Conflicts: # lib/features/profile/data/profile_parser.dart
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
A subscription that is valid renders as Expired on every import. The value is not garbage and the
panel is not lying about the plan — the client simply feeds a number that is not an absolute
timestamp into
DateTime.fromMillisecondsSinceEpoch, lands in 1970, and the threeremainingText()implementations in
profile_tile.dartpaint it red._parseSubscriptionInfospecial-cases exactly one non-instant value,expire == 0, and treatseverything else as a UNIX timestamp in seconds. Panels in the wild also send a negative sentinel
for "never expires" and a relative duration (days/hours) instead of an absolute instant. Both fall
straight through into the 1970 branch:
expiresentDateTime7(7 days)-1(never)<unix seconds>Root cause
lib/features/profile/data/profile_parser.dart,_parseSubscriptionInfo:SubscriptionInfo.isExpiredisexpire <= DateTime.now()(profile_entity.dart:60), so any valuebelow "now" is reported as expired. The
== 0guard is the only thing standing between a duration anda 1970 date, and it does not cover
-1or a small duration.Fix
Validate that
expirecan actually be an absolute instant before trusting it; anything that cannot istreated as "never expires", which is the same conclusion the client already reaches for
0:<= 0— covers the negative sentinels panels use for unlimited.< 1_000_000_000(2001-09-09) — a relative value in seconds/days, not an instant.> 253_402_300_799(9999-12-31) — would overflow the millisecond arithmetic.The same pass also stops a
subscription-userinfovalue with a stray;from throwingRangeErrorinside the map comprehension.v.split('=').secondon a segment that has no=(atrailing
;, or;;) throws, and becauseparse()runs insideEither.tryCatch(..., ProfileFailure.unexpected)that discarded the entire profile — a malformedoptional header failing the whole import. Segments are now filtered to those that actually contain
=, and the value is read with.lastso a value containing=is not truncated.Testing
Three cases added to
test/features/profile/data/profile_parser_test.dart, matching the existingheader-map style in that file:
expire=7is treated as unlimited andisExpiredis false (was: red Expired).;no longer discards the profile (was:RangeError→ProfileFailure).Verified against a standalone harness that extracts the parser body out of this repository's
profile_parser.dart(rather than a hand-copied duplicate), renames only the two privateidentifiers so it can be called from
main(), and renders through the sameisExpired/ratio/remainingrules the tile uses. 21 checks, run againstorigin/mainand against this branch:The last row matters: a timestamp that really is in the past still reports expired, so the fix does
not paper over genuine expiry.
total=0still maps to the unlimited-traffic sentinel, and the twocases that were already
nullbefore this change (missingexpirekey, capitalised keys) areunchanged.
This is ad-hoc verification, not the project's test suite. I did try to run the real thing: Flutter
3.47.5 is available here,
flutter pub getsucceeded, butbuild_runner— which generates the.freezed.dart/.g.dartfiles this package needs (none are checked in) — produced nothing afterfour minutes while the disk went from 97% to 99%, so I stopped it rather than risk the disk for a
green run. The three cases added to
test/features/profile/data/profile_parser_test.dartthereforehave not been executed by me or by CI. Running
flutter test test/features/profile/data/profile_parser_test.dartbefore merge would close that gap.I could not read the reporter's actual response headers (the subscription is behind a paid login), so
the exact form v2sx.com sends is inferred from the WHMCS v2ray modules that emit this header. If the
panel does send a proper absolute timestamp and something else is responsible, that would be worth a
follow-up with the raw header attached — the parsing above is defensive and does not change the
behaviour for well-formed input.
#2330