Blocking somebody now cancels their sealed passes too
§21.4 gave a lever to cut off one contact and nothing pulled it. That is the failure this project has been fixing all day in other places — a capability built and left unreachable. Blocking is where it belongs, and the reason is stronger than convenience. The relay CANNOT enforce a block against a sealed sender: the request carries no sender to compare against a block list, and the send route's own comment says so. So blocking stopped the identified path and nothing else, and a blocked person's sealed messages were dropped by the app after decryption rather than refused at the door. Revoking their capabilities is what closes that. The copy changes with it, because "buddies you block can't send you messages" was not true and is the kind of overclaim a safety screen must not make. It now says what blocking does, and names the gap left: the shared key everybody holds is not that person's alone, so it takes replacing to close completely — with the cost of that stated in the same breath rather than in a different screen. The sealed-sender section changes for the same reason. It said replacing the key is "the only way" to cut somebody off, which was true when it was written and is not now. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
79c2734f86
commit
8061f54e96
@@ -855,8 +855,11 @@ fun ColumnScope.AccountScreen(
|
||||
SettingsRow(
|
||||
label = "Sealed sender",
|
||||
description = "Messages you send are addressed to the recipient without naming you. "
|
||||
+ "Replacing your delivery key is the only way to stop someone abusing it — and "
|
||||
+ "it cuts off every contact until you next message them.",
|
||||
+ "Because nothing names the sender, the server cannot block one — so blocking "
|
||||
+ "somebody now also cancels the one-use passes you gave them, which is the part "
|
||||
+ "that can be aimed at a single person. This replaces the shared key instead, "
|
||||
+ "which everybody holds: it is the way to cut off somebody you cannot identify, "
|
||||
+ "and it costs every contact until you next message them.",
|
||||
) {
|
||||
KitChip(text = "New key", selected = false,
|
||||
onClick = model::rotateDeliveryKey, tag = "rotate-delivery-key")
|
||||
|
||||
@@ -1015,6 +1015,24 @@ class MessengerViewModel(app: Application) : AndroidViewModel(app) {
|
||||
val done = withContext(Dispatchers.IO) {
|
||||
runCatching {
|
||||
current.api.setBlocked(userId, blocked)
|
||||
// 🔴 **And take their sealed capabilities with it.** The relay
|
||||
// cannot enforce a block against a sealed sender — the request
|
||||
// carries no sender to compare against a block list, and the
|
||||
// send route says so itself — so without this, blocking stops
|
||||
// the identified path and nothing else, and a blocked person's
|
||||
// sealed messages are dropped by this app after decryption
|
||||
// rather than refused at the door.
|
||||
//
|
||||
// ⚠️ One of two doors, and this shuts one. They keep the shared
|
||||
// delivery key of §14.4, which the relay also cannot attribute,
|
||||
// until it is rotated — and rotating costs every other contact
|
||||
// a redistribution. Best-effort and after the block has landed:
|
||||
// the block is the safety action, and failing it because a
|
||||
// follow-up failed would leave somebody unblocked who believes
|
||||
// otherwise.
|
||||
if (blocked) {
|
||||
runCatching { current.conversations.revokeDeliveryTokens(userId) }
|
||||
}
|
||||
current.api.blocked().toSet() to current.roster()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user