From bc5bf155a2b328cbb169dc64049605036fc01748 Mon Sep 17 00:00:00 2001
From: Kamal Bramwell <kamal@elixxir.io>
Date: Fri, 2 Dec 2022 09:08:30 -0500
Subject: [PATCH] Added Crust backup/restore data source

---
 .../messenger/backup/cloud/crust/Crust.kt     | 88 +++++++++++++++++++
 .../backup/cloud/crust/CrustDataSource.kt     | 31 +++++++
 .../backup/data/BackupLocationRepository.kt   | 10 ++-
 .../messenger/backup/data/BackupSource.kt     |  2 +-
 .../backup/data/backup/BackupMediator.kt      |  1 +
 .../backup/BackupPreferencesRepository.kt     |  1 +
 .../repository/PreferencesRepository.kt       |  7 ++
 7 files changed, 138 insertions(+), 2 deletions(-)
 create mode 100644 app/src/main/java/io/xxlabs/messenger/backup/cloud/crust/Crust.kt
 create mode 100644 app/src/main/java/io/xxlabs/messenger/backup/cloud/crust/CrustDataSource.kt

diff --git a/app/src/main/java/io/xxlabs/messenger/backup/cloud/crust/Crust.kt b/app/src/main/java/io/xxlabs/messenger/backup/cloud/crust/Crust.kt
new file mode 100644
index 00000000..ebfd9cda
--- /dev/null
+++ b/app/src/main/java/io/xxlabs/messenger/backup/cloud/crust/Crust.kt
@@ -0,0 +1,88 @@
+package io.xxlabs.messenger.backup.cloud.crust
+
+import io.xxlabs.messenger.R
+import io.xxlabs.messenger.backup.bindings.AccountArchive
+import io.xxlabs.messenger.backup.bindings.BackupService
+import io.xxlabs.messenger.backup.cloud.CloudStorage
+import io.xxlabs.messenger.backup.data.backup.BackupPreferencesRepository
+import io.xxlabs.messenger.backup.data.restore.RestoreEnvironment
+import io.xxlabs.messenger.backup.model.BackupLocation
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+
+/**
+ * Encapsulates Crust storage API.
+ */
+class Crust private constructor(
+    private val backupService: BackupService,
+    private val preferences: BackupPreferencesRepository,
+    private val crustApi: CrustDataSource
+) : CloudStorage(backupService) {
+
+    private var cachedBackupData: AccountArchive? = null
+
+    override val location: BackupLocation = BackupLocationData(
+        R.drawable.ic_sftp,
+        "Crust",
+        ::signInRequired,
+        ::authBackgroundsApp,
+        ::signOut,
+        ::isEnabled
+    ) {
+        null
+    }
+
+    private fun signInRequired(): Boolean = false
+
+    private fun authBackgroundsApp() = false
+
+    private fun signOut() {}
+
+    override fun onAuthResultSuccess() {
+        scope.launch {
+            fetchData()
+            withContext(Dispatchers.Main) {
+                _authResultCallback?.onSuccess()
+            }
+        }
+    }
+
+    private suspend fun fetchData() {
+        cachedBackupData = crustApi.recoverBackup("").getOrNull()?.let {
+            AccountArchive(it)
+        }
+    }
+
+    override suspend fun onRestore(environment: RestoreEnvironment) {
+        updateProgress(25)
+        cachedBackupData?.restoreUsing(environment)
+    }
+
+    override fun isEnabled(): Boolean {
+        return preferences.isCrustEnabled
+    }
+
+    override fun backupNow() {
+        if (isEnabled()) backup()
+    }
+
+    private fun backup() {
+        scope.launch {
+            updateProgress()
+            crustApi.uploadBackup(backupService.backupFilePath)
+            updateProgress(25)
+        }
+    }
+
+    companion object {
+        @Volatile
+        private var instance: Crust? = null
+
+        fun getInstance(
+            backupService: BackupService,
+            preferences: BackupPreferencesRepository,
+            crustApi: CrustDataSource
+        ): Crust = instance ?: Crust(backupService, preferences, crustApi)
+    }
+}
\ No newline at end of file
diff --git a/app/src/main/java/io/xxlabs/messenger/backup/cloud/crust/CrustDataSource.kt b/app/src/main/java/io/xxlabs/messenger/backup/cloud/crust/CrustDataSource.kt
new file mode 100644
index 00000000..2ffbad53
--- /dev/null
+++ b/app/src/main/java/io/xxlabs/messenger/backup/cloud/crust/CrustDataSource.kt
@@ -0,0 +1,31 @@
+package io.xxlabs.messenger.backup.cloud.crust
+
+import bindings.Bindings
+import bindings.UserDiscovery
+
+interface CrustDataSource {
+    suspend fun uploadBackup(path: String): ByteArray
+    suspend fun recoverBackup(username: String): Result<ByteArray>
+}
+
+class BindingsCrustMediator(
+    var udManager: UserDiscovery? = null,
+    var receptionRsaPrivateKey: ByteArray = byteArrayOf()
+) : CrustDataSource {
+
+
+    override suspend fun uploadBackup(path: String): ByteArray {
+        return udManager?.let {
+            Bindings.uploadBackup(path, udManager, receptionRsaPrivateKey)
+        } ?: byteArrayOf()
+    }
+
+    override suspend fun recoverBackup(username: String): Result<ByteArray> {
+        return try {
+            val backupData = Bindings.recoverBackup(username)
+            Result.success(backupData)
+        } catch (e: Exception) {
+            Result.failure(e)
+        }
+    }
+}
\ No newline at end of file
diff --git a/app/src/main/java/io/xxlabs/messenger/backup/data/BackupLocationRepository.kt b/app/src/main/java/io/xxlabs/messenger/backup/data/BackupLocationRepository.kt
index f307ca2a..8cddcfce 100644
--- a/app/src/main/java/io/xxlabs/messenger/backup/data/BackupLocationRepository.kt
+++ b/app/src/main/java/io/xxlabs/messenger/backup/data/BackupLocationRepository.kt
@@ -1,6 +1,8 @@
 package io.xxlabs.messenger.backup.data
 
 import io.xxlabs.messenger.backup.bindings.BackupService
