Conversation
Co-authored-by: luis.dee16 <luis.dee16@gmail.com>
WalkthroughThe VintedAPI service's anti-detection mechanisms have been refactored: proxy rotation shifted from round-robin indexing to probabilistic random selection with scheduled rotation every 3-5 requests; request timing now includes asymmetric jitter with an 80% delay probability; error handling (401/404/429/403) now triggers immediate proxy rotation and explicit cookie refresh; and session management aligned with desktop behavior. Changes
Sequence DiagramsequenceDiagram
participant Client
participant VintedAPI
participant ProxySelector
participant Session
Client->>VintedAPI: request()
VintedAPI->>VintedAPI: increment requestCount
VintedAPI->>VintedAPI: shouldRotateProxy()?
alt Rotation Needed
rect rgb(200, 220, 255)
VintedAPI->>ProxySelector: getRandomProxy()
ProxySelector-->>VintedAPI: new proxy
VintedAPI->>VintedAPI: rotateProxySession()
VintedAPI->>Session: create with new proxy
VintedAPI->>VintedAPI: apply post-rotation delay
VintedAPI->>VintedAPI: reset nextProxyRotationAt
end
end
VintedAPI->>VintedAPI: computeDelay (time-based)
VintedAPI->>VintedAPI: 80% chance: add asymmetric jitter
VintedAPI->>VintedAPI: apply delay
VintedAPI->>Session: executeRequest()
Session-->>VintedAPI: response
alt Error (401/404/429)
rect rgb(255, 200, 200)
VintedAPI->>VintedAPI: setCookies() [clear + refresh]
VintedAPI->>ProxySelector: getRandomProxy()
VintedAPI->>VintedAPI: rotateProxySession()
VintedAPI->>VintedAPI: retry with new proxy
end
end
alt Error (403)
rect rgb(255, 220, 180)
VintedAPI->>Session: reset/recreate session
VintedAPI->>VintedAPI: setCookies()
VintedAPI->>VintedAPI: rotateProxySession()
end
end
VintedAPI-->>Client: result
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes
Possibly related PRs
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (4)
iOSApp/VintedNotifications/Services/VintedAPI.swift (4)
39-42: Request timing / jitter behavior looks coherent, with a small clarity tweak possibleThe min/max delay plus asymmetric jitter and 80% delay probability work together as intended: first request after app launch effectively has no delay (due to
lastRequestTime == 0), then subsequent calls are spaced with human‑like gaps usingtimeSinceLastRequest. Logic is sound.If you want this to be more explicit/less sentinel‑based, you could initialize
lastRequestTime = Date().timeIntervalSince1970ininit()and adjust the comment onminRequestDelayto clarify the “first request is usually immediate” behavior. Optional only.Also applies to: 431-451
296-304: Proxy rotation schedule is reasonable; consider thread‑safety and rotation bookkeepingThe new rotation scheme (global
requestCount,nextProxyRotationAt, random working proxy, rotation every 3–5 requests and immediately at some error paths) matches the PR goal and is much closer to “desktop‑like” behavior. The code paths all terminate correctly and won’t over‑rotate whenworkingProxiesis empty.Two improvements to consider:
Thread‑safety of counters and session
Ifsearchcan be called concurrently from multiple tasks/threads,requestCount,nextProxyRotationAt,workingProxies, andsessionmutations are unsynchronized. A lightweight fix would be to isolateVintedAPIon a single actor/queue (e.g. mark the class@MainActorif it’s only used from UI, or refactor into anactor), so rotations and counts are serialized.Avoid “rotations” that keep the same proxy
rotateProxySession()may pick the same proxy viarandomElement(). If you want rotations to always switch IP when more than one proxy is available, you could remember the last proxy string and resample when there is more than one proxy andnewProxy == lastProxy.Both are refinements; current behavior is functionally correct.
Also applies to: 319-325, 328-344, 556-567
403-411: Cookie clearing + refresh behavior is correct but could better sync withlastCookieRefreshClearing all cookies before
setCookies()and reusing that in 401/404/403 handlers is consistent with the stated “match desktop” intent and should help recover from bad/expired cookie state.Two minor follow‑ups to consider:
Align
lastCookieRefreshwith manual refreshes
Calls tosetCookies()in the 401/404 and 403 branches don’t updatelastCookieRefresh, soensureFreshCookies()will still think the last refresh time is the older value. That’s harmless but can cause extra HEAD refreshes earlier than needed. UpdatinglastCookieRefreshinsidesetCookies()(on success) would keep the bookkeeping accurate.Scope of cookie clearing
BecausecreateSessionusesHTTPCookieStorage.shared,setCookies()currently wipes all cookies, not just Vinted‑related ones. If the app ever talks to other domains, you may want to filter deletes to cookies whose domain matchescurrentLocale/vinted.instead of clearing the entire store.Both are optimization/behavioral nits rather than blockers.
Also applies to: 608-615, 643-652
621-631: 429/403 handling logic matches the goal; consider slightly stronger backoff on repeated 403s
- 429: Backoff with jitter plus an immediate proxy rotation when proxies are available is a solid strategy and should noticeably reduce rate‑limit loops.
- 403: On first 403 per
searchcall, you resettriedto 0, refresh cookies, rotate (or recreate) the session, and back off before retrying, which aligns with the “reset session + new proxy” desktop behavior.One refinement to think about: subsequent 403s after
newSessionis set only log and immediately proceed to the next loop iteration, so you’ll send up tomaxRetries−1 extra 403s with no extra delay or rotation. You might want to treat “second 403 after reset” as a strong signal and either:
- bail out early (return empty), or
- reuse the generic backoff behavior (similar to
default) and possibly rotate again.Not a correctness bug, but could further reduce detection pressure on hard‑blocked sessions.
Also applies to: 637-656
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
iOSApp/VintedNotifications/Services/VintedAPI.swift(9 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
iOSApp/VintedNotifications/Services/VintedAPI.swift (1)
iOSApp/VintedNotifications/Services/LogService.swift (2)
info(80-82)warning(84-86)
🔇 Additional comments (2)
iOSApp/VintedNotifications/Services/VintedAPI.swift (2)
377-382: Accept‑Language override guards are sensibleOnly randomizing
Accept-Languagewhen it’s missing fromdefaultHeadersListis a good call; this lets persisted/desktop‑aligned headers win, while still giving you variability by default.No issues here from a correctness standpoint.
686-687: Good call adding human‑like delay togetUserCountryReusing
addRequestDelay()here keeps user‑info lookups aligned with the rest of your traffic pattern, which should help keep the profile consistent with desktop behavior.No issues spotted.
Improve iOS app's undetectability by aligning its network request patterns and error handling with the desktop app.
The iOS app was experiencing significantly higher rates of 403 errors and rate limits compared to the desktop app. This PR implements several changes to mimic the desktop app's network behavior, including more frequent and randomized proxy rotation, human-like request timing, consistent header ordering, and robust session/cookie management upon encountering authentication or rate-limiting errors, thereby reducing detection.
Summary by CodeRabbit
✏️ Tip: You can customize this high-level summary in your review settings.