Story audiences (Android): all contacts, only chosen, or all except
Three modes, stored in the vault, applied at post time. 🔴 The audience is enforced by who is SENT the bytes, not by a flag. A story is sealed to each recipient's devices through the ratchet, so somebody outside the list is never sent it - there is no copy on the relay for them to be denied. Every mainstream product holds one server-side copy and decides who is shown it; this cannot work that way even if somebody wanted it to, and that is the feature rather than a limitation. Which also answers "make sure stories are only visible to friends": they already were, structurally. There is no public audience and there cannot be one - a story has to be encrypted to somebody in particular. ⚠️ The saved list is intersected with the live contact list in every branch, including "only chosen". An id left behind after that person was removed as a contact must not resurrect them as a recipient. The screen says what will actually happen - "your next story goes to 3 contacts" - resolved the same way, and refuses a post that would reach nobody rather than silently succeeding at nothing. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
85d6825fdf
commit
780dc50652
@@ -61,6 +61,7 @@ class Vault(private val storage: Storage, private val key: SecretKey) {
|
||||
private const val MY_AVATAR = "my-avatar"
|
||||
private const val OUTBOX = "outbox"
|
||||
private const val CALL_LOG = "call-log"
|
||||
private const val STORY_AUDIENCE = "story-audience"
|
||||
/** Kept because the whole log is re-sealed on every write. */
|
||||
private const val CALL_LOG_MAX = 500
|
||||
|
||||
@@ -554,6 +555,23 @@ class Vault(private val storage: Storage, private val key: SecretKey) {
|
||||
writeJson(CALL_LOG, JSONObject().put("calls", trimmed))
|
||||
}
|
||||
|
||||
/**
|
||||
* Who may see this account's stories.
|
||||
*
|
||||
* 🔴 **Enforced by who receives the bytes, not by a flag.** A story is
|
||||
* sealed to each recipient's devices through the ratchet, so somebody
|
||||
* outside the audience is never sent it at all — there is no copy on the
|
||||
* relay for them to be denied. That is a stronger guarantee than every
|
||||
* mainstream product, where the server holds one copy and decides who is
|
||||
* shown it, and it is worth not weakening later for convenience.
|
||||
*
|
||||
* ⚠️ In the vault. An audience list is a statement about who somebody
|
||||
* trusts, which is exactly the metadata this app exists to keep private.
|
||||
*/
|
||||
fun storyAudience(): JSONObject? = readJson(STORY_AUDIENCE)
|
||||
|
||||
fun saveStoryAudience(audience: JSONObject) = writeJson(STORY_AUDIENCE, audience)
|
||||
|
||||
/** Rewrite a thread wholesale, for restating a message's delivery state. */
|
||||
fun replaceHistory(threadId: String, messages: JSONArray) =
|
||||
writeJson(historyName(threadId), JSONObject().put("messages", messages))
|
||||
|
||||
Reference in New Issue
Block a user