Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d4b66f0f authored by shamim-emon's avatar shamim-emon
Browse files

refactor: port AutocryptGossipHeaderParser from java to kotlin

parent a895754a
Loading
Loading
Loading
Loading
+50 −75
Original line number Diff line number Diff line
package com.fsck.k9.autocrypt;
package com.fsck.k9.autocrypt

import androidx.annotation.VisibleForTesting
import com.fsck.k9.mail.Part
import com.fsck.k9.mail.internet.MimeUtility
import java.util.Collections
import net.thunderbird.core.logging.legacy.Log
import okio.ByteString.Companion.decodeBase64

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
internal object AutocryptGossipHeaderParser {

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;

import com.fsck.k9.mail.Part;
import com.fsck.k9.mail.internet.MimeUtility;
import okio.ByteString;
import net.thunderbird.core.logging.legacy.Log;


class AutocryptGossipHeaderParser {
    private static final AutocryptGossipHeaderParser INSTANCE = new AutocryptGossipHeaderParser();


    public static AutocryptGossipHeaderParser getInstance() {
        return INSTANCE;
    fun getAllAutocryptGossipHeaders(part: Part): List<AutocryptGossipHeader> {
        val headers = part.getHeader(AutocryptGossipHeader.AUTOCRYPT_GOSSIP_HEADER)
        val autocryptHeaders = parseAllAutocryptGossipHeaders(headers)
        return Collections.unmodifiableList(autocryptHeaders)
    }

    private AutocryptGossipHeaderParser() { }


    List<AutocryptGossipHeader> getAllAutocryptGossipHeaders(Part part) {
        String[] headers = part.getHeader(AutocryptGossipHeader.AUTOCRYPT_GOSSIP_HEADER);
        List<AutocryptGossipHeader> autocryptHeaders = parseAllAutocryptGossipHeaders(headers);

        return Collections.unmodifiableList(autocryptHeaders);
    }

    @Nullable
    @VisibleForTesting
    AutocryptGossipHeader parseAutocryptGossipHeader(String headerValue) {
        Map<String,String> parameters = MimeUtility.getAllHeaderParameters(headerValue);

        String type = parameters.remove(AutocryptHeader.AUTOCRYPT_PARAM_TYPE);
        if (type != null && !type.equals(AutocryptHeader.AUTOCRYPT_TYPE_1)) {
            Log.e("autocrypt: unsupported type parameter %s", type);
            return null;
    fun parseAutocryptGossipHeader(headerValue: String): AutocryptGossipHeader? {
        val parameters = MimeUtility.getAllHeaderParameters(headerValue).toMutableMap()

        val type = parameters.remove(AutocryptHeader.AUTOCRYPT_PARAM_TYPE)
        val base64KeyData = parameters.remove(AutocryptHeader.AUTOCRYPT_PARAM_KEY_DATA)
        val addr = parameters.remove(AutocryptHeader.AUTOCRYPT_PARAM_ADDR)
        val decodedKey = base64KeyData?.decodeBase64()

        return when {
            type != null && type != AutocryptHeader.AUTOCRYPT_TYPE_1 -> {
                Log.e("autocrypt: unsupported type parameter %s", type)
                null
            }

        String base64KeyData = parameters.remove(AutocryptHeader.AUTOCRYPT_PARAM_KEY_DATA);
        if (base64KeyData == null) {
            Log.e("autocrypt: missing key parameter");
            return null;
            base64KeyData == null -> {
                Log.e("autocrypt: missing key parameter")
                null
            }

        ByteString byteString = ByteString.decodeBase64(base64KeyData);
        if (byteString == null) {
            Log.e("autocrypt: error parsing base64 data");
            return null;
            decodedKey == null -> {
                Log.e("autocrypt: error parsing base64 data")
                null
            }

        String addr = parameters.remove(AutocryptHeader.AUTOCRYPT_PARAM_ADDR);
        if (addr == null) {
            Log.e("autocrypt: no to header!");
            return null;
            addr == null -> {
                Log.e("autocrypt: no to header!")
                null
            }

        if (hasCriticalParameters(parameters)) {
            return null;
            hasCriticalParameters(parameters) -> {
                null
            }

        return new AutocryptGossipHeader(addr, byteString.toByteArray());
            else -> {
                AutocryptGossipHeader(addr, decodedKey.toByteArray())
            }

    private boolean hasCriticalParameters(Map<String, String> parameters) {
        for (String parameterName : parameters.keySet()) {
            if (parameterName != null && !parameterName.startsWith("_")) {
                return true;
        }
    }
        return false;

    private fun hasCriticalParameters(parameters: Map<String, String>): Boolean {
        return parameters.keys.any { !it.startsWith("_") }
    }

    @NonNull
    private List<AutocryptGossipHeader> parseAllAutocryptGossipHeaders(String[] headers) {
        ArrayList<AutocryptGossipHeader> autocryptHeaders = new ArrayList<>();
        for (String header : headers) {
            AutocryptGossipHeader autocryptHeader = parseAutocryptGossipHeader(header);
            if (autocryptHeader == null) {
                Log.e("Encountered malformed autocrypt-gossip header - skipping!");
                continue;
    private fun parseAllAutocryptGossipHeaders(headers: Array<String>): List<AutocryptGossipHeader> {
        return headers.mapNotNull { header ->
            parseAutocryptGossipHeader(header) ?: run {
                Log.e("Encountered malformed autocrypt-gossip header - skipping!")
                null
            }
            autocryptHeaders.add(autocryptHeader);
        }
        return autocryptHeaders;
    }
}
+2 −2
Original line number Diff line number Diff line
@@ -25,8 +25,8 @@ public class AutocryptOperations {


    public static AutocryptOperations getInstance() {
        AutocryptHeaderParser autocryptHeaderParser = AutocryptHeaderParser.getInstance();
        AutocryptGossipHeaderParser autocryptGossipHeaderParser = AutocryptGossipHeaderParser.getInstance();
        AutocryptHeaderParser autocryptHeaderParser = AutocryptHeaderParser.Companion.getInstance();
        AutocryptGossipHeaderParser autocryptGossipHeaderParser = AutocryptGossipHeaderParser.INSTANCE;
        return new AutocryptOperations(autocryptHeaderParser, autocryptGossipHeaderParser);
    }