git » sdk » main » tree

[main] / borogove / EncryptionInfo.hx

package borogove;

enum abstract EncryptionStatus(Int) {
	var DecryptionSuccess; // Message was encrypted, and we decrypted it
	var DecryptionFailure; // Message is encrypted, and we failed to decrypt it
}

@:nullSafety(Strict)
class EncryptionInfo {
    public final status:EncryptionStatus;
    public final method:String;
    public final methodName:Null<String>;
    public final reason:Null<String>;
    public final reasonText:Null<String>;

	// List from XEP-0380
	private static final knownEncryptionSchemes:Map<String,String> = [
		"urn:xmpp:otr:0" => "OTR",
		"jabber:x:encrypted" => "Legacy OpenPGP",
		"urn:xmpp:openpgp:0" => "OpenPGP",
		"eu.siacs.conversations.axolotl" => "OMEMO",
		"urn:xmpp:omemo:1" => "OMEMO 1",
		"urn:xmpp:omemo:2" => "OMEMO 2",
    ];

    public function new(status:EncryptionStatus, method:String, ?methodName:String, ?reason:String, ?reasonText:String) {
        this.status = status;
        this.method = method;
        this.methodName = methodName;
        this.reason = reason;
        this.reasonText = reasonText;
    }

    public function toXml():Stanza {
        final el = new Stanza("decryption-status", {
            xmlns: "https://borogove.dev/protocol/sdk",
            encryption: this.method,
            result: status == DecryptionSuccess?"success":"failure",
        });
        if(reason != null) {
            el.textTag("reason", reason);
        }
        if(reasonText != null) {
            el.textTag("text", reasonText);
        }
        return el;
    }

    // Typically used to deduce an EncryptionInfo when none has been provided
    // May return null if the stanza is not recognizably encrypted.
    static public function fromStanza(stanza:Stanza):Null<EncryptionInfo> {
		final emeElement = stanza.getChild("encryption", "urn:xmpp:eme:0");
        // We did not decrypt this stanza, so check for any signs
        // that it was encrypted in the first place...
        var ns = null, name = null;
        if(emeElement != null) {
            ns = emeElement.attr.get("namespace");
            name = emeElement.attr.get("name");
        } else if(stanza.getChild("encrypted", "eu.siacs.conversations.axolotl") != null) {
            // Special handling for OMEMO without EME, just because it is
            // so widely used.
            ns = "eu.siacs.conversations.axolotl";
        }
        if(ns != null) {
            return new EncryptionInfo(
                DecryptionFailure,
                ns??"unknown",
                knownEncryptionSchemes.get(ns)??name??"Unknown encryption",
                "unsupported-encryption",
                "Unsupported encryption method: "+(name??ns)
            );
        }
        return null; // Probably not encrypted
    }
}