diff --git a/lib/build.gradle b/lib/build.gradle index d221cbca..b4f20fa1 100644 --- a/lib/build.gradle +++ b/lib/build.gradle @@ -67,6 +67,9 @@ dependencies { implementation 'androidx.security:security-crypto:1.1.0-alpha03' implementation "org.bouncycastle:bcpkix-jdk15on:1.67" + // Serialization + implementation 'org.mongodb:bson:4.2.2' + // Testing testImplementation 'junit:junit:4.13.2' testImplementation 'androidx.test:core:1.3.0' diff --git a/lib/src/main/java/tech/relaycorp/relaydroid/endpoint/ThirdPartyEndpoint.kt b/lib/src/main/java/tech/relaycorp/relaydroid/endpoint/ThirdPartyEndpoint.kt index aa233f17..d80e740c 100644 --- a/lib/src/main/java/tech/relaycorp/relaydroid/endpoint/ThirdPartyEndpoint.kt +++ b/lib/src/main/java/tech/relaycorp/relaydroid/endpoint/ThirdPartyEndpoint.kt @@ -1,14 +1,17 @@ package tech.relaycorp.relaydroid.endpoint -import org.json.JSONObject +import org.bson.BSONException +import org.bson.BsonBinary +import org.bson.BsonBinaryReader +import org.bson.BsonBinaryWriter +import org.bson.io.BasicOutputBuffer import tech.relaycorp.relaydroid.Storage -import tech.relaycorp.relaydroid.common.decodeBase64 -import tech.relaycorp.relaydroid.common.encodeBase64 import tech.relaycorp.relaydroid.storage.persistence.PersistenceException import tech.relaycorp.relaynet.RelaynetException import tech.relaycorp.relaynet.wrappers.x509.Certificate import tech.relaycorp.relaynet.wrappers.x509.CertificateException -import java.nio.charset.Charset +import java.nio.ByteBuffer + public sealed class ThirdPartyEndpoint( public val thirdPartyAddress: String, // Private address @@ -109,28 +112,40 @@ public class PublicThirdPartyEndpoint( internal data class StoredData( val publicAddress: String, val identityCertificate: Certificate ) { - fun serialize() = - JSONObject().also { json -> - json.put("public_address", publicAddress) - json.put( - "identity_certificate", - identityCertificate.serialize().encodeBase64() - ) + @Throws(PersistenceException::class) + fun serialize(): ByteArray { + try { + val output = BasicOutputBuffer() + BsonBinaryWriter(output).use { + it.writeStartDocument() + it.writeString("public_address", publicAddress) + it.writeBinaryData("identity_certificate", BsonBinary(identityCertificate.serialize())) + it.writeEndDocument() + } + return output.toByteArray() + } catch (exp: BSONException) { + throw PersistenceException("Could not serialize PublicThirdPartyEndpoint", exp) } - .toString() - .toByteArray(Charset.forName("UTF-8")) + } companion object { - fun deserialize(byteArray: ByteArray): StoredData { - val jsonString = byteArray.toString(Charset.forName("UTF-8")) - val json = JSONObject(jsonString) - return StoredData( - json.getString("public_address"), - Certificate.deserialize( - json.getString("identity_certificate").decodeBase64() - ) - ) - } + @Throws(PersistenceException::class) + fun deserialize(byteArray: ByteArray): StoredData = + try { + BsonBinaryReader(ByteBuffer.wrap(byteArray)).use { reader -> + reader.readStartDocument() + StoredData( + reader.readString("public_address"), + Certificate.deserialize( + reader.readBinaryData("identity_certificate").data + ) + ).also { + reader.readEndDocument() + } + } + } catch (exp: BSONException) { + throw PersistenceException("Could not deserialize PublicThirdPartyEndpoint", exp) + } } } } diff --git a/lib/src/test/java/tech/relaycorp/relaydroid/endpoint/PublicThirdPartyEndpointTest.kt b/lib/src/test/java/tech/relaycorp/relaydroid/endpoint/PublicThirdPartyEndpointTest.kt index bfba8303..a016a3a5 100644 --- a/lib/src/test/java/tech/relaycorp/relaydroid/endpoint/PublicThirdPartyEndpointTest.kt +++ b/lib/src/test/java/tech/relaycorp/relaydroid/endpoint/PublicThirdPartyEndpointTest.kt @@ -8,6 +8,8 @@ import org.junit.Assert.assertEquals import org.junit.Assert.assertNull import org.junit.Before import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner import tech.relaycorp.relaydroid.Relaynet import tech.relaycorp.relaydroid.storage.StorageImpl import tech.relaycorp.relaydroid.storage.mockStorage @@ -77,4 +79,17 @@ internal class PublicThirdPartyEndpointTest { PublicThirdPartyEndpoint.import("example.org", cert) } + + @Test + fun storedDataSerialization() { + val publicAddress = "example.org" + val certificate = PDACertPath.PUBLIC_GW + + val dataSerialized = + PublicThirdPartyEndpoint.StoredData(publicAddress, certificate).serialize() + val data = PublicThirdPartyEndpoint.StoredData.deserialize(dataSerialized) + + assertEquals(publicAddress, data.publicAddress) + assertEquals(certificate, data.identityCertificate) + } }