From ceead4815bcda8868e2776ba530a3901402197b2 Mon Sep 17 00:00:00 2001 From: Tom Hacohen Date: Tue, 28 Jan 2020 17:01:21 +0200 Subject: [PATCH] Move to the external journalmanager module (moved the code there) --- app/build.gradle | 5 +- .../etesync/syncadapter/AccountSettings.kt | 2 +- .../syncadapter/journalmanager/BaseManager.kt | 116 -------- .../syncadapter/journalmanager/Constants.kt | 8 - .../syncadapter/journalmanager/Crypto.kt | 262 ----------------- .../syncadapter/journalmanager/Exceptions.kt | 141 ---------- .../journalmanager/JournalAuthenticator.kt | 61 ---- .../journalmanager/JournalEntryManager.kt | 116 -------- .../journalmanager/JournalManager.kt | 220 --------------- .../journalmanager/UserInfoManager.kt | 148 ---------- .../journalmanager/util/ByteUtil.java | 248 ---------------- .../syncadapter/model/CollectionInfo.kt | 6 +- .../etesync/syncadapter/model/SyncEntry.kt | 4 +- .../syncadapter/CalendarSyncManager.kt | 4 +- .../syncadapter/ContactsSyncManager.kt | 4 +- .../syncadapter/SyncAdapterService.kt | 8 +- .../syncadapter/syncadapter/SyncManager.kt | 6 +- .../syncadapter/SyncNotification.kt | 2 +- .../syncadapter/TasksSyncManager.kt | 2 +- .../etesync/syncadapter/ui/AccountActivity.kt | 6 +- .../syncadapter/ui/AddMemberFragment.kt | 6 +- .../ui/ChangeEncryptionPasswordActivity.kt | 8 +- .../ui/CollectionMembersListFragment.kt | 2 +- .../ui/CreateCollectionFragment.kt | 6 +- .../syncadapter/ui/DebugInfoActivity.kt | 2 +- .../ui/DeleteCollectionFragment.kt | 6 +- .../syncadapter/ui/ExceptionInfoFragment.kt | 3 +- .../syncadapter/ui/RemoveMemberFragment.kt | 2 +- .../ui/setup/BaseConfigurationFinder.kt | 6 +- .../ui/setup/SetupEncryptionFragment.kt | 6 +- .../ui/setup/SetupUserInfoFragment.kt | 6 +- .../journalmanager/AuthenticatorTest.kt | 55 ---- .../journalmanager/EncryptionTest.kt | 90 ------ .../syncadapter/journalmanager/Helpers.kt | 8 - .../syncadapter/journalmanager/ServiceTest.kt | 265 ------------------ 35 files changed, 48 insertions(+), 1792 deletions(-) delete mode 100644 app/src/main/java/com/etesync/syncadapter/journalmanager/BaseManager.kt delete mode 100644 app/src/main/java/com/etesync/syncadapter/journalmanager/Constants.kt delete mode 100644 app/src/main/java/com/etesync/syncadapter/journalmanager/Crypto.kt delete mode 100644 app/src/main/java/com/etesync/syncadapter/journalmanager/Exceptions.kt delete mode 100644 app/src/main/java/com/etesync/syncadapter/journalmanager/JournalAuthenticator.kt delete mode 100644 app/src/main/java/com/etesync/syncadapter/journalmanager/JournalEntryManager.kt delete mode 100644 app/src/main/java/com/etesync/syncadapter/journalmanager/JournalManager.kt delete mode 100644 app/src/main/java/com/etesync/syncadapter/journalmanager/UserInfoManager.kt delete mode 100644 app/src/main/java/com/etesync/syncadapter/journalmanager/util/ByteUtil.java delete mode 100644 app/src/test/java/com/etesync/syncadapter/journalmanager/AuthenticatorTest.kt delete mode 100644 app/src/test/java/com/etesync/syncadapter/journalmanager/EncryptionTest.kt delete mode 100644 app/src/test/java/com/etesync/syncadapter/journalmanager/Helpers.kt delete mode 100644 app/src/test/java/com/etesync/syncadapter/journalmanager/ServiceTest.kt diff --git a/app/build.gradle b/app/build.gradle index 19feaeb7..ae0feab5 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -133,6 +133,7 @@ dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" implementation "org.jetbrains.anko:anko-commons:0.10.4" + implementation "com.etesync:journalmanager:1.0.1" def acraVersion = '5.3.0' implementation "ch.acra:acra-mail:$acraVersion" @@ -157,10 +158,6 @@ dependencies { kapt "io.requery:requery-processor:$requeryVersion" implementation 'com.google.code.findbugs:jsr305:3.0.2' - def spongyCastleVersion = "1.54.0.0" - implementation "com.madgag.spongycastle:core:$spongyCastleVersion" - implementation "com.madgag.spongycastle:prov:$spongyCastleVersion" - def okhttp3Version = "3.12.1" implementation "com.squareup.okhttp3:logging-interceptor:$okhttp3Version" diff --git a/app/src/main/java/com/etesync/syncadapter/AccountSettings.kt b/app/src/main/java/com/etesync/syncadapter/AccountSettings.kt index 408d9589..6e58ee0d 100644 --- a/app/src/main/java/com/etesync/syncadapter/AccountSettings.kt +++ b/app/src/main/java/com/etesync/syncadapter/AccountSettings.kt @@ -19,7 +19,7 @@ import android.os.Build import android.os.Bundle import at.bitfire.vcard4android.ContactsStorageException import at.bitfire.vcard4android.GroupMethod -import com.etesync.syncadapter.journalmanager.Crypto +import com.etesync.journalmanager.Crypto import com.etesync.syncadapter.log.Logger import com.etesync.syncadapter.utils.Base64 import java.net.URI diff --git a/app/src/main/java/com/etesync/syncadapter/journalmanager/BaseManager.kt b/app/src/main/java/com/etesync/syncadapter/journalmanager/BaseManager.kt deleted file mode 100644 index b36d8b6b..00000000 --- a/app/src/main/java/com/etesync/syncadapter/journalmanager/BaseManager.kt +++ /dev/null @@ -1,116 +0,0 @@ -package com.etesync.syncadapter.journalmanager - -import com.etesync.syncadapter.GsonHelper -import com.etesync.syncadapter.log.Logger -import okhttp3.* -import java.io.ByteArrayOutputStream -import java.io.IOException -import java.net.HttpURLConnection -import java.util.logging.Level -import javax.net.ssl.SSLHandshakeException -import javax.net.ssl.SSLProtocolException - -abstract class BaseManager { - - protected var remote: HttpUrl? = null - protected var client: OkHttpClient? = null - - @Throws(Exceptions.HttpException::class) - fun newCall(request: Request): Response { - val response: Response - try { - Logger.log.fine("Making request for ${request.url()}") - response = client!!.newCall(request).execute() - } catch (e: IOException) { - if (e is SSLProtocolException) { - throw e - } else if (e is SSLHandshakeException && e.cause is SSLProtocolException) { - throw e - } - Logger.log.log(Level.SEVERE, "Failed while connecting to server", e) - throw Exceptions.ServiceUnavailableException("[" + e.javaClass.name + "] " + e.localizedMessage) - } - - if (!response.isSuccessful) { - val apiError = if (response.header("Content-Type", "application/json")!!.startsWith("application/json")) - GsonHelper.gson.fromJson(response.body()!!.charStream(), ApiError::class.java) - else - ApiError(code="got_html", detail="Got HTML while expecting JSON") - - - when (response.code()) { - HttpURLConnection.HTTP_BAD_GATEWAY -> throw Exceptions.BadGatewayException(response, "Bad gateway: most likely a server restart") - HttpURLConnection.HTTP_UNAVAILABLE -> throw Exceptions.ServiceUnavailableException(response, "Service unavailable") - HttpURLConnection.HTTP_UNAUTHORIZED -> throw Exceptions.UnauthorizedException(response, "Unauthorized auth token") - HttpURLConnection.HTTP_CONFLICT -> throw Exceptions.ConflictException(response, "Http conflict") - HttpURLConnection.HTTP_FORBIDDEN -> { - if (apiError.code == "service_inactive") { - throw Exceptions.UserInactiveException(response, apiError.detail) - } else if (apiError.code == "associate_not_allowed") { - throw Exceptions.AssociateNotAllowedException(response, apiError.detail) - } else if (apiError.code == "journal_owner_inactive") { - throw Exceptions.ReadOnlyException(response, apiError.detail) - } - } - }// Fall through. We want to always throw when unsuccessful. - - throw Exceptions.HttpException(response, apiError.detail) - } - - return response - } - - internal class ApiError( - var detail: String? = null, - var code: String? = null - ) - - open class Base { - var content: ByteArray? = null - var uid: String? = null - - fun getContent(crypto: Crypto.CryptoManager): String { - return String(crypto.decrypt(content!!)!!) - } - - fun setContent(crypto: Crypto.CryptoManager, content: String) { - this.content = crypto.encrypt(content.toByteArray()) - } - - fun calculateHmac(crypto: Crypto.CryptoManager, uuid: String?): ByteArray { - val hashContent = ByteArrayOutputStream() - - try { - if (uuid != null) { - hashContent.write(uuid.toByteArray()) - } - - hashContent.write(content!!) - } catch (e: IOException) { - // Can never happen, but just in case, return a bad hmac - return "DEADBEEFDEADBEEFDEADBEEFDEADBEEF".toByteArray() - } - - return crypto.hmac(hashContent.toByteArray()) - } - - protected constructor() {} - - constructor(crypto: Crypto.CryptoManager, content: String, uid: String) { - setContent(crypto, content) - this.uid = uid - } - - override fun toString(): String { - return javaClass.simpleName + "<" + uid + ">" - } - - internal open fun toJson(): String { - return GsonHelper.gson.toJson(this, javaClass) - } - } - - companion object { - val JSON = MediaType.parse("application/json; charset=utf-8") - } -} diff --git a/app/src/main/java/com/etesync/syncadapter/journalmanager/Constants.kt b/app/src/main/java/com/etesync/syncadapter/journalmanager/Constants.kt deleted file mode 100644 index 7222c3ad..00000000 --- a/app/src/main/java/com/etesync/syncadapter/journalmanager/Constants.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.etesync.syncadapter.journalmanager - -class Constants { - companion object { - @JvmField - val CURRENT_VERSION = 2 - } -} diff --git a/app/src/main/java/com/etesync/syncadapter/journalmanager/Crypto.kt b/app/src/main/java/com/etesync/syncadapter/journalmanager/Crypto.kt deleted file mode 100644 index 31917949..00000000 --- a/app/src/main/java/com/etesync/syncadapter/journalmanager/Crypto.kt +++ /dev/null @@ -1,262 +0,0 @@ -package com.etesync.syncadapter.journalmanager - -import com.etesync.syncadapter.journalmanager.util.ByteUtil -import com.etesync.syncadapter.log.Logger -import com.etesync.syncadapter.utils.Base64 -import org.apache.commons.lang3.ArrayUtils -import org.spongycastle.crypto.AsymmetricBlockCipher -import org.spongycastle.crypto.BufferedBlockCipher -import org.spongycastle.crypto.InvalidCipherTextException -import org.spongycastle.crypto.digests.SHA256Digest -import org.spongycastle.crypto.encodings.OAEPEncoding -import org.spongycastle.crypto.engines.AESEngine -import org.spongycastle.crypto.engines.RSAEngine -import org.spongycastle.crypto.generators.RSAKeyPairGenerator -import org.spongycastle.crypto.generators.SCrypt -import org.spongycastle.crypto.macs.HMac -import org.spongycastle.crypto.modes.CBCBlockCipher -import org.spongycastle.crypto.paddings.PKCS7Padding -import org.spongycastle.crypto.paddings.PaddedBufferedBlockCipher -import org.spongycastle.crypto.params.KeyParameter -import org.spongycastle.crypto.params.ParametersWithIV -import org.spongycastle.crypto.params.RSAKeyGenerationParameters -import org.spongycastle.crypto.util.PrivateKeyFactory -import org.spongycastle.crypto.util.PrivateKeyInfoFactory -import org.spongycastle.crypto.util.PublicKeyFactory -import org.spongycastle.crypto.util.SubjectPublicKeyInfoFactory -import org.spongycastle.util.encoders.Hex -import java.io.IOException -import java.io.Serializable -import java.math.BigInteger -import java.security.SecureRandom -import java.util.* - -object Crypto { - @JvmStatic - fun deriveKey(salt: String, password: String): String { - val keySize = 190 - - return Base64.encodeToString(SCrypt.generate(password.toByteArray(), salt.toByteArray(), 16384, 8, 1, keySize), Base64.NO_WRAP) - } - - @JvmStatic - fun generateKeyPair(): AsymmetricKeyPair? { - val keyPairGenerator = RSAKeyPairGenerator() - keyPairGenerator.init(RSAKeyGenerationParameters(BigInteger.valueOf(65537), SecureRandom(), 3072, 160)) - val keyPair = keyPairGenerator.generateKeyPair() - try { - val privateKeyInfo = PrivateKeyInfoFactory.createPrivateKeyInfo(keyPair.private) - val publicKeyInfo = SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(keyPair.public) - return AsymmetricKeyPair(privateKeyInfo.encoded, publicKeyInfo.encoded) - } catch (e: IOException) { - e.printStackTrace() - } - - return null - } - - class AsymmetricKeyPair(val privateKey: ByteArray, val publicKey: ByteArray) : Serializable - - class AsymmetricCryptoManager(private val keyPair: AsymmetricKeyPair) { - - fun encrypt(pubkey: ByteArray, content: ByteArray?): ByteArray? { - var cipher: AsymmetricBlockCipher = RSAEngine() - cipher = OAEPEncoding(cipher) - try { - cipher.init(true, PublicKeyFactory.createKey(pubkey)) - return cipher.processBlock(content, 0, content!!.size) - } catch (e: IOException) { - e.printStackTrace() - } catch (e: InvalidCipherTextException) { - e.printStackTrace() - Logger.log.severe("Invalid ciphertext: " + Base64.encodeToString(content, Base64.NO_WRAP)) - } - - return null - } - - fun decrypt(cipherText: ByteArray): ByteArray? { - var cipher: AsymmetricBlockCipher = RSAEngine() - cipher = OAEPEncoding(cipher) - try { - cipher.init(false, PrivateKeyFactory.createKey(keyPair.privateKey)) - return cipher.processBlock(cipherText, 0, cipherText.size) - } catch (e: IOException) { - e.printStackTrace() - } catch (e: InvalidCipherTextException) { - e.printStackTrace() - Logger.log.severe("Invalid ciphertext: " + Base64.encodeToString(cipherText, Base64.NO_WRAP)) - } - - return null - } - - companion object { - - fun getKeyFingerprint(pubkey: ByteArray): ByteArray { - return sha256(pubkey) - } - - @JvmStatic - fun getPrettyKeyFingerprint(pubkey: ByteArray): String { - val fingerprint = Crypto.AsymmetricCryptoManager.getKeyFingerprint(pubkey) - val spacing = " " - val ret = getEncodedChunk(fingerprint, 0) + spacing + - getEncodedChunk(fingerprint, 4) + spacing + - getEncodedChunk(fingerprint, 8) + spacing + - getEncodedChunk(fingerprint, 12) + "\n" + - getEncodedChunk(fingerprint, 16) + spacing + - getEncodedChunk(fingerprint, 20) + spacing + - getEncodedChunk(fingerprint, 24) + spacing + - getEncodedChunk(fingerprint, 28) - return ret.trim { it <= ' ' } - } - - private fun getEncodedChunk(hash: ByteArray, offset: Int): String { - val chunk = ByteUtil.byteArray4ToLong(hash, offset) % 100000 - return String.format(Locale.getDefault(), "%05d", chunk) - } - } - } - - class CryptoManager { - val version: Byte - private var cipherKey: ByteArray? = null - private var hmacKey: ByteArray? = null - private var derivedKey: ByteArray? = null - - private val random: SecureRandom - get() = SecureRandom() - - private fun setDerivedKey(derivedKey: ByteArray?) { - cipherKey = hmac256("aes".toByteArray(), derivedKey) - hmacKey = hmac256("hmac".toByteArray(), derivedKey) - } - - constructor(version: Int, keyPair: AsymmetricKeyPair, encryptedKey: ByteArray) { - val cryptoManager = Crypto.AsymmetricCryptoManager(keyPair) - derivedKey = cryptoManager.decrypt(encryptedKey) - - this.version = version.toByte() - setDerivedKey(derivedKey) - } - - @Throws(Exceptions.IntegrityException::class, Exceptions.VersionTooNewException::class) - constructor(version: Int, keyBase64: String, salt: String) { - if (version > java.lang.Byte.MAX_VALUE) { - throw Exceptions.IntegrityException("Version is out of range.") - } else if (version > Constants.CURRENT_VERSION) { - throw Exceptions.VersionTooNewException("Version to new: " + version.toString()) - } else if (version == 1) { - derivedKey = Base64.decode(keyBase64, Base64.NO_WRAP) - } else { - derivedKey = hmac256(salt.toByteArray(), Base64.decode(keyBase64, Base64.NO_WRAP)) - } - - this.version = version.toByte() - setDerivedKey(derivedKey) - } - - private fun getCipher(iv: ByteArray, encrypt: Boolean): BufferedBlockCipher { - val key = KeyParameter(cipherKey!!) - val params = ParametersWithIV(key, iv) - - val padding = PKCS7Padding() - val cipher = PaddedBufferedBlockCipher( - CBCBlockCipher(AESEngine()), padding) - cipher.reset() - cipher.init(encrypt, params) - - return cipher - } - - fun decrypt(_data: ByteArray): ByteArray? { - val iv = Arrays.copyOfRange(_data, 0, blockSize) - val data = Arrays.copyOfRange(_data, blockSize, _data.size) - - val cipher = getCipher(iv, false) - - val buf = ByteArray(cipher.getOutputSize(data.size)) - var len = cipher.processBytes(data, 0, data.size, buf, 0) - try { - len += cipher.doFinal(buf, len) - } catch (e: InvalidCipherTextException) { - e.printStackTrace() - Logger.log.severe("Invalid ciphertext: " + Base64.encodeToString(_data, Base64.NO_WRAP)) - return null - } - - // remove padding - val out = ByteArray(len) - System.arraycopy(buf, 0, out, 0, len) - - return out - } - - fun encrypt(data: ByteArray): ByteArray? { - val iv = ByteArray(blockSize) - random.nextBytes(iv) - - val cipher = getCipher(iv, true) - - val buf = ByteArray(cipher.getOutputSize(data.size) + blockSize) - System.arraycopy(iv, 0, buf, 0, iv.size) - val len = iv.size + cipher.processBytes(data, 0, data.size, buf, iv.size) - try { - cipher.doFinal(buf, len) - } catch (e: InvalidCipherTextException) { - Logger.log.severe("Invalid ciphertext: " + Base64.encodeToString(data, Base64.NO_WRAP)) - e.printStackTrace() - return null - } - - return buf - } - - fun hmac(data: ByteArray): ByteArray { - return if (version.toInt() == 1) { - hmac256(hmacKey, data) - } else { - // Starting from version 2 we hmac the version too. - hmac256(hmacKey, ArrayUtils.add(data, version)) - } - } - - fun getEncryptedKey(keyPair: AsymmetricKeyPair, publicKey: ByteArray): ByteArray? { - val cryptoManager = AsymmetricCryptoManager(keyPair) - return cryptoManager.encrypt(publicKey, derivedKey) - } - - companion object { - val HMAC_SIZE = 256 / 8 // hmac256 in bytes - - private val blockSize = 16 // AES's block size in bytes - - private fun hmac256(keyByte: ByteArray?, data: ByteArray?): ByteArray { - val hmac = HMac(SHA256Digest()) - val key = KeyParameter(keyByte!!) - val ret = ByteArray(hmac.macSize) - hmac.init(key) - hmac.update(data, 0, data!!.size) - hmac.doFinal(ret, 0) - return ret - } - } - } - - internal fun sha256(base: String): String { - return toHex(sha256(base.toByteArray())) - } - - private fun sha256(base: ByteArray): ByteArray { - val digest = SHA256Digest() - digest.update(base, 0, base.size) - val ret = ByteArray(digest.digestSize) - digest.doFinal(ret, 0) - return ret - } - - internal fun toHex(bytes: ByteArray): String { - return Hex.toHexString(bytes).toLowerCase() - } -} diff --git a/app/src/main/java/com/etesync/syncadapter/journalmanager/Exceptions.kt b/app/src/main/java/com/etesync/syncadapter/journalmanager/Exceptions.kt deleted file mode 100644 index c4901251..00000000 --- a/app/src/main/java/com/etesync/syncadapter/journalmanager/Exceptions.kt +++ /dev/null @@ -1,141 +0,0 @@ -package com.etesync.syncadapter.journalmanager - -import at.bitfire.cert4android.Constants -import okhttp3.Response -import okio.Buffer -import java.io.IOException -import java.io.Serializable -import java.security.GeneralSecurityException - -class Exceptions { - class AssociateNotAllowedException(response: Response, message: String?) : HttpException(response, message) - - class ConflictException(response: Response, message: String?) : IgnorableHttpException(response, message ?: "Conflict exception") - - class ReadOnlyException(response: Response, message: String?) : HttpException(response, message) - - class UnauthorizedException(response: Response, message: String?) : HttpException(response, message) - - class UserInactiveException(response: Response, message: String?) : HttpException(response, message) - - class BadGatewayException(response: Response, message: String) : IgnorableHttpException(response, message) - - class ServiceUnavailableException : IgnorableHttpException { - var retryAfter: Long = 0 - - constructor(message: String) : super(message) { - this.retryAfter = 0 - } - - constructor(response: Response, message: String) : super(response, message) { - this.retryAfter = java.lang.Long.valueOf(response.header("Retry-After", "0")!!) - } - } - - class IntegrityException(message: String) : GeneralSecurityException(message) - - open class IgnorableHttpException : HttpException { - constructor(message: String) : super(message) - constructor(response: Response, message: String) : super(response, message) - } - - open class GenericCryptoException(message: String) : Exception(message) - - class VersionTooNewException(message: String) : GenericCryptoException(message) - - open class HttpException : Exception, Serializable { - internal val status: Int - override val message: String - - val request: String? - val response: String? - - constructor(message: String) : super(message) { - this.message = message - - this.status = -1 - this.response = null - this.request = this.response - } - - constructor(status: Int, message: String) : super(status.toString() + " " + message) { - this.status = status - this.message = message - - response = null - request = response - } - - @JvmOverloads constructor(response: Response, custom_message: String? = null) : super(response.code().toString() + " " + response.message()) { - - status = response.code() - message = custom_message ?: response.message() - - /* As we don't know the media type and character set of request and response body, - only printable ASCII characters will be shown in clear text. Other octets will - be shown as "[xx]" where xx is the hex value of the octet. - */ - - // format request - val request = response.request() - var formatted = StringBuilder() - formatted.append(request.method()).append(" ").append(request.url().encodedPath()).append("\n") - var headers = request.headers() - for (name in headers.names()) { - for (value in headers.values(name)) { - /* Redact authorization token. */ - if (name == "Authorization") { - formatted.append(name).append(": ").append("XXXXXX").append("\n") - } else { - formatted.append(name).append(": ").append(value).append("\n") - } - } - } - if (request.body() != null) - try { - formatted.append("\n") - val buffer = Buffer() - request.body()!!.writeTo(buffer) - while (!buffer.exhausted()) - appendByte(formatted, buffer.readByte()) - } catch (e: IOException) { - Constants.log.warning("Couldn't read request body") - } - - this.request = formatted.toString() - - // format response - formatted = StringBuilder() - formatted.append(response.protocol()).append(" ").append(response.code()).append(" ").append(message).append("\n") - headers = response.headers() - for (name in headers.names()) - for (value in headers.values(name)) - formatted.append(name).append(": ").append(value).append("\n") - if (response.body() != null) { - val body = response.body() - try { - formatted.append("\n") - for (b in body!!.bytes()) - appendByte(formatted, b) - } catch (e: IOException) { - Constants.log.warning("Couldn't read response body") - } - - body!!.close() - } - this.response = formatted.toString() - } - - private fun appendByte(formatted: StringBuilder, b: Byte) { - if (b == '\r'.toByte()) - formatted.append("[CR]") - else if (b == '\n'.toByte()) - formatted.append("[LF]\n") - else if (b >= 0x20 && b <= 0x7E) - // printable ASCII - formatted.append(b.toChar()) - else - formatted.append("[" + Integer.toHexString(b.toInt() and 0xff) + "]") - } - } -} diff --git a/app/src/main/java/com/etesync/syncadapter/journalmanager/JournalAuthenticator.kt b/app/src/main/java/com/etesync/syncadapter/journalmanager/JournalAuthenticator.kt deleted file mode 100644 index d280c981..00000000 --- a/app/src/main/java/com/etesync/syncadapter/journalmanager/JournalAuthenticator.kt +++ /dev/null @@ -1,61 +0,0 @@ -package com.etesync.syncadapter.journalmanager - -import com.etesync.syncadapter.GsonHelper -import okhttp3.* -import java.io.IOException -import java.net.HttpURLConnection - -class JournalAuthenticator(private val client: OkHttpClient, private val remote: HttpUrl) { - private inner class AuthResponse private constructor() { - val token: String? = null - } - - @Throws(Exceptions.HttpException::class, IOException::class) - fun getAuthToken(username: String, password: String): String? { - val remote = remote.newBuilder() - .addPathSegments("api-token-auth") - .addPathSegment("") - .build() - val formBuilder = FormBody.Builder() - .add("username", username) - .add("password", password) - - val request = Request.Builder() - .post(formBuilder.build()) - .url(remote) - .build() - - val response = client.newCall(request).execute() - if (response.isSuccessful) { - return GsonHelper.gson.fromJson(response.body()!!.charStream(), AuthResponse::class.java).token - } else if (response.code() == HttpURLConnection.HTTP_BAD_REQUEST) { - throw Exceptions.UnauthorizedException(response, "Username or password incorrect") - } else { - throw Exceptions.HttpException(response) - } - } - - fun invalidateAuthToken(authToken: String) { - val remote = remote.newBuilder() - .addPathSegments("api/logout") - .addPathSegment("") - .build() - - val body = RequestBody.create(null, byteArrayOf()) - val request = Request.Builder() - .post(body) - .url(remote) - .build() - - val response = client.newCall(request).execute() - if (response.isSuccessful) { - return - } else { - when (response.code()) { - HttpURLConnection.HTTP_BAD_GATEWAY -> throw Exceptions.BadGatewayException(response, "Bad gateway: most likely a server restart") - HttpURLConnection.HTTP_UNAVAILABLE -> throw Exceptions.ServiceUnavailableException(response, "Service unavailable") - HttpURLConnection.HTTP_UNAUTHORIZED -> throw Exceptions.UnauthorizedException(response, "Unauthorized auth token") - } - } - } -} diff --git a/app/src/main/java/com/etesync/syncadapter/journalmanager/JournalEntryManager.kt b/app/src/main/java/com/etesync/syncadapter/journalmanager/JournalEntryManager.kt deleted file mode 100644 index ff725309..00000000 --- a/app/src/main/java/com/etesync/syncadapter/journalmanager/JournalEntryManager.kt +++ /dev/null @@ -1,116 +0,0 @@ -package com.etesync.syncadapter.journalmanager - -import com.etesync.syncadapter.GsonHelper -import com.etesync.syncadapter.log.Logger -import com.google.gson.reflect.TypeToken -import okhttp3.HttpUrl -import okhttp3.OkHttpClient -import okhttp3.Request -import okhttp3.RequestBody - -class JournalEntryManager(httpClient: OkHttpClient, remote: HttpUrl, val uid: String) : BaseManager() { - - init { - this.remote = remote.newBuilder() - .addPathSegments("api/v1/journals") - .addPathSegments(uid) - .addPathSegment("entries") - .addPathSegment("") - .build() - Logger.log.info("Created for: " + this.remote!!.toString()) - - this.client = httpClient - } - - @Throws(Exceptions.HttpException::class, Exceptions.IntegrityException::class) - fun list(crypto: Crypto.CryptoManager, last: String?, limit: Int): List { - var previousEntry: Entry? = null - val urlBuilder = this.remote!!.newBuilder() - if (last != null) { - urlBuilder.addQueryParameter("last", last) - previousEntry = Entry.getFakeWithUid(last) - } - - if (limit > 0) { - urlBuilder.addQueryParameter("limit", limit.toString()) - } - - val remote = urlBuilder.build() - - val request = Request.Builder() - .get() - .url(remote) - .build() - - val response = newCall(request) - val body = response.body() - val ret = GsonHelper.gson.fromJson>(body!!.charStream(), entryType) - - for (entry in ret) { - entry.verify(crypto, previousEntry) - previousEntry = entry - } - - return ret - } - - @Throws(Exceptions.HttpException::class) - fun create(entries: List, last: String?) { - val urlBuilder = this.remote!!.newBuilder() - if (last != null) { - urlBuilder.addQueryParameter("last", last) - } - - val remote = urlBuilder.build() - - val body = RequestBody.create(BaseManager.JSON, GsonHelper.gson.toJson(entries, entryType)) - - val request = Request.Builder() - .post(body) - .url(remote) - .build() - - newCall(request) - } - - class Entry : BaseManager.Base() { - - fun update(crypto: Crypto.CryptoManager, content: String, previous: Entry?) { - setContent(crypto, content) - uid = calculateHmac(crypto, previous) - } - - @Throws(Exceptions.IntegrityException::class) - internal fun verify(crypto: Crypto.CryptoManager, previous: Entry?) { - val correctHash = calculateHmac(crypto, previous) - if (uid != correctHash) { - throw Exceptions.IntegrityException("Bad HMAC. $uid != $correctHash") - } - } - - private fun calculateHmac(crypto: Crypto.CryptoManager, previous: Entry?): String { - var uuid: String? = null - if (previous != null) { - uuid = previous.uid - } - - return Crypto.toHex(calculateHmac(crypto, uuid)) - } - - companion object { - @JvmStatic - fun getFakeWithUid(uid: String): Entry { - val ret = Entry() - ret.uid = uid - return ret - } - } - } - - companion object { - private val entryType = object : TypeToken>() { - - }.type - } - -} diff --git a/app/src/main/java/com/etesync/syncadapter/journalmanager/JournalManager.kt b/app/src/main/java/com/etesync/syncadapter/journalmanager/JournalManager.kt deleted file mode 100644 index 93471458..00000000 --- a/app/src/main/java/com/etesync/syncadapter/journalmanager/JournalManager.kt +++ /dev/null @@ -1,220 +0,0 @@ -package com.etesync.syncadapter.journalmanager - -import com.etesync.syncadapter.GsonHelper -import com.etesync.syncadapter.journalmanager.Crypto.CryptoManager.Companion.HMAC_SIZE -import com.etesync.syncadapter.journalmanager.Crypto.sha256 -import com.etesync.syncadapter.journalmanager.Crypto.toHex -import com.etesync.syncadapter.log.Logger -import com.google.gson.reflect.TypeToken -import okhttp3.HttpUrl -import okhttp3.OkHttpClient -import okhttp3.Request -import okhttp3.RequestBody -import org.spongycastle.util.Arrays -import java.util.* - -class JournalManager(httpClient: OkHttpClient, remote: HttpUrl) : BaseManager() { - init { - this.remote = remote.newBuilder() - .addPathSegments("api/v1/journals") - .addPathSegment("") - .build() - Logger.log.info("Created for: " + this.remote!!.toString()) - - this.client = httpClient - } - - @Throws(Exceptions.HttpException::class) - fun list(): List { - val request = Request.Builder() - .get() - .url(remote!!) - .build() - - val response = newCall(request) - val body = response.body() - val ret = GsonHelper.gson.fromJson>(body!!.charStream(), journalType) - - for (journal in ret) { - journal.processFromJson() - } - - return ret - } - - @Throws(Exceptions.HttpException::class) - fun delete(journal: Journal) { - val remote = this.remote!!.resolve(journal.uid!! + "/") - val request = Request.Builder() - .delete() - .url(remote!!) - .build() - - newCall(request) - } - - @Throws(Exceptions.HttpException::class) - fun create(journal: Journal) { - val body = RequestBody.create(BaseManager.JSON, journal.toJson()) - - val request = Request.Builder() - .post(body) - .url(remote!!) - .build() - - newCall(request) - } - - @Throws(Exceptions.HttpException::class) - fun update(journal: Journal) { - val remote = this.remote!!.resolve(journal.uid!! + "/") - val body = RequestBody.create(BaseManager.JSON, journal.toJson()) - - val request = Request.Builder() - .put(body) - .url(remote!!) - .build() - - newCall(request) - } - - private fun getMemberRemote(journal: Journal, user: String?): HttpUrl { - val bulider = this.remote!!.newBuilder() - bulider.addPathSegment(journal.uid!!) - .addPathSegment("members") - if (user != null) { - bulider.addPathSegment(user) - } - bulider.addPathSegment("") - return bulider.build() - } - - @Throws(Exceptions.HttpException::class, Exceptions.IntegrityException::class, Exceptions.GenericCryptoException::class) - fun listMembers(journal: Journal): List { - val request = Request.Builder() - .get() - .url(getMemberRemote(journal, null)) - .build() - - val response = newCall(request) - val body = response.body() - return GsonHelper.gson.fromJson(body!!.charStream(), memberType) - } - - @Throws(Exceptions.HttpException::class) - fun deleteMember(journal: Journal, member: Member) { - val body = RequestBody.create(BaseManager.JSON, member.toJson()) - - val request = Request.Builder() - .delete(body) - .url(getMemberRemote(journal, member.user)) - .build() - - newCall(request) - } - - @Throws(Exceptions.HttpException::class) - fun addMember(journal: Journal, member: Member) { - val body = RequestBody.create(BaseManager.JSON, member.toJson()) - - val request = Request.Builder() - .post(body) - .url(getMemberRemote(journal, null)) - .build() - - newCall(request) - } - - class Journal : BaseManager.Base { - val owner: String? = null - val key: ByteArray? = null - var version = -1 - val readOnly = false - - @Transient - private var hmac: ByteArray? = null - - private constructor() : super() {} - - constructor(crypto: Crypto.CryptoManager, content: String, uid: String) : super(crypto, content, uid) { - hmac = calculateHmac(crypto) - version = crypto.version.toInt() - } - - fun processFromJson() { - hmac = Arrays.copyOfRange(content!!, 0, HMAC_SIZE) - content = Arrays.copyOfRange(content!!, HMAC_SIZE, content!!.size) - } - - @Throws(Exceptions.IntegrityException::class) - fun verify(crypto: Crypto.CryptoManager) { - val hmac = this.hmac; - - if (hmac == null) { - throw Exceptions.IntegrityException("HMAC is null!") - } - - val correctHash = calculateHmac(crypto) - if (!Arrays.areEqual(hmac, correctHash)) { - throw Exceptions.IntegrityException("Bad HMAC. " + toHex(hmac) + " != " + toHex(correctHash)) - } - } - - internal fun calculateHmac(crypto: Crypto.CryptoManager): ByteArray { - return super.calculateHmac(crypto, uid) - } - - internal override fun toJson(): String { - val rawContent = content - content = Arrays.concatenate(hmac, rawContent) - val ret = super.toJson() - content = rawContent - return ret - } - - companion object { - @JvmStatic - fun fakeWithUid(uid: String): Journal { - val ret = Journal() - ret.uid = uid - return ret - } - - @JvmStatic - fun genUid(): String { - return sha256(UUID.randomUUID().toString()) - } - } - } - - class Member { - val user: String? - val key: ByteArray? - val readOnly: Boolean - - private constructor() { - this.user = null - this.key = null - this.readOnly = false - } - - constructor(user: String, encryptedKey: ByteArray, readOnly: Boolean = false) { - this.user = user - this.key = encryptedKey - this.readOnly = readOnly - } - - internal fun toJson(): String { - return GsonHelper.gson.toJson(this, javaClass) - } - } - - companion object { - private val journalType = object : TypeToken>() { - - }.type - private val memberType = object : TypeToken>() { - - }.type - } -} diff --git a/app/src/main/java/com/etesync/syncadapter/journalmanager/UserInfoManager.kt b/app/src/main/java/com/etesync/syncadapter/journalmanager/UserInfoManager.kt deleted file mode 100644 index 544597c4..00000000 --- a/app/src/main/java/com/etesync/syncadapter/journalmanager/UserInfoManager.kt +++ /dev/null @@ -1,148 +0,0 @@ -package com.etesync.syncadapter.journalmanager - -import com.etesync.syncadapter.GsonHelper -import com.etesync.syncadapter.journalmanager.Crypto.CryptoManager.Companion.HMAC_SIZE -import com.etesync.syncadapter.journalmanager.Crypto.toHex -import okhttp3.* -import org.spongycastle.util.Arrays -import java.io.IOException -import java.net.HttpURLConnection - -class UserInfoManager(httpClient: OkHttpClient, remote: HttpUrl) : BaseManager() { - init { - this.remote = remote.newBuilder() - .addPathSegments("api/v1/user") - .addPathSegment("") - .build() - - this.client = httpClient - } - - @Throws(Exceptions.HttpException::class) - fun fetch(owner: String): UserInfo? { - val remote = this.remote!!.newBuilder().addPathSegment(owner).addPathSegment("").build() - val request = Request.Builder() - .get() - .url(remote) - .build() - - val response: Response - try { - response = newCall(request) - } catch (e: Exceptions.HttpException) { - return if (e.status == HttpURLConnection.HTTP_NOT_FOUND) { - null - } else { - throw e - } - } - - val body = response.body() - val ret = GsonHelper.gson.fromJson(body!!.charStream(), UserInfo::class.java) - ret.owner = owner - - return ret - } - - @Throws(Exceptions.HttpException::class) - fun delete(userInfo: UserInfo) { - val remote = this.remote!!.newBuilder().addPathSegment(userInfo.owner!!).addPathSegment("").build() - val request = Request.Builder() - .delete() - .url(remote) - .build() - - newCall(request) - } - - @Throws(Exceptions.HttpException::class) - fun create(userInfo: UserInfo) { - val body = RequestBody.create(BaseManager.JSON, userInfo.toJson()) - - val request = Request.Builder() - .post(body) - .url(remote!!) - .build() - - newCall(request) - } - - @Throws(Exceptions.HttpException::class) - fun update(userInfo: UserInfo) { - val remote = this.remote!!.newBuilder().addPathSegment(userInfo.owner!!).addPathSegment("").build() - val body = RequestBody.create(BaseManager.JSON, userInfo.toJson()) - - val request = Request.Builder() - .put(body) - .url(remote) - .build() - - newCall(request) - } - - class UserInfo { - @Transient - var owner: String? = null - @Transient - val plan: String? = null - val version: Byte? - val pubkey: ByteArray? - private var content: ByteArray? = null - - fun getContent(crypto: Crypto.CryptoManager): ByteArray? { - val content = Arrays.copyOfRange(this.content!!, HMAC_SIZE, this.content!!.size) - return crypto.decrypt(content) - } - - fun setContent(crypto: Crypto.CryptoManager, rawContent: ByteArray) { - val content = crypto.encrypt(rawContent) - this.content = Arrays.concatenate(calculateHmac(crypto, content), content) - } - - @Throws(Exceptions.IntegrityException::class) - fun verify(crypto: Crypto.CryptoManager) { - if (this.content == null) { - // Nothing to verify. - return - } - - val hmac = Arrays.copyOfRange(this.content!!, 0, HMAC_SIZE) - val content = Arrays.copyOfRange(this.content!!, HMAC_SIZE, this.content!!.size) - - val correctHash = calculateHmac(crypto, content) - if (!Arrays.areEqual(hmac, correctHash)) { - throw Exceptions.IntegrityException("Bad HMAC. " + toHex(hmac) + " != " + toHex(correctHash)) - } - } - - private fun calculateHmac(crypto: Crypto.CryptoManager, content: ByteArray?): ByteArray { - return crypto.hmac(Arrays.concatenate(content, pubkey)) - } - - private constructor() { - this.version = null - this.pubkey = null - } - - constructor(crypto: Crypto.CryptoManager, owner: String, pubkey: ByteArray, content: ByteArray) { - this.owner = owner - this.pubkey = pubkey - version = crypto.version - setContent(crypto, content) - } - - internal fun toJson(): String { - return GsonHelper.gson.toJson(this, javaClass) - } - - companion object { - - @JvmStatic - @Throws(IOException::class) - fun generate(cryptoManager: Crypto.CryptoManager, owner: String): UserInfo { - val keyPair = Crypto.generateKeyPair() - return UserInfo(cryptoManager, owner, keyPair!!.publicKey, keyPair.privateKey) - } - } - } -} diff --git a/app/src/main/java/com/etesync/syncadapter/journalmanager/util/ByteUtil.java b/app/src/main/java/com/etesync/syncadapter/journalmanager/util/ByteUtil.java deleted file mode 100644 index ebd063e5..00000000 --- a/app/src/main/java/com/etesync/syncadapter/journalmanager/util/ByteUtil.java +++ /dev/null @@ -1,248 +0,0 @@ -/** - * Copyright (C) 2014-2016 Open Whisper Systems - * - * Licensed according to the LICENSE file in this repository. - */ -package com.etesync.syncadapter.journalmanager.util; - -import org.apache.commons.codec.binary.Hex; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.text.ParseException; - -public class ByteUtil { - - public static byte[] combine(byte[]... elements) { - try { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - - for (byte[] element : elements) { - baos.write(element); - } - - return baos.toByteArray(); - } catch (IOException e) { - throw new AssertionError(e); - } - } - - public static byte[][] split(byte[] input, int firstLength, int secondLength) { - byte[][] parts = new byte[2][]; - - parts[0] = new byte[firstLength]; - System.arraycopy(input, 0, parts[0], 0, firstLength); - - parts[1] = new byte[secondLength]; - System.arraycopy(input, firstLength, parts[1], 0, secondLength); - - return parts; - } - - public static byte[][] split(byte[] input, int firstLength, int secondLength, int thirdLength) - throws ParseException - { - if (input == null || firstLength < 0 || secondLength < 0 || thirdLength < 0 || - input.length < firstLength + secondLength + thirdLength) - { - throw new ParseException("Input too small: " + (input == null ? null : Hex.encodeHex(input)), 0); - } - - byte[][] parts = new byte[3][]; - - parts[0] = new byte[firstLength]; - System.arraycopy(input, 0, parts[0], 0, firstLength); - - parts[1] = new byte[secondLength]; - System.arraycopy(input, firstLength, parts[1], 0, secondLength); - - parts[2] = new byte[thirdLength]; - System.arraycopy(input, firstLength + secondLength, parts[2], 0, thirdLength); - - return parts; - } - - public static byte[] trim(byte[] input, int length) { - byte[] result = new byte[length]; - System.arraycopy(input, 0, result, 0, result.length); - - return result; - } - - public static byte[] copyFrom(byte[] input) { - byte[] output = new byte[input.length]; - System.arraycopy(input, 0, output, 0, output.length); - - return output; - } - - public static byte intsToByteHighAndLow(int highValue, int lowValue) { - return (byte)((highValue << 4 | lowValue) & 0xFF); - } - - public static int highBitsToInt(byte value) { - return (value & 0xFF) >> 4; - } - - public static int lowBitsToInt(byte value) { - return (value & 0xF); - } - - public static int highBitsToMedium(int value) { - return (value >> 12); - } - - public static int lowBitsToMedium(int value) { - return (value & 0xFFF); - } - - public static byte[] shortToByteArray(int value) { - byte[] bytes = new byte[2]; - shortToByteArray(bytes, 0, value); - return bytes; - } - - public static int shortToByteArray(byte[] bytes, int offset, int value) { - bytes[offset+1] = (byte)value; - bytes[offset] = (byte)(value >> 8); - return 2; - } - - public static int shortToLittleEndianByteArray(byte[] bytes, int offset, int value) { - bytes[offset] = (byte)value; - bytes[offset+1] = (byte)(value >> 8); - return 2; - } - - public static byte[] mediumToByteArray(int value) { - byte[] bytes = new byte[3]; - mediumToByteArray(bytes, 0, value); - return bytes; - } - - public static int mediumToByteArray(byte[] bytes, int offset, int value) { - bytes[offset + 2] = (byte)value; - bytes[offset + 1] = (byte)(value >> 8); - bytes[offset] = (byte)(value >> 16); - return 3; - } - - public static byte[] intToByteArray(int value) { - byte[] bytes = new byte[4]; - intToByteArray(bytes, 0, value); - return bytes; - } - - public static int intToByteArray(byte[] bytes, int offset, int value) { - bytes[offset + 3] = (byte)value; - bytes[offset + 2] = (byte)(value >> 8); - bytes[offset + 1] = (byte)(value >> 16); - bytes[offset] = (byte)(value >> 24); - return 4; - } - - public static int intToLittleEndianByteArray(byte[] bytes, int offset, int value) { - bytes[offset] = (byte)value; - bytes[offset+1] = (byte)(value >> 8); - bytes[offset+2] = (byte)(value >> 16); - bytes[offset+3] = (byte)(value >> 24); - return 4; - } - - public static byte[] longToByteArray(long l) { - byte[] bytes = new byte[8]; - longToByteArray(bytes, 0, l); - return bytes; - } - - public static int longToByteArray(byte[] bytes, int offset, long value) { - bytes[offset + 7] = (byte)value; - bytes[offset + 6] = (byte)(value >> 8); - bytes[offset + 5] = (byte)(value >> 16); - bytes[offset + 4] = (byte)(value >> 24); - bytes[offset + 3] = (byte)(value >> 32); - bytes[offset + 2] = (byte)(value >> 40); - bytes[offset + 1] = (byte)(value >> 48); - bytes[offset] = (byte)(value >> 56); - return 8; - } - - public static int longTo4ByteArray(byte[] bytes, int offset, long value) { - bytes[offset + 3] = (byte)value; - bytes[offset + 2] = (byte)(value >> 8); - bytes[offset + 1] = (byte)(value >> 16); - bytes[offset + 0] = (byte)(value >> 24); - return 4; - } - - public static int byteArrayToShort(byte[] bytes) { - return byteArrayToShort(bytes, 0); - } - - public static int byteArrayToShort(byte[] bytes, int offset) { - return - (bytes[offset] & 0xff) << 8 | (bytes[offset + 1] & 0xff); - } - - // The SSL patented 3-byte Value. - public static int byteArrayToMedium(byte[] bytes, int offset) { - return - (bytes[offset] & 0xff) << 16 | - (bytes[offset + 1] & 0xff) << 8 | - (bytes[offset + 2] & 0xff); - } - - public static int byteArrayToInt(byte[] bytes) { - return byteArrayToInt(bytes, 0); - } - - public static int byteArrayToInt(byte[] bytes, int offset) { - return - (bytes[offset] & 0xff) << 24 | - (bytes[offset + 1] & 0xff) << 16 | - (bytes[offset + 2] & 0xff) << 8 | - (bytes[offset + 3] & 0xff); - } - - public static int byteArrayToIntLittleEndian(byte[] bytes, int offset) { - return - (bytes[offset + 3] & 0xff) << 24 | - (bytes[offset + 2] & 0xff) << 16 | - (bytes[offset + 1] & 0xff) << 8 | - (bytes[offset] & 0xff); - } - - public static long byteArrayToLong(byte[] bytes) { - return byteArrayToLong(bytes, 0); - } - - public static long byteArray4ToLong(byte[] bytes, int offset) { - return - ((bytes[offset + 0] & 0xffL) << 24) | - ((bytes[offset + 1] & 0xffL) << 16) | - ((bytes[offset + 2] & 0xffL) << 8) | - ((bytes[offset + 3] & 0xffL)); - } - - public static long byteArray5ToLong(byte[] bytes, int offset) { - return - ((bytes[offset] & 0xffL) << 32) | - ((bytes[offset + 1] & 0xffL) << 24) | - ((bytes[offset + 2] & 0xffL) << 16) | - ((bytes[offset + 3] & 0xffL) << 8) | - ((bytes[offset + 4] & 0xffL)); - } - - public static long byteArrayToLong(byte[] bytes, int offset) { - return - ((bytes[offset] & 0xffL) << 56) | - ((bytes[offset + 1] & 0xffL) << 48) | - ((bytes[offset + 2] & 0xffL) << 40) | - ((bytes[offset + 3] & 0xffL) << 32) | - ((bytes[offset + 4] & 0xffL) << 24) | - ((bytes[offset + 5] & 0xffL) << 16) | - ((bytes[offset + 6] & 0xffL) << 8) | - ((bytes[offset + 7] & 0xffL)); - } - -} diff --git a/app/src/main/java/com/etesync/syncadapter/model/CollectionInfo.kt b/app/src/main/java/com/etesync/syncadapter/model/CollectionInfo.kt index 130b2900..308fff6f 100644 --- a/app/src/main/java/com/etesync/syncadapter/model/CollectionInfo.kt +++ b/app/src/main/java/com/etesync/syncadapter/model/CollectionInfo.kt @@ -9,13 +9,11 @@ package com.etesync.syncadapter.model import android.content.ContentValues -import com.etesync.syncadapter.journalmanager.Constants -import com.etesync.syncadapter.journalmanager.JournalManager +import com.etesync.journalmanager.Constants +import com.etesync.journalmanager.JournalManager import com.etesync.syncadapter.model.ServiceDB.Collections import com.google.gson.GsonBuilder import com.google.gson.annotations.Expose -import io.requery.Persistable -import io.requery.sql.EntityDataStore import java.io.Serializable class CollectionInfo : Serializable { diff --git a/app/src/main/java/com/etesync/syncadapter/model/SyncEntry.kt b/app/src/main/java/com/etesync/syncadapter/model/SyncEntry.kt index 8516aae1..8ab4f258 100644 --- a/app/src/main/java/com/etesync/syncadapter/model/SyncEntry.kt +++ b/app/src/main/java/com/etesync/syncadapter/model/SyncEntry.kt @@ -1,8 +1,8 @@ package com.etesync.syncadapter.model import com.etesync.syncadapter.GsonHelper -import com.etesync.syncadapter.journalmanager.Crypto -import com.etesync.syncadapter.journalmanager.JournalEntryManager +import com.etesync.journalmanager.Crypto +import com.etesync.journalmanager.JournalEntryManager import java.io.Serializable diff --git a/app/src/main/java/com/etesync/syncadapter/syncadapter/CalendarSyncManager.kt b/app/src/main/java/com/etesync/syncadapter/syncadapter/CalendarSyncManager.kt index 566789c9..01e16506 100644 --- a/app/src/main/java/com/etesync/syncadapter/syncadapter/CalendarSyncManager.kt +++ b/app/src/main/java/com/etesync/syncadapter/syncadapter/CalendarSyncManager.kt @@ -20,8 +20,8 @@ import at.bitfire.vcard4android.ContactsStorageException import com.etesync.syncadapter.AccountSettings import com.etesync.syncadapter.Constants import com.etesync.syncadapter.R -import com.etesync.syncadapter.journalmanager.Exceptions -import com.etesync.syncadapter.journalmanager.JournalEntryManager +import com.etesync.journalmanager.Exceptions +import com.etesync.journalmanager.JournalEntryManager import com.etesync.syncadapter.log.Logger import com.etesync.syncadapter.model.CollectionInfo import com.etesync.syncadapter.model.SyncEntry diff --git a/app/src/main/java/com/etesync/syncadapter/syncadapter/ContactsSyncManager.kt b/app/src/main/java/com/etesync/syncadapter/syncadapter/ContactsSyncManager.kt index ee87763e..4db7948e 100644 --- a/app/src/main/java/com/etesync/syncadapter/syncadapter/ContactsSyncManager.kt +++ b/app/src/main/java/com/etesync/syncadapter/syncadapter/ContactsSyncManager.kt @@ -20,8 +20,8 @@ import com.etesync.syncadapter.AccountSettings import com.etesync.syncadapter.Constants import com.etesync.syncadapter.HttpClient import com.etesync.syncadapter.R -import com.etesync.syncadapter.journalmanager.Exceptions -import com.etesync.syncadapter.journalmanager.JournalEntryManager +import com.etesync.journalmanager.Exceptions +import com.etesync.journalmanager.JournalEntryManager import com.etesync.syncadapter.log.Logger import com.etesync.syncadapter.model.CollectionInfo import com.etesync.syncadapter.model.SyncEntry diff --git a/app/src/main/java/com/etesync/syncadapter/syncadapter/SyncAdapterService.kt b/app/src/main/java/com/etesync/syncadapter/syncadapter/SyncAdapterService.kt index ad9d63c6..1253641a 100644 --- a/app/src/main/java/com/etesync/syncadapter/syncadapter/SyncAdapterService.kt +++ b/app/src/main/java/com/etesync/syncadapter/syncadapter/SyncAdapterService.kt @@ -23,9 +23,9 @@ import androidx.core.util.Pair import at.bitfire.ical4android.CalendarStorageException import at.bitfire.vcard4android.ContactsStorageException import com.etesync.syncadapter.* -import com.etesync.syncadapter.journalmanager.Crypto -import com.etesync.syncadapter.journalmanager.Exceptions -import com.etesync.syncadapter.journalmanager.JournalManager +import com.etesync.journalmanager.Crypto +import com.etesync.journalmanager.Exceptions +import com.etesync.journalmanager.JournalManager import com.etesync.syncadapter.log.Logger import com.etesync.syncadapter.model.CollectionInfo import com.etesync.syncadapter.model.JournalEntity @@ -51,7 +51,7 @@ class CachedJournalFetcher { for (journal in journalsManager.list()) { val crypto: Crypto.CryptoManager if (journal.key != null) { - crypto = Crypto.CryptoManager(journal.version, settings.keyPair!!, journal.key) + crypto = Crypto.CryptoManager(journal.version, settings.keyPair!!, journal.key!!) } else { crypto = Crypto.CryptoManager(journal.version, settings.password(), journal.uid!!) } diff --git a/app/src/main/java/com/etesync/syncadapter/syncadapter/SyncManager.kt b/app/src/main/java/com/etesync/syncadapter/syncadapter/SyncManager.kt index 86750e06..013e56c9 100644 --- a/app/src/main/java/com/etesync/syncadapter/syncadapter/SyncManager.kt +++ b/app/src/main/java/com/etesync/syncadapter/syncadapter/SyncManager.kt @@ -18,9 +18,9 @@ import at.bitfire.ical4android.InvalidCalendarException import at.bitfire.vcard4android.ContactsStorageException import com.etesync.syncadapter.* import com.etesync.syncadapter.Constants.KEY_ACCOUNT -import com.etesync.syncadapter.journalmanager.Crypto -import com.etesync.syncadapter.journalmanager.Exceptions -import com.etesync.syncadapter.journalmanager.JournalEntryManager +import com.etesync.journalmanager.Crypto +import com.etesync.journalmanager.Exceptions +import com.etesync.journalmanager.JournalEntryManager import com.etesync.syncadapter.log.Logger import com.etesync.syncadapter.model.* import com.etesync.syncadapter.model.SyncEntry.Actions.ADD diff --git a/app/src/main/java/com/etesync/syncadapter/syncadapter/SyncNotification.kt b/app/src/main/java/com/etesync/syncadapter/syncadapter/SyncNotification.kt index 8e09e14a..11f55848 100644 --- a/app/src/main/java/com/etesync/syncadapter/syncadapter/SyncNotification.kt +++ b/app/src/main/java/com/etesync/syncadapter/syncadapter/SyncNotification.kt @@ -14,7 +14,7 @@ import at.bitfire.vcard4android.ContactsStorageException import com.etesync.syncadapter.AccountSettings import com.etesync.syncadapter.Constants import com.etesync.syncadapter.R -import com.etesync.syncadapter.journalmanager.Exceptions +import com.etesync.journalmanager.Exceptions import com.etesync.syncadapter.log.Logger import com.etesync.syncadapter.ui.AccountSettingsActivity import com.etesync.syncadapter.ui.DebugInfoActivity diff --git a/app/src/main/java/com/etesync/syncadapter/syncadapter/TasksSyncManager.kt b/app/src/main/java/com/etesync/syncadapter/syncadapter/TasksSyncManager.kt index 13b84de6..32f8166b 100644 --- a/app/src/main/java/com/etesync/syncadapter/syncadapter/TasksSyncManager.kt +++ b/app/src/main/java/com/etesync/syncadapter/syncadapter/TasksSyncManager.kt @@ -16,7 +16,7 @@ import at.bitfire.ical4android.Task import com.etesync.syncadapter.AccountSettings import com.etesync.syncadapter.Constants import com.etesync.syncadapter.R -import com.etesync.syncadapter.journalmanager.JournalEntryManager +import com.etesync.journalmanager.JournalEntryManager import com.etesync.syncadapter.log.Logger import com.etesync.syncadapter.model.CollectionInfo import com.etesync.syncadapter.model.SyncEntry diff --git a/app/src/main/java/com/etesync/syncadapter/ui/AccountActivity.kt b/app/src/main/java/com/etesync/syncadapter/ui/AccountActivity.kt index 58b8ea1d..eeb3b627 100644 --- a/app/src/main/java/com/etesync/syncadapter/ui/AccountActivity.kt +++ b/app/src/main/java/com/etesync/syncadapter/ui/AccountActivity.kt @@ -28,9 +28,9 @@ import androidx.core.content.ContextCompat import at.bitfire.ical4android.TaskProvider import at.bitfire.vcard4android.ContactsStorageException import com.etesync.syncadapter.* -import com.etesync.syncadapter.journalmanager.Crypto -import com.etesync.syncadapter.journalmanager.Exceptions -import com.etesync.syncadapter.journalmanager.JournalAuthenticator +import com.etesync.journalmanager.Crypto +import com.etesync.journalmanager.Exceptions +import com.etesync.journalmanager.JournalAuthenticator import com.etesync.syncadapter.log.Logger import com.etesync.syncadapter.model.CollectionInfo import com.etesync.syncadapter.model.JournalEntity diff --git a/app/src/main/java/com/etesync/syncadapter/ui/AddMemberFragment.kt b/app/src/main/java/com/etesync/syncadapter/ui/AddMemberFragment.kt index bfb30d6f..d74a0964 100644 --- a/app/src/main/java/com/etesync/syncadapter/ui/AddMemberFragment.kt +++ b/app/src/main/java/com/etesync/syncadapter/ui/AddMemberFragment.kt @@ -12,9 +12,9 @@ import android.widget.TextView import androidx.appcompat.app.AlertDialog import androidx.fragment.app.DialogFragment import com.etesync.syncadapter.* -import com.etesync.syncadapter.journalmanager.Crypto -import com.etesync.syncadapter.journalmanager.JournalManager -import com.etesync.syncadapter.journalmanager.UserInfoManager +import com.etesync.journalmanager.Crypto +import com.etesync.journalmanager.JournalManager +import com.etesync.journalmanager.UserInfoManager import com.etesync.syncadapter.model.CollectionInfo import com.etesync.syncadapter.model.JournalEntity import okhttp3.HttpUrl diff --git a/app/src/main/java/com/etesync/syncadapter/ui/ChangeEncryptionPasswordActivity.kt b/app/src/main/java/com/etesync/syncadapter/ui/ChangeEncryptionPasswordActivity.kt index 83188f43..0899c259 100644 --- a/app/src/main/java/com/etesync/syncadapter/ui/ChangeEncryptionPasswordActivity.kt +++ b/app/src/main/java/com/etesync/syncadapter/ui/ChangeEncryptionPasswordActivity.kt @@ -18,9 +18,9 @@ import androidx.appcompat.app.AlertDialog import com.etesync.syncadapter.AccountSettings import com.etesync.syncadapter.HttpClient import com.etesync.syncadapter.R -import com.etesync.syncadapter.journalmanager.Crypto -import com.etesync.syncadapter.journalmanager.JournalManager -import com.etesync.syncadapter.journalmanager.UserInfoManager +import com.etesync.journalmanager.Crypto +import com.etesync.journalmanager.JournalManager +import com.etesync.journalmanager.UserInfoManager import com.etesync.syncadapter.log.Logger import com.etesync.syncadapter.syncadapter.requestSync import com.google.android.material.textfield.TextInputLayout @@ -84,7 +84,7 @@ open class ChangeEncryptionPasswordActivity : BaseActivity() { Logger.log.info("Finished deriving new key") val userInfoContent = userInfo.getContent(cryptoManager)!! - cryptoManager = Crypto.CryptoManager(userInfo.version.toInt(), new_key, "userInfo") + cryptoManager = Crypto.CryptoManager(userInfo.version!!.toInt(), new_key, "userInfo") userInfo.setContent(cryptoManager, userInfoContent) Logger.log.info("Fetching journal list") diff --git a/app/src/main/java/com/etesync/syncadapter/ui/CollectionMembersListFragment.kt b/app/src/main/java/com/etesync/syncadapter/ui/CollectionMembersListFragment.kt index 2628245f..59246888 100644 --- a/app/src/main/java/com/etesync/syncadapter/ui/CollectionMembersListFragment.kt +++ b/app/src/main/java/com/etesync/syncadapter/ui/CollectionMembersListFragment.kt @@ -12,7 +12,7 @@ import android.widget.TextView import androidx.appcompat.app.AlertDialog import androidx.fragment.app.ListFragment import com.etesync.syncadapter.* -import com.etesync.syncadapter.journalmanager.JournalManager +import com.etesync.journalmanager.JournalManager import com.etesync.syncadapter.model.CollectionInfo import com.etesync.syncadapter.model.JournalEntity import com.etesync.syncadapter.model.JournalModel diff --git a/app/src/main/java/com/etesync/syncadapter/ui/CreateCollectionFragment.kt b/app/src/main/java/com/etesync/syncadapter/ui/CreateCollectionFragment.kt index 5522f295..c9d605fe 100644 --- a/app/src/main/java/com/etesync/syncadapter/ui/CreateCollectionFragment.kt +++ b/app/src/main/java/com/etesync/syncadapter/ui/CreateCollectionFragment.kt @@ -21,9 +21,9 @@ import androidx.loader.content.AsyncTaskLoader import androidx.loader.content.Loader import at.bitfire.ical4android.TaskProvider import com.etesync.syncadapter.* -import com.etesync.syncadapter.journalmanager.Crypto -import com.etesync.syncadapter.journalmanager.Exceptions -import com.etesync.syncadapter.journalmanager.JournalManager +import com.etesync.journalmanager.Crypto +import com.etesync.journalmanager.Exceptions +import com.etesync.journalmanager.JournalManager import com.etesync.syncadapter.model.CollectionInfo import com.etesync.syncadapter.model.JournalEntity import com.etesync.syncadapter.model.JournalModel diff --git a/app/src/main/java/com/etesync/syncadapter/ui/DebugInfoActivity.kt b/app/src/main/java/com/etesync/syncadapter/ui/DebugInfoActivity.kt index 5a921dac..61e0f3d8 100644 --- a/app/src/main/java/com/etesync/syncadapter/ui/DebugInfoActivity.kt +++ b/app/src/main/java/com/etesync/syncadapter/ui/DebugInfoActivity.kt @@ -28,7 +28,7 @@ import androidx.core.content.ContextCompat import at.bitfire.vcard4android.ContactsStorageException import com.etesync.syncadapter.* import com.etesync.syncadapter.Constants.KEY_ACCOUNT -import com.etesync.syncadapter.journalmanager.Exceptions.HttpException +import com.etesync.journalmanager.Exceptions.HttpException import com.etesync.syncadapter.log.Logger import com.etesync.syncadapter.model.EntryEntity import com.etesync.syncadapter.model.JournalEntity diff --git a/app/src/main/java/com/etesync/syncadapter/ui/DeleteCollectionFragment.kt b/app/src/main/java/com/etesync/syncadapter/ui/DeleteCollectionFragment.kt index c54c9ff6..fbeded62 100644 --- a/app/src/main/java/com/etesync/syncadapter/ui/DeleteCollectionFragment.kt +++ b/app/src/main/java/com/etesync/syncadapter/ui/DeleteCollectionFragment.kt @@ -20,9 +20,9 @@ import androidx.loader.app.LoaderManager import androidx.loader.content.AsyncTaskLoader import androidx.loader.content.Loader import com.etesync.syncadapter.* -import com.etesync.syncadapter.journalmanager.Crypto -import com.etesync.syncadapter.journalmanager.Exceptions -import com.etesync.syncadapter.journalmanager.JournalManager +import com.etesync.journalmanager.Crypto +import com.etesync.journalmanager.Exceptions +import com.etesync.journalmanager.JournalManager import com.etesync.syncadapter.model.CollectionInfo import com.etesync.syncadapter.model.JournalEntity import okhttp3.HttpUrl diff --git a/app/src/main/java/com/etesync/syncadapter/ui/ExceptionInfoFragment.kt b/app/src/main/java/com/etesync/syncadapter/ui/ExceptionInfoFragment.kt index a761837c..4dce9c6d 100644 --- a/app/src/main/java/com/etesync/syncadapter/ui/ExceptionInfoFragment.kt +++ b/app/src/main/java/com/etesync/syncadapter/ui/ExceptionInfoFragment.kt @@ -10,13 +10,12 @@ package com.etesync.syncadapter.ui import android.accounts.Account import android.app.Dialog -import android.content.Intent import android.os.Bundle import androidx.appcompat.app.AlertDialog import androidx.fragment.app.DialogFragment import com.etesync.syncadapter.Constants import com.etesync.syncadapter.R -import com.etesync.syncadapter.journalmanager.Exceptions.HttpException +import com.etesync.journalmanager.Exceptions.HttpException import java.io.IOException class ExceptionInfoFragment : DialogFragment() { diff --git a/app/src/main/java/com/etesync/syncadapter/ui/RemoveMemberFragment.kt b/app/src/main/java/com/etesync/syncadapter/ui/RemoveMemberFragment.kt index 27b45b49..89003650 100644 --- a/app/src/main/java/com/etesync/syncadapter/ui/RemoveMemberFragment.kt +++ b/app/src/main/java/com/etesync/syncadapter/ui/RemoveMemberFragment.kt @@ -8,7 +8,7 @@ import android.os.Bundle import androidx.appcompat.app.AlertDialog import androidx.fragment.app.DialogFragment import com.etesync.syncadapter.* -import com.etesync.syncadapter.journalmanager.JournalManager +import com.etesync.journalmanager.JournalManager import com.etesync.syncadapter.model.CollectionInfo import okhttp3.HttpUrl diff --git a/app/src/main/java/com/etesync/syncadapter/ui/setup/BaseConfigurationFinder.kt b/app/src/main/java/com/etesync/syncadapter/ui/setup/BaseConfigurationFinder.kt index 5022d2c1..4d977a54 100644 --- a/app/src/main/java/com/etesync/syncadapter/ui/setup/BaseConfigurationFinder.kt +++ b/app/src/main/java/com/etesync/syncadapter/ui/setup/BaseConfigurationFinder.kt @@ -9,9 +9,9 @@ package com.etesync.syncadapter.ui.setup import android.content.Context import com.etesync.syncadapter.HttpClient -import com.etesync.syncadapter.journalmanager.Crypto -import com.etesync.syncadapter.journalmanager.Exceptions -import com.etesync.syncadapter.journalmanager.JournalAuthenticator +import com.etesync.journalmanager.Crypto +import com.etesync.journalmanager.Exceptions +import com.etesync.journalmanager.JournalAuthenticator import com.etesync.syncadapter.log.Logger import com.etesync.syncadapter.model.CollectionInfo import okhttp3.HttpUrl diff --git a/app/src/main/java/com/etesync/syncadapter/ui/setup/SetupEncryptionFragment.kt b/app/src/main/java/com/etesync/syncadapter/ui/setup/SetupEncryptionFragment.kt index 1f183d38..f4faa07b 100644 --- a/app/src/main/java/com/etesync/syncadapter/ui/setup/SetupEncryptionFragment.kt +++ b/app/src/main/java/com/etesync/syncadapter/ui/setup/SetupEncryptionFragment.kt @@ -22,9 +22,9 @@ import androidx.appcompat.app.AlertDialog import androidx.fragment.app.DialogFragment import at.bitfire.ical4android.TaskProvider import com.etesync.syncadapter.* -import com.etesync.syncadapter.journalmanager.Crypto -import com.etesync.syncadapter.journalmanager.Exceptions -import com.etesync.syncadapter.journalmanager.UserInfoManager +import com.etesync.journalmanager.Crypto +import com.etesync.journalmanager.Exceptions +import com.etesync.journalmanager.UserInfoManager import com.etesync.syncadapter.log.Logger import com.etesync.syncadapter.model.CollectionInfo import com.etesync.syncadapter.model.JournalEntity diff --git a/app/src/main/java/com/etesync/syncadapter/ui/setup/SetupUserInfoFragment.kt b/app/src/main/java/com/etesync/syncadapter/ui/setup/SetupUserInfoFragment.kt index 80f42a93..b9599962 100644 --- a/app/src/main/java/com/etesync/syncadapter/ui/setup/SetupUserInfoFragment.kt +++ b/app/src/main/java/com/etesync/syncadapter/ui/setup/SetupUserInfoFragment.kt @@ -13,9 +13,9 @@ import com.etesync.syncadapter.Constants.KEY_ACCOUNT import com.etesync.syncadapter.HttpClient import com.etesync.syncadapter.InvalidAccountException import com.etesync.syncadapter.R -import com.etesync.syncadapter.journalmanager.Constants -import com.etesync.syncadapter.journalmanager.Crypto -import com.etesync.syncadapter.journalmanager.UserInfoManager +import com.etesync.journalmanager.Constants +import com.etesync.journalmanager.Crypto +import com.etesync.journalmanager.UserInfoManager import com.etesync.syncadapter.log.Logger import okhttp3.HttpUrl diff --git a/app/src/test/java/com/etesync/syncadapter/journalmanager/AuthenticatorTest.kt b/app/src/test/java/com/etesync/syncadapter/journalmanager/AuthenticatorTest.kt deleted file mode 100644 index be38d8c6..00000000 --- a/app/src/test/java/com/etesync/syncadapter/journalmanager/AuthenticatorTest.kt +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright © 2013 – 2015 Ricki Hirner (bitfire web engineering). - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Public License v3.0 - * which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/gpl.html - */ - -package com.etesync.syncadapter.journalmanager - -import com.etesync.syncadapter.HttpClient -import okhttp3.HttpUrl -import okhttp3.OkHttpClient -import org.junit.After -import org.junit.Assert.assertNotEquals -import org.junit.Before -import org.junit.Test -import java.io.IOException - -class AuthenticatorTest { - private var httpClient: OkHttpClient? = null - private var remote: HttpUrl? = null - - @Before - @Throws(IOException::class) - fun setUp() { - httpClient = HttpClient.Builder().build().okHttpClient - remote = HttpUrl.parse("http://localhost:8000") // FIXME: hardcode for now, should make configureable - } - - @After - @Throws(IOException::class) - fun tearDown() { - } - - @Test - @Throws(IOException::class, Exceptions.HttpException::class) - fun testAuthToken() { - val journalAuthenticator = JournalAuthenticator(httpClient!!, remote!!) - val authToken = journalAuthenticator.getAuthToken(Helpers.USER, Helpers.PASSWORD) - assertNotEquals(authToken!!.length.toLong(), 0) - - val httpClient2 = HttpClient.Builder(null, null, authToken).build().okHttpClient - val journalAuthenticator2 = JournalAuthenticator(httpClient2!!, remote!!) - journalAuthenticator2.invalidateAuthToken(authToken) - } - - @Test(expected = Exceptions.UnauthorizedException::class) - @Throws(Exceptions.IntegrityException::class, Exceptions.VersionTooNewException::class, IOException::class, Exceptions.HttpException::class) - fun testNoUser() { - val journalAuthenticator = JournalAuthenticator(httpClient!!, remote!!) - val authToken = journalAuthenticator.getAuthToken(Helpers.USER, "BadPassword") - assertNotEquals(authToken!!.length.toLong(), 0) - } -} diff --git a/app/src/test/java/com/etesync/syncadapter/journalmanager/EncryptionTest.kt b/app/src/test/java/com/etesync/syncadapter/journalmanager/EncryptionTest.kt deleted file mode 100644 index 4e8e6aa3..00000000 --- a/app/src/test/java/com/etesync/syncadapter/journalmanager/EncryptionTest.kt +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright © 2013 – 2015 Ricki Hirner (bitfire web engineering). - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Public License v3.0 - * which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/gpl.html - */ - -package com.etesync.syncadapter.journalmanager - -import com.etesync.syncadapter.utils.Base64 -import org.junit.After -import org.junit.Assert.assertArrayEquals -import org.junit.Assert.assertEquals -import org.junit.Before -import org.junit.Test -import org.spongycastle.util.encoders.Hex -import java.io.IOException - -class EncryptionTest { - @Before - @Throws(IOException::class) - fun setUp() { - } - - @After - @Throws(IOException::class) - fun tearDown() { - } - - @Test - fun testDerivePassword() { - val key = Crypto.deriveKey(Helpers.USER, Helpers.PASSWORD) - assertEquals(key, Helpers.keyBase64) - } - - @Test - @Throws(Exceptions.IntegrityException::class, Exceptions.GenericCryptoException::class) - fun testCryptoV1() { - val cryptoManager = Crypto.CryptoManager(1, Helpers.keyBase64, "TestSaltShouldBeJournalId") - - val clearText = "This Is Some Test Cleartext." - val cipher = cryptoManager.encrypt(clearText.toByteArray()) - assertEquals(clearText, String(cryptoManager.decrypt(cipher!!)!!)) - - val expected = "Lz+HUFzh1HdjxuGdQrBwBG1IzHT0ug6mO8fwePSbXtc=" - assertEquals(expected, Base64.encodeToString(cryptoManager.hmac("Some test data".toByteArray()), Base64.NO_WRAP)) - } - - @Test - @Throws(Exceptions.IntegrityException::class, Exceptions.GenericCryptoException::class) - fun testCryptoV2() { - val cryptoManager = Crypto.CryptoManager(2, Helpers.keyBase64, "TestSaltShouldBeJournalId") - - val clearText = "This Is Some Test Cleartext." - val cipher = cryptoManager.encrypt(clearText.toByteArray()) - assertEquals(clearText, String(cryptoManager.decrypt(cipher!!)!!)) - - val expected = "XQ/A0gentOaE98R9wzf3zEIAHj4OH1GF8J4C6JiJupo=" - assertEquals(expected, Base64.encodeToString(cryptoManager.hmac("Some test data".toByteArray()), Base64.NO_WRAP)) - } - - @Test(expected = Exceptions.VersionTooNewException::class) - @Throws(Exceptions.IntegrityException::class, Exceptions.VersionTooNewException::class) - fun testCryptoVersionTooNew() { - Crypto.CryptoManager(120, Helpers.keyBase64, "TestSaltShouldBeJournalId") - } - - @Test(expected = Exceptions.IntegrityException::class) - @Throws(Exceptions.IntegrityException::class, Exceptions.VersionTooNewException::class) - fun testCryptoVersionOutOfRange() { - Crypto.CryptoManager(999, Helpers.keyBase64, "TestSaltShouldBeJournalId") - } - - @Test - @Throws(Exceptions.IntegrityException::class, Exceptions.GenericCryptoException::class) - fun testAsymCrypto() { - val keyPair = Crypto.generateKeyPair() - val cryptoManager = Crypto.AsymmetricCryptoManager(keyPair!!) - - val clearText = "This Is Some Test Cleartext.".toByteArray() - val cipher = cryptoManager.encrypt(keyPair.publicKey, clearText) - val clearText2 = cryptoManager.decrypt(cipher!!) - assertArrayEquals(clearText, clearText2) - - // Mostly for coverage. Make sure it's the expected sha256 value. - assertEquals("ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb", - Hex.toHexString(Crypto.AsymmetricCryptoManager.getKeyFingerprint("a".toByteArray())).toLowerCase()) - } -} diff --git a/app/src/test/java/com/etesync/syncadapter/journalmanager/Helpers.kt b/app/src/test/java/com/etesync/syncadapter/journalmanager/Helpers.kt deleted file mode 100644 index 53e49e5a..00000000 --- a/app/src/test/java/com/etesync/syncadapter/journalmanager/Helpers.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.etesync.syncadapter.journalmanager - -internal object Helpers { - val USER = "test@localhost" - val USER2 = "test2@localhost" - val PASSWORD = "SomePassword" - val keyBase64 = "Gpn6j6WJ/9JJbVkWhmEfZjlqSps5rwEOzjUOO0rqufvb4vtT4UfRgx0uMivuGwjF7/8Y1z1glIASX7Oz/4l2jucgf+lAzg2oTZFodWkXRZCDmFa7c9a8/04xIs7koFmUH34Rl9XXW6V2/GDVigQhQU8uWnrGo795tupoNQMbtB8RgMX5GyuxR55FvcybHpYBbwrDIsKvXcBxWFEscdNU8zyeq3yjvDo/W/y24dApW3mnNo7vswoL2rpkZj3dqw==" -} diff --git a/app/src/test/java/com/etesync/syncadapter/journalmanager/ServiceTest.kt b/app/src/test/java/com/etesync/syncadapter/journalmanager/ServiceTest.kt deleted file mode 100644 index c426c57a..00000000 --- a/app/src/test/java/com/etesync/syncadapter/journalmanager/ServiceTest.kt +++ /dev/null @@ -1,265 +0,0 @@ -/* - * Copyright © 2013 – 2015 Ricki Hirner (bitfire web engineering). - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Public License v3.0 - * which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/gpl.html - */ - -package com.etesync.syncadapter.journalmanager - -import com.etesync.syncadapter.App -import com.etesync.syncadapter.HttpClient -import com.etesync.syncadapter.model.CollectionInfo -import okhttp3.* -import okio.BufferedSink -import org.junit.After -import org.junit.Assert.* -import org.junit.Before -import org.junit.Test -import java.io.IOException -import java.util.* - -class ServiceTest { - private var httpClient: OkHttpClient? = null - private var remote: HttpUrl? = null - private var authToken: String? = null - - @Before - @Throws(Exception::class) - fun setUp() { - httpClient = HttpClient.Builder().build().okHttpClient - remote = HttpUrl.parse("http://localhost:8000") // FIXME: hardcode for now, should make configureable - val journalAuthenticator = JournalAuthenticator(httpClient!!, remote!!) - authToken = journalAuthenticator.getAuthToken(Helpers.USER, Helpers.PASSWORD) - - httpClient = HttpClient.Builder(null, null, authToken!!).build().okHttpClient - - /* Reset */ - val request = Request.Builder() - .post(object : RequestBody() { - override fun contentType(): MediaType? { - return null - } - - @Throws(IOException::class) - override fun writeTo(sink: BufferedSink) { - - } - }) - .url(remote!!.newBuilder().addEncodedPathSegments("reset/").build()) - .build() - val response = httpClient!!.newCall(request).execute() - if (!response.isSuccessful) { - throw Exception("Failed resetting") - } - } - - @After - @Throws(IOException::class) - fun tearDown() { - } - - @Test - @Throws(IOException::class, Exceptions.HttpException::class, Exceptions.GenericCryptoException::class, Exceptions.IntegrityException::class) - fun testSyncSimple() { - var caught: Exception? - val journalManager = JournalManager(httpClient!!, remote!!) - val info = CollectionInfo.defaultForServiceType(CollectionInfo.Type.ADDRESS_BOOK) - info.uid = JournalManager.Journal.genUid() - info.displayName = "Test" - val crypto = Crypto.CryptoManager(info.version, Helpers.keyBase64, info.uid!!) - var journal = JournalManager.Journal(crypto, info.toJson(), info.uid!!) - journalManager.create(journal) - - // Try pushing the same journal (uid clash) - try { - caught = null - journalManager.create(journal) - } catch (e: Exceptions.HttpException) { - caught = e - } - - assertNotNull(caught) - - var journals: List = journalManager.list() - assertEquals(journals.size.toLong(), 1) - var info2 = CollectionInfo.fromJson(journals[0].getContent(crypto)) - assertEquals(info2.displayName, info.displayName) - - // Update journal - info.displayName = "Test 2" - journal = JournalManager.Journal(crypto, info.toJson(), info.uid!!) - journalManager.update(journal) - - journals = journalManager.list() - assertEquals(journals.size.toLong(), 1) - info2 = CollectionInfo.fromJson(journals[0].getContent(crypto)) - assertEquals(info2.displayName, info.displayName) - - // Delete journal - journalManager.delete(journal) - - journals = journalManager.list() - assertEquals(journals.size.toLong(), 0) - - // Bad HMAC - info.uid = JournalManager.Journal.genUid() - journal = JournalManager.Journal(crypto, info.toJson(), info.uid!!) - info.displayName = "Test 3" - //// We assume this doesn't update the hmac. - journal.setContent(crypto, info.toJson()) - journalManager.create(journal) - - try { - caught = null - for (journal1 in journalManager.list()) { - val crypto1 = Crypto.CryptoManager(info.version, Helpers.keyBase64, journal1.uid!!) - journal1.verify(crypto1) - } - } catch (e: Exceptions.IntegrityException) { - caught = e - } - - assertNotNull(caught) - } - - - @Test - @Throws(IOException::class, Exceptions.HttpException::class, Exceptions.GenericCryptoException::class, Exceptions.IntegrityException::class) - fun testSyncEntry() { - var caught: Exception? - val journalManager = JournalManager(httpClient!!, remote!!) - val info = CollectionInfo.defaultForServiceType(CollectionInfo.Type.ADDRESS_BOOK) - info.uid = JournalManager.Journal.genUid() - info.displayName = "Test" - val crypto = Crypto.CryptoManager(info.version, Helpers.keyBase64, info.uid!!) - val journal = JournalManager.Journal(crypto, info.toJson(), info.uid!!) - journalManager.create(journal) - - val journalEntryManager = JournalEntryManager(httpClient!!, remote!!, info.uid!!) - var previousEntry: JournalEntryManager.Entry? = null - val entry = JournalEntryManager.Entry() - entry.update(crypto, "Content", previousEntry) - - var entries: MutableList = LinkedList() - var retEntries: List - - entries.add(entry) - journalEntryManager.create(entries, null) - previousEntry = entry - - entries.clear() - var entry2 = JournalEntryManager.Entry() - entry2.update(crypto, "Content", previousEntry) - entries.add(entry2) - - // Pushing a correct entries without the last parameter - try { - caught = null - journalEntryManager.create(entries, null) - } catch (e: Exceptions.HttpException) { - caught = e - } - - assertNotNull(caught) - - // Adding a second entry - journalEntryManager.create(entries, previousEntry.uid) - previousEntry = entry2 - - entries.clear() - entries.add(entry) - entries.add(entry2) - - // Check last works: - retEntries = journalEntryManager.list(crypto, entry.uid, 0) - assertEquals(retEntries.size.toLong(), 1) - retEntries = journalEntryManager.list(crypto, entry2.uid, 0) - assertEquals(retEntries.size.toLong(), 0) - - // Corrupt the journal and verify we catch it - entries.clear() - entry2 = JournalEntryManager.Entry() - entry2.update(crypto, "Content", null) - entries.add(entry2) - - journalEntryManager.create(entries, previousEntry.uid) - - try { - caught = null - journalEntryManager.list(crypto, null, 0) - } catch (e: Exceptions.IntegrityException) { - caught = e - } - - assertNotNull(caught) - } - - - @Test - @Throws(IOException::class, Exceptions.HttpException::class, Exceptions.GenericCryptoException::class, Exceptions.IntegrityException::class) - fun testUserInfo() { - val cryptoManager = Crypto.CryptoManager(Constants.CURRENT_VERSION, Helpers.keyBase64, "userInfo") - var userInfo: UserInfoManager.UserInfo? - var userInfo2: UserInfoManager.UserInfo? - val manager = UserInfoManager(httpClient!!, remote!!) - - // Get when there's nothing - userInfo = manager.fetch(Helpers.USER) - assertNull(userInfo) - - // Create - userInfo = UserInfoManager.UserInfo.generate(cryptoManager, Helpers.USER) - manager.create(userInfo) - - // Get - userInfo2 = manager.fetch(Helpers.USER) - assertNotNull(userInfo2) - assertArrayEquals(userInfo.getContent(cryptoManager), userInfo2!!.getContent(cryptoManager)) - - // Update - userInfo.setContent(cryptoManager, "test".toByteArray()) - manager.update(userInfo) - userInfo2 = manager.fetch(Helpers.USER) - assertNotNull(userInfo2) - assertArrayEquals(userInfo.getContent(cryptoManager), userInfo2!!.getContent(cryptoManager)) - - // Delete - manager.delete(userInfo) - userInfo = manager.fetch(Helpers.USER) - assertNull(userInfo) - } - - - @Test - @Throws(IOException::class, Exceptions.HttpException::class, Exceptions.GenericCryptoException::class, Exceptions.IntegrityException::class) - fun testJournalMember() { - val journalManager = JournalManager(httpClient!!, remote!!) - val info = CollectionInfo.defaultForServiceType(CollectionInfo.Type.ADDRESS_BOOK) - info.uid = JournalManager.Journal.genUid() - info.displayName = "Test" - val crypto = Crypto.CryptoManager(info.version, Helpers.keyBase64, info.uid!!) - val journal = JournalManager.Journal(crypto, info.toJson(), info.uid!!) - journalManager.create(journal) - - assertEquals(journalManager.listMembers(journal).size.toLong(), 0) - - // Test inviting ourselves - val member = JournalManager.Member(Helpers.USER, "test".toByteArray()) - journalManager.addMember(journal, member) - // We shouldn't show in the list - assertEquals(journalManager.listMembers(journal).size.toLong(), 0) - // Though we should have a key in the journal - assertNotNull(journalManager.list().first().key) - - val member2 = JournalManager.Member(Helpers.USER2, "test".toByteArray()) - journalManager.addMember(journal, member2) - assertEquals(journalManager.listMembers(journal).size.toLong(), 1) - - // Uninviting user - journalManager.deleteMember(journal, member2) - - assertEquals(journalManager.listMembers(journal).size.toLong(), 0) - } -}