Skip to content

Favorites consent, visible mutuality, and honest copy - #1663

Open
jackjackbits wants to merge 4 commits into
fix/system-message-spoofingfrom
feat/favorites-consent
Open

Favorites consent, visible mutuality, and honest copy#1663
jackjackbits wants to merge 4 commits into
fix/system-message-spoofingfrom
feat/favorites-consent

Conversation

@jackjackbits

Copy link
Copy Markdown
Collaborator

Tier-1 batch 5/6. The star read like a private bookmark but behaved like a friend request + identity handshake: it immediately notified the peer and transmitted your durable Nostr key, while the tapper saw nothing — and mutuality (the state that actually gates offline delivery) was invisible at the point of decision. Now: a one-time consent dialog before the first favorite (both star surfaces; /fav as an explicit typed command proceeds without a dialog; acknowledged flag resets on panic wipe); half star until reciprocated with tooltips + VoiceOver labels; FEATURES copy leads with the real mechanism instead of notifications; and geohash block copy says the block is per-channel (identities are derived per-geohash) on both the context-menu and /block paths. 7 new strings + 3 updated values × 30 locales.

🤖 Generated with Claude Code

The star read like a private bookmark but behaved like a friend
request plus an identity handshake: tapping it immediately notified
the peer ("alice favorited you") and transmitted the durable Nostr
public key — while the tapper saw nothing. And the load-bearing state,
mutuality (one-sided favorites do NOT enable offline delivery), was
invisible at the point of decision.

- One-time consent: the first favorite ever asks, naming the person
  and disclosing the notification + key sharing (both star surfaces:
  peer list and DM header). Acknowledged once; reset by panic wipe.
  /fav (an explicit typed command) proceeds without a dialog.
- Mutuality visible where the decision happens: half star until
  reciprocated, filled star when mutual, with tooltips and VoiceOver
  state labels for both. The DM header state now carries
  isMutualFavorite.
- FEATURES copy described favorites as notifications; it now leads
  with the actual mechanism (offline messaging via nostr when mutual).
- Geohash block copy no longer implies a global block: identities are
  derived per-geohash, so the same person appears as someone new in
  other channels — the message says so now (both the context-menu and
  /block paths).

7 new strings + 3 updated values, all 30 locales.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d4d78e85eb

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread bitchat/Views/MeshPeerList.swift Outdated
Comment on lines +186 to +189
if !peer.isFavorite, !FavoriteConsent.isAcknowledged {
pendingFavorite = peer
} else {
onToggleFavorite(peer.peerID)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Apply consent to every favorite action

On a fresh install, choosing “Add favorite” from the row's context menu or VoiceOver custom actions still invokes onToggleFavorite directly at lines 223–224 and 248–249. Those paths therefore notify the peer and disclose the user's durable Nostr key without showing the newly required consent dialog; route all add-favorite actions through the pendingFavorite flow while allowing removals to remain immediate.

Useful? React with 👍 / 👎.

Comment thread bitchat/Views/MeshPeerList.swift Outdated
.contentShape(Rectangle())
}
.buttonStyle(.plain)
.help(peer.isMutualFavorite ? Strings.favoriteMutualTooltip : Strings.favoritePendingTooltip)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Show the pending tooltip only for actual favorites

For every non-favorite peer, both isMutualFavorite and isFavorite are false, so hovering the empty star displays “favorited — offline messaging starts when they favorite you back” even though the user has not favorited that peer. Select an add-favorite tooltip for the unfavorited state, and reserve favoritePendingTooltip for one-sided favorites.

Useful? React with 👍 / 👎.

jackjackbits and others added 2 commits August 11, 2026 10:14
…tooltip

- Codex P1: the context-menu and VoiceOver "add favorite" actions
  called onToggleFavorite directly, bypassing the one-time consent
  dialog and disclosing the nostr key without asking. All add-favorite
  entry points now route through requestFavoriteToggle (consent gate);
  removals stay immediate.
- Codex P2: the empty star showed the "favorited — offline messaging
  starts when they favorite you back" tooltip on peers that weren't
  favorited at all. The pending/mutual copy now applies only once
  isFavorite; an unfavorited star reads "add favorite".

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@jackjackbits

Copy link
Copy Markdown
Collaborator Author

Both Codex findings addressed: every add-favorite entry point (star button, context menu, VoiceOver custom action) now routes through requestFavoriteToggle, which shows the one-time consent dialog before disclosing the nostr key; removals stay immediate. And the empty-star tooltip no longer claims a favorite that doesn't exist — the mutual/pending copy applies only once isFavorite, otherwise it reads "add favorite".

- CommandProcessorTests still asserted the old "blocked … in geohash
  chats" copy that this branch rewrote to the per-channel wording.
- The `mesh_peers.state.favorite` state constant was replaced by the
  mutual/pending pair and left unused — Periphery (now blocking) flagged
  it. Removed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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.

1 participant