Skip to content

feat: Warning about trackers - #864

Open
qutad wants to merge 1 commit into
permissionlesstech:mainfrom
qutad:fix/tracking-link-warnings
Open

feat: Warning about trackers#864
qutad wants to merge 1 commit into
permissionlesstech:mainfrom
qutad:fix/tracking-link-warnings

Conversation

@qutad

@qutad qutad commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Summary

  • detect known tracking query parameters, including Instagram igsh
  • warn before sending tracked links from phone and Wear
  • warn before opening tracked links from chat messages
  • leave URLs unchanged when the user chooses to proceed

Detection

The initial conservative catalog includes:

  • igsh
  • utm_*
  • fbclid
  • gclid
  • dclid
  • msclkid
  • twclid
  • ttclid

Detection inspects exact query parameter names and ignores matching text in paths, fragments, values, and ordinary messages.

Testing

  • ./gradlew testDebugUnitTest lintDebug
  • ./gradlew :app:assembleDebug :wear:assembleDebug
  • manually tested send confirmation with Yes and No
  • manually tested URL-open confirmation with Yes and No
  • manually tested safe URLs without tracking parameters
  • manually tested Wear typing and dictation
  • manually tested tracked notification replies

Screenshots

Sending a link:
Screenshot_20260805-145133

Opening a link:
Screenshot_20260805-145142

Risk

It warns without automatically removing or rewriting URL parameters. So it means it can cause some certain risks

Closes #731

@qutad qutad changed the title Warning about trackers feat: Warning about trackers Aug 5, 2026

@Chessing234 Chessing234 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Nice feature and the detector is careful — I checked the URL regex for catastrophic backtracking and it's fine, each label is anchored by its dot. A few things to sort out first.

The two composers now behave differently. In PrivateChatSheet you added accepted && messageText.text == submittedText before clearing, plus the LaunchedEffect(persistedDraft) sync. In ChatScreen the same onSend was converted to take submittedText but still clears unconditionally on accepted, and has no draft sync. If the guard is needed in one place it's needed in both; if it isn't, it should come out of PrivateChatSheet.

The draft LaunchedEffect eats typed whitespace. setDraft only stores when bounded.isNotBlank(), otherwise it removes the key. So in PrivateChatSheet: type a leading space → setConversationDraft(peerID, " ") → key removed → persistedDraft is ""LaunchedEffect sees "" != " " and overwrites the field. The space is erased as you type it. The same effect can clobber a composer mid-edit when boundDrafts evicts (MAX_DRAFTS = 50, MAX_DRAFT_CHARS_TOTAL = 128_000), and it moves the caret to the end whenever it fires.

This whole draft-observation mechanism is also unrelated to tracking links — it exists only to surface the stashed notification reply — and isn't mentioned in the description. It's a real behaviour change to the private-chat composer and deserves its own PR, or at least its own section in the description.

The notification reply silently becomes a draft. From the user's side they typed a reply and hit send. If POST_NOTIFICATIONS isn't granted the notify() is skipped entirely and there is no other trace — the reply just doesn't send and nothing says so. And showTrackingReplyWarning posts under conversationID.hashCode(), the same id as the DM notification, so the warning replaces the MessagingStyle thread it came from. Is replacing intended? Either way the no-permission path needs a fallback.

The @Synchronized additions are partial. draftFor, setDraft and appendDraft get the annotation, but removeConversation, migrate and loadDrafts all mutate _drafts.value without it, so the races are still there. This also looks unrelated to tracking links — separate PR?

Detection gaps. igshid is Instagram's long-standing share parameter and the test explicitly asserts it is not flagged ("https://example.com/?igshid=value"assertFalse). Was that deliberate? Also missing: wbraid and gbraid (Google's gclid successors, now the common case on iOS traffic), si (YouTube), mc_cid/mc_eid.

Strings. All six are tools:ignore="MissingTranslation" in an app shipping 33 locales, for user-facing security copy. And yes/no are very generic names to claim in the global resource namespace — tracking_link_confirm/tracking_link_cancel would be safer.

Smaller: mergeConversationDrafts uses appendedText.takeLast(maxChars), which truncates a URL from the front — the end you'd want to keep is the host.

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.

Warn user about url tracker such as igsh

2 participants