Skip to content

[#108] Resolve "disappearing messages"

aguestuser requested to merge 108-disappearing-messages into master

Context

Provides channel-wide enforced disappearing messages, as specified in the #Behavior section of #108 (closed).

Additionally, it refactors how we handle updated safety numbers to accomodate a new api for safety number changes introduced in upstream changes to signald. Note: we had to incorporate those changes into this MR because there were upstream bugs in how disappearing message expiry times were set, and to pull in the fix for that, we had to also pull in the new API for safety number changes. Fortunately, the new API is a lot simpler, which allowed us to clean up the retrusting code quite a bit. (Notably: we get the new fingerprint directly in the error message, and as such, no longer have to query the trust store for new/untrusted fingerprints in order to figure out which fingerprint to trust.)

As a side effect of noticing that signal will produce rate limit errors if you try to trust the same phone number's new safety number more than 2 times in ~10 minutes, i added a notification function that sends a signal message to all the signup channel admins if this ever happens. I don't anticipate anyone will be reinstalling Signal 3 or more times in less than 10 minutes, but if they do, they will become completely locked out of signalboost in a way that we cannot fix (because we will never see the safety number change error with the new fingerprint -- we will always see the rate limit error before the useful error arrives). This seems upsetting enough that it is a situation we would want to know about and try to manually fix and/or communicate about personally if it's the case.

I anticipate that we might have a slightly nicer workaround for this very rare failure mode after making the upstream patch described in #180 (closed) .

Changes

migrations

includes breaking-change migrations that @team-friendo devs should run after merging this MR

dependency updates

Update the release of signald we depend on in docker/signald.dockerfile to incorporate changes to expiring message behavior and safety number change handling, including 2 upstream MRs we made to make this ticket work:

for disappearing messages:

  • add an expiryTime field (with default value of 1 week) to the channels table

  • add detectUpdatableExpiryTime and upateExpiryTime to dispatcher.run.dispatch

  • detect looks for expirty time on incoming messages that doesn't match what's stored in the channel's db record, and calls update if it finds one.

  • update acts differently depending on who changed the expiry time

    • if the change was made by an admin, it writes the new expiry time to the db and propogates it to all signal threads between the channel phone number and its admins/subscribers
    • if the change was made by a subscriber (or ranod) it reverts the timer in the sender/channel thread to whatever the admins had set it to be in the channels table, does not store the new time, and sends an explanation/sorry message to the sender
  • add setExpiryTimeForNewUsers to dispatcher.messenger.handleCommandResult

    • this sets the disappearing message timer just after every command that a user might use to join the channel (JOIN, ACCEPT, ADD, INVITE) so that nobody can join without observing the pre-existing disappearing message timer
    • it sets the timer after the first message, so that users will still have the welcome message on their phone for later reference on how to use signalbost
  • add a call to setExpiration into handling signup messages so that these messages (which include new admin phone numbers) will always be scrubbed from the phones of signalboost instance maintainers who receive them

for safety number changes

  • add a deauthorizations table (with corresponding model and repository modules). its job is to track any outstanding deauahtorizations for a given admin on a given channel, along with what the newly not-trusted fingerprint is
  • add detectUpdatableFingerprint and updateFingerprint to dispatcher.run.dispatch
    • detect looks for an untrusted fingerprint error message from signald and if it finds one, returns an UpdatableFingerprint struct that wraps the channel and member phone number, the new fingerprint for the member and the original message that failed to send because of the fingerprint change (so that the message can be resent). a detected UpdatAbleFingerprint causes update to be called
    • update acts differently for subscribers and admins
      • for subscribers, it automatically retrusts the subscribers' fingerprint and resends the message
      • for admins, it calls safetyNumbers.deauthorize, which creates a deauthorization record (tracking the fingerprint we want to retrust if other admins decide to retrust the person) and notifies other admins that the untrusted person has been booted from the channel
  • modify execute.addAdmin to first look for a pending deauthorization for anyone that another admin wants to add
    • if it finds an existing deauth record, it trusts the fingerprint that is stored in it, deletes the deauth record, then proceeds to add the admin as normal
  • modify signal.trust to leverage the fact that we know fingerprints ahead of time to send a trust message right away without bothering to query for the fingerprint via get_identities. in fact: delete all the code related to get_identities queries since we don't need it anymore and it was confusing!

for rate limit errors:

  • add detectRateLimitError and notifyRateLimit error to dispatcher.run.dispatch
    • detect matches on a signald error message that says anything about 413 or rate limit and calls update if it finds one
    • update sends a message to all signalboost instance maintainers including the phone numbers of the channel and member phone number for whom the rate limit error occured (but not the contents of the message that failed to send)
  • i imagine we can remove this if we wind up not getting it a lot. including it out of an abundance of caution
Edited by aguestuser

Merge request reports