package e2ee import "fmt" // Mode is the account-wide OMEMO policy (see persistence.Session.OMEMO), // combined with a chat's optional Override and its auto-upgrade sticky // flag (Backend.Enabled) by ShouldEncrypt to decide whether to attempt // outgoing encryption for that chat right now. type Mode int const ( // ModeAuto (the default) only encrypts once a chat has auto-upgraded // (Backend.Enabled), i.e. its peer has already sent this chat an OMEMO // message. This is the original, only behavior before Mode existed. ModeAuto Mode = iota // ModeOn always attempts to encrypt, regardless of whether the peer // has ever shown OMEMO support. If no session can be established, the // send fails outright rather than falling back to plaintext - the // same OMEMOSendFailedBody convention already used at every Encrypt // call site applies, it's just reached unconditionally now instead of // only for already-active chats. Incoming plaintext is still accepted // and processed as usual - this mode only ever affects outgoing. ModeOn // ModeOff never encrypts outgoing content, even for a chat that has // already auto-upgraded - inbound OMEMO messages are still decrypted // normally regardless of this mode (decryption never consults Mode at // all, only the encrypt hooks do). ModeOff ) func (m Mode) String() string { switch m { case ModeOn: return "on" case ModeOff: return "off" default: return "auto" } } // ParseMode maps persistence.Session.OMEMO's stored string to a Mode - an // empty string (an account that predates this field, or never touched it) // is treated the same as "auto", matching Mode's zero value and default. func ParseMode(s string) (Mode, error) { switch s { case "", "auto": return ModeAuto, nil case "on": return ModeOn, nil case "off": return ModeOff, nil default: return ModeAuto, fmt.Errorf("e2ee: unknown mode %q (want on, auto, or off)", s) } } // ShouldEncrypt decides whether owner's outgoing content should be // encrypted right now, combining (in priority order): owner's explicit // per-chat Override, if one has been set; otherwise mode's account-wide // policy, consulting backend's auto-upgrade sticky flag (Enabled) only for // ModeAuto. This is the single place that combination logic lives - every // encrypt hook (SendMessageToGateway, sendMessagesReverse, // updateMessageContent) calls this instead of checking Enabled directly, // so a chat's effective behavior can never drift between call sites. func ShouldEncrypt(backend Backend, owner PeerID, mode Mode) (bool, error) { if override, isSet, err := backend.Override(owner); err != nil { return false, err } else if isSet { return override, nil } switch mode { case ModeOn: return true, nil case ModeOff: return false, nil default: return backend.Enabled(owner) } }