diff --git a/README.md b/README.md index 4fe59c8d..3d5697d7 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ Then add the following dependency to your module's build.gradle ```gradle dependencies { ... - implementation "com.metallicus:protonsdk:0.5.3" + implementation "com.metallicus:protonsdk:0.5.4" } ``` diff --git a/buildSrc/src/main/kotlin/Dependencies.kt b/buildSrc/src/main/kotlin/Dependencies.kt index a77553d0..7a267906 100644 --- a/buildSrc/src/main/kotlin/Dependencies.kt +++ b/buildSrc/src/main/kotlin/Dependencies.kt @@ -23,8 +23,8 @@ const val kotlinVersion = "1.3.72" const val orchidVersion = "0.21.1" object ProtonSdk { - const val versionCode = 15 - const val versionName = "0.5.3" + const val versionCode = 16 + const val versionName = "0.5.4" } object BuildPlugins { diff --git a/protonsdk/src/main/java/com/metallicus/protonsdk/AccountModule.kt b/protonsdk/src/main/java/com/metallicus/protonsdk/AccountModule.kt index 0495e5a9..7e825a79 100644 --- a/protonsdk/src/main/java/com/metallicus/protonsdk/AccountModule.kt +++ b/protonsdk/src/main/java/com/metallicus/protonsdk/AccountModule.kt @@ -22,6 +22,7 @@ package com.metallicus.protonsdk import android.content.Context +import android.util.Base64 import com.metallicus.protonsdk.common.SecureKeys import com.metallicus.protonsdk.common.Prefs import com.metallicus.protonsdk.common.Resource @@ -58,8 +59,8 @@ class AccountModule { DaggerInjector.component.inject(this) } - fun hasActiveAccount(): Boolean { - return prefs.getActiveAccountName().isNotEmpty() + fun getActiveAccountName(): String { + return prefs.getActiveAccountName() } suspend fun accountAvailable(chainUrl: String, accountName: String): Boolean { @@ -105,6 +106,18 @@ class AccountModule { } } + fun hasPrivateKeys(): Boolean { + return secureKeys.hasKeys() + } + + fun resetPrivateKeys(oldPin: String, newPin: String): Boolean { + return secureKeys.resetKeys(oldPin, newPin) + } + + fun isPinValid(pin: String): Boolean { + return secureKeys.checkPin(pin) + } + private suspend fun fetchAccountContact(chainUrl: String, accountName: String): AccountContact { val accountContact = AccountContact(accountName) accountContact.accountName = accountName @@ -216,6 +229,11 @@ class AccountModule { } } + fun getActiveAccountPrivateKey(pin: String): String { + val publicKey = prefs.getActivePublicKey() + return secureKeys.getPrivateKey(publicKey, pin).orEmpty() + } + private fun getActiveAccountSignature(pin: String): String { val accountName = prefs.getActiveAccountName() val publicKey = prefs.getActivePublicKey() @@ -233,7 +251,7 @@ class AccountModule { val accountName = chainAccount.account.accountName val updateAccountNameUrl = - chainAccount.chainProvider.chainUrl + chainAccount.chainProvider.updateAccountNamePath + chainAccount.chainProvider.chainApiUrl + chainAccount.chainProvider.updateAccountNamePath val response = accountRepository.updateAccountName( updateAccountNameUrl, @@ -264,7 +282,7 @@ class AccountModule { val accountName = chainAccount.account.accountName val updateAccountAvatarUrl = - chainAccount.chainProvider.chainUrl + chainAccount.chainProvider.updateAccountAvatarPath + chainAccount.chainProvider.chainApiUrl + chainAccount.chainProvider.updateAccountAvatarPath val response = accountRepository.updateAccountAvatar( updateAccountAvatarUrl, @@ -274,7 +292,7 @@ class AccountModule { return if (response.isSuccessful) { val account = chainAccount.account - account.accountContact.avatar = imageByteArray.toString(Charset.defaultCharset()) + account.accountContact.avatar = Base64.encodeToString(imageByteArray, Base64.DEFAULT) accountRepository.updateAccount(account) Resource.success(chainAccount) diff --git a/protonsdk/src/main/java/com/metallicus/protonsdk/ActionsModule.kt b/protonsdk/src/main/java/com/metallicus/protonsdk/ActionsModule.kt index 17e6319b..79de8c4a 100644 --- a/protonsdk/src/main/java/com/metallicus/protonsdk/ActionsModule.kt +++ b/protonsdk/src/main/java/com/metallicus/protonsdk/ActionsModule.kt @@ -249,9 +249,9 @@ class ActionsModule { if (pushTransactionResponse.isSuccessful) { Resource.success(pushTransactionResponse.body()) } else { - val msg = jsonToBinResponse.errorBody()?.string() + val msg = pushTransactionResponse.errorBody()?.string() val errorMsg = if (msg.isNullOrEmpty()) { - jsonToBinResponse.message() + pushTransactionResponse.message() } else { msg } @@ -259,9 +259,9 @@ class ActionsModule { Resource.error(errorMsg) } } else { - val msg = jsonToBinResponse.errorBody()?.string() + val msg = chainInfoResponse.errorBody()?.string() val errorMsg = if (msg.isNullOrEmpty()) { - jsonToBinResponse.message() + chainInfoResponse.message() } else { msg } diff --git a/protonsdk/src/main/java/com/metallicus/protonsdk/Proton.kt b/protonsdk/src/main/java/com/metallicus/protonsdk/Proton.kt index d1367ce2..7ed6b00c 100644 --- a/protonsdk/src/main/java/com/metallicus/protonsdk/Proton.kt +++ b/protonsdk/src/main/java/com/metallicus/protonsdk/Proton.kt @@ -145,6 +145,18 @@ class Proton private constructor(context: Context) { } catch (e: Exception) { "" } } + fun hasPrivateKeys(): Boolean { + return accountModule.hasPrivateKeys() + } + + fun resetPrivateKeys(oldPin: String, newPin: String): Boolean { + return accountModule.resetPrivateKeys(oldPin, newPin) + } + + fun isPinValid(pin: String): Boolean { + return accountModule.isPinValid(pin) + } + fun accountAvailable(accountName: String): LiveData> = liveData { emit(Resource.loading()) @@ -197,8 +209,12 @@ class Proton private constructor(context: Context) { } } + fun getActiveAccountName(): String { + return accountModule.getActiveAccountName() + } + fun hasActiveAccount(): Boolean { - return accountModule.hasActiveAccount() + return getActiveAccountName().isNotEmpty() } fun setActiveAccount(activeAccount: ActiveAccount): LiveData> = liveData { @@ -214,6 +230,10 @@ class Proton private constructor(context: Context) { } } + fun getActiveAccountPrivateKey(pin: String): String { + return accountModule.getActiveAccountPrivateKey(pin) + } + private suspend fun getActiveAccountAsync() = suspendCoroutine { continuation -> workersModule.onInitActiveAccount { success, data -> if (success) { @@ -268,7 +288,7 @@ class Proton private constructor(context: Context) { } val exchangeRateUrl = - activeAccount.chainProvider.chainUrl + activeAccount.chainProvider.exchangeRatePath + activeAccount.chainProvider.chainApiUrl + activeAccount.chainProvider.exchangeRatePath tokenContractsModule.updateExchangeRates(exchangeRateUrl, tokenContractsMap) @@ -358,16 +378,18 @@ class Proton private constructor(context: Context) { } } - fun transferTokens(pin: String, contract: String, toAccount: String, amount: String, memo: String): LiveData> = liveData { + fun transferTokens(pin: String, tokenContractId: String, toAccount: String, amount: String, memo: String): LiveData> = liveData { emit(Resource.loading()) try { val activeAccount = getActiveAccountAsync() + val tokenContract = tokenContractsModule.getTokenContract(tokenContractId) + emit(actionsModule.transferTokens( activeAccount.chainProvider.chainUrl, pin, - contract, + tokenContract.contract, activeAccount.account.accountName, toAccount, amount, diff --git a/protonsdk/src/main/java/com/metallicus/protonsdk/common/SecureKeys.kt b/protonsdk/src/main/java/com/metallicus/protonsdk/common/SecureKeys.kt index 9c87e7df..662e6981 100644 --- a/protonsdk/src/main/java/com/metallicus/protonsdk/common/SecureKeys.kt +++ b/protonsdk/src/main/java/com/metallicus/protonsdk/common/SecureKeys.kt @@ -22,6 +22,7 @@ package com.metallicus.protonsdk.common import android.content.Context +import com.metallicus.protonsdk.eosio.commander.ec.EosPrivateKey import com.metallicus.protonsdk.securestorage.SecurePreferences import com.metallicus.protonsdk.securestorage.SecureStorageException import timber.log.Timber @@ -39,6 +40,41 @@ class SecureKeys(private val context: Context) { return securePrefs.all.isNotEmpty() } + fun checkPin(pin: String): Boolean { + var isValid = false + SecurePreferences.setSharedPreferencesName(SHARED_PREFS_FILENAME) + val securePrefs = SecurePreferences.getSharedPreferences(context) + if (securePrefs.all.isNotEmpty()) { + isValid = try { + val firstAccount = securePrefs.all.entries.iterator().next() + val publicKey = firstAccount.key + val privateKey = SecurePreferences.getStringValue(context, publicKey, pin, "") + EosPrivateKey(privateKey).publicKey.toString() == publicKey + } catch (e: Exception) { + false + } + } + return isValid + } + + fun resetKeys(oldPin: String, newPin: String): Boolean { + return try { + SecurePreferences.setSharedPreferencesName(SHARED_PREFS_FILENAME) + val securePrefs = SecurePreferences.getSharedPreferences(context) + securePrefs.all.forEach { secureKey -> + val publicKey = secureKey.key + val privateKey = SecurePreferences.getStringValue(context, publicKey, oldPin, "") + privateKey?.let { + SecurePreferences.setValue(context, publicKey, it, newPin) + } + } + true + } catch (e: SecureStorageException) { + Timber.d(e) + false + } + } + fun keyExists(publicKey: String): Boolean { SecurePreferences.setSharedPreferencesName(SHARED_PREFS_FILENAME) return SecurePreferences.contains(context, publicKey) diff --git a/protonsdk/src/main/java/com/metallicus/protonsdk/db/ProtonDb.kt b/protonsdk/src/main/java/com/metallicus/protonsdk/db/ProtonDb.kt index 35258709..999b4878 100755 --- a/protonsdk/src/main/java/com/metallicus/protonsdk/db/ProtonDb.kt +++ b/protonsdk/src/main/java/com/metallicus/protonsdk/db/ProtonDb.kt @@ -33,7 +33,7 @@ import com.metallicus.protonsdk.model.* AccountContact::class, CurrencyBalance::class, Action::class], - version = 16, + version = 17, exportSchema = false ) abstract class ProtonDb : RoomDatabase() { diff --git a/protonsdk/src/main/java/com/metallicus/protonsdk/model/Action.kt b/protonsdk/src/main/java/com/metallicus/protonsdk/model/Action.kt index 9e99fd42..3cf88b59 100644 --- a/protonsdk/src/main/java/com/metallicus/protonsdk/model/Action.kt +++ b/protonsdk/src/main/java/com/metallicus/protonsdk/model/Action.kt @@ -53,8 +53,6 @@ data class Action( lateinit var accountContact: AccountContact - enum class IconType { AVATAR, SEND, RECEIVE, STAKE, UNSTAKE, BUY_RAM } - fun isTransfer(): Boolean { return (actionTrace.act.name == "transfer") } @@ -63,26 +61,6 @@ data class Action( return (accountName == actionTrace.act.data?.from && actionTrace.act.data.from != actionTrace.act.data.to) } - fun getIconType(): IconType { - return IconType.AVATAR - -// return if (accountContact.isLynxChain) { -// IconType.AVATAR -// } else { -// if (actionTrace.act.data?.to == "eosio.ramfee" || actionTrace.act.data?.to == "eosio.ram") { -// IconType.BUY_RAM -// } else if (actionTrace.act.data?.to == "eosio.stake") { -// IconType.STAKE -// } else if (actionTrace.act.data?.from == "eosio.stake") { -// IconType.UNSTAKE -// } else if (!isSender()) { -// IconType.RECEIVE -// } else { -// IconType.SEND -// } -// } - } - fun getDisplayName(): String { return when { actionTrace.act.data?.to == "eosio.ramfee" -> "Buy RAM Fee" diff --git a/protonsdk/src/main/java/com/metallicus/protonsdk/model/ChainProvider.kt b/protonsdk/src/main/java/com/metallicus/protonsdk/model/ChainProvider.kt index 6a5c2e55..17922d85 100644 --- a/protonsdk/src/main/java/com/metallicus/protonsdk/model/ChainProvider.kt +++ b/protonsdk/src/main/java/com/metallicus/protonsdk/model/ChainProvider.kt @@ -49,4 +49,6 @@ data class ChainProvider( @SerializedName("updateAccountAvatarPath") val updateAccountAvatarPath: String, @SerializedName("updateAccountNamePath") val updateAccountNamePath: String, @SerializedName("exchangeRatePath") val exchangeRatePath: String -) \ No newline at end of file +) { + lateinit var chainApiUrl: String +} \ No newline at end of file diff --git a/protonsdk/src/main/java/com/metallicus/protonsdk/repository/ActionRepository.kt b/protonsdk/src/main/java/com/metallicus/protonsdk/repository/ActionRepository.kt index dd4b2021..d45131e9 100755 --- a/protonsdk/src/main/java/com/metallicus/protonsdk/repository/ActionRepository.kt +++ b/protonsdk/src/main/java/com/metallicus/protonsdk/repository/ActionRepository.kt @@ -61,7 +61,7 @@ class ActionRepository @Inject constructor( } suspend fun getChainInfo(chainUrl: String): Response { - return protonChainService.getChainInfo(chainUrl) + return protonChainService.getChainInfo("$chainUrl/v1/chain/get_info") } suspend fun getRequiredKeys(chainUrl: String, requiredKeysBody: RequiredKeysBody): Response { diff --git a/protonsdk/src/main/java/com/metallicus/protonsdk/workers/InitChainProviderWorker.kt b/protonsdk/src/main/java/com/metallicus/protonsdk/workers/InitChainProviderWorker.kt index 773c2fe6..03130c84 100644 --- a/protonsdk/src/main/java/com/metallicus/protonsdk/workers/InitChainProviderWorker.kt +++ b/protonsdk/src/main/java/com/metallicus/protonsdk/workers/InitChainProviderWorker.kt @@ -55,6 +55,7 @@ class InitChainProviderWorker chainProviderRepository.removeAll() val chainProvider = Gson().fromJson(response.body(), ChainProvider::class.java) + chainProvider.chainApiUrl = protonChainUrl chainProviderRepository.addChainProvider(chainProvider) diff --git a/protonsdk/src/main/java/com/metallicus/protonsdk/workers/UpdateTokenContractRatesWorker.kt b/protonsdk/src/main/java/com/metallicus/protonsdk/workers/UpdateTokenContractRatesWorker.kt index 582325bb..e26540f5 100644 --- a/protonsdk/src/main/java/com/metallicus/protonsdk/workers/UpdateTokenContractRatesWorker.kt +++ b/protonsdk/src/main/java/com/metallicus/protonsdk/workers/UpdateTokenContractRatesWorker.kt @@ -52,7 +52,7 @@ class UpdateTokenContractRatesWorker tokenContractsMap["${it.contract}:${it.getSymbol()}"] = it.id } - val exchangeRateUrl = chainProvider.chainUrl + chainProvider.exchangeRatePath + val exchangeRateUrl = chainProvider.chainApiUrl + chainProvider.exchangeRatePath val exchangeRatesResponse = tokenContractRepository.fetchExchangeRates(exchangeRateUrl) if (exchangeRatesResponse.isSuccessful) {