+import io.xxlabs.messenger.backup.cloud.crust.BindingsCrustMediator
+import io.xxlabs.messenger.backup.cloud.crust.Crust
 import io.xxlabs.messenger.backup.cloud.drive.GoogleDrive
 import io.xxlabs.messenger.backup.cloud.dropbox.Dropbox
 import io.xxlabs.messenger.backup.cloud.sftp.transfer.Sftp
@@ -12,14 +14,18 @@ abstract class BackupLocationRepository(
     backupService: BackupService,
 ) : AccountBackupDataSource {
 
+    private val crustApi = BindingsCrustMediator()
+
     protected val googleDrive = GoogleDrive.getInstance(backupService, preferences)
     protected val dropbox = Dropbox.getInstance(backupService, preferences)
     protected val sftp = Sftp.getInstance(backupService, preferences)
+    protected val crust = Crust.getInstance(backupService, preferences, crustApi)
 
     override val locations: List<AccountBackup> = listOf(
         googleDrive,
         dropbox,
-        sftp
+        sftp,
+        crust
     )
 
     override fun getBackupFrom(source: BackupSource): AccountBackup =
@@ -27,6 +33,7 @@ abstract class BackupLocationRepository(
             BackupSource.DRIVE -> googleDrive
             BackupSource.DROPBOX -> dropbox
             BackupSource.SFTP -> sftp
+            BackupSource.CRUST -> crust
         }
 
     override fun getSourceFor(backup: AccountBackup): BackupSource? =
@@ -34,6 +41,7 @@ abstract class BackupLocationRepository(
             is GoogleDrive -> BackupSource.DRIVE
             is Dropbox -> BackupSource.DROPBOX
             is Sftp -> BackupSource.SFTP
+            is Crust -> BackupSource.CRUST
             else -> null
         }
 }
\ No newline at end of file
diff --git a/app/src/main/java/io/xxlabs/messenger/backup/data/BackupSource.kt b/app/src/main/java/io/xxlabs/messenger/backup/data/BackupSource.kt
index 8bf3bcdc..7cb9bf5f 100644
--- a/app/src/main/java/io/xxlabs/messenger/backup/data/BackupSource.kt
+++ b/app/src/main/java/io/xxlabs/messenger/backup/data/BackupSource.kt
@@ -2,4 +2,4 @@ package io.xxlabs.messenger.backup.data
 
 import java.io.Serializable
 
-enum class BackupSource : Serializable { DRIVE, DROPBOX, SFTP }
\ No newline at end of file
+enum class BackupSource : Serializable { DRIVE, DROPBOX, SFTP, CRUST }
\ No newline at end of file
diff --git a/app/src/main/java/io/xxlabs/messenger/backup/data/backup/BackupMediator.kt b/app/src/main/java/io/xxlabs/messenger/backup/data/backup/BackupMediator.kt
index 86099fbf..fa696e60 100644
--- a/app/src/main/java/io/xxlabs/messenger/backup/data/backup/BackupMediator.kt
+++ b/app/src/main/java/io/xxlabs/messenger/backup/data/backup/BackupMediator.kt
@@ -24,6 +24,7 @@ class BackupMediator @Inject constructor(
             googleDrive.location.name -> googleDrive
             dropbox.location.name -> dropbox
             sftp.location.name -> sftp
+            crust.location.name -> crust
             else -> null
         }
 
diff --git a/app/src/main/java/io/xxlabs/messenger/backup/data/backup/BackupPreferencesRepository.kt b/app/src/main/java/io/xxlabs/messenger/backup/data/backup/BackupPreferencesRepository.kt
index 23cfcaaf..e4325468 100644
--- a/app/src/main/java/io/xxlabs/messenger/backup/data/backup/BackupPreferencesRepository.kt
+++ b/app/src/main/java/io/xxlabs/messenger/backup/data/backup/BackupPreferencesRepository.kt
@@ -5,6 +5,7 @@ interface BackupPreferencesRepository {
     var isGoogleDriveEnabled: Boolean
     var isDropboxEnabled: Boolean
     var isSftpEnabled: Boolean
+    var isCrustEnabled: Boolean
     var backupPassword: String?
     var autoBackup: Boolean
     var wiFiOnlyBackup: Boolean
diff --git a/app/src/main/java/io/xxlabs/messenger/repository/PreferencesRepository.kt b/app/src/main/java/io/xxlabs/messenger/repository/PreferencesRepository.kt
index e7b1b1a9..c25e36ab 100644
--- a/app/src/main/java/io/xxlabs/messenger/repository/PreferencesRepository.kt
+++ b/app/src/main/java/io/xxlabs/messenger/repository/PreferencesRepository.kt
@@ -245,6 +245,13 @@ class PreferencesRepository @Inject constructor(
             preferences.edit().putBoolean("sftp_enabled", value).apply()
         }
 
+    override var isCrustEnabled: Boolean = preferences.getBoolean("crust_enabled", false)
+        get() = preferences.getBoolean("crust_enabled", false)
+        set(value) {
+            field = value
+            preferences.edit().putBoolean("crust_enabled", value).apply()
+        }
+
     override var backupPassword: String? = preferences.getString("backup_pw", null)
         get() = preferences.getString("backup_pw", null)
         set(value) {
-- 
GitLab