|
|
/*
|
|
|
* Copyright © 2013 – 2016 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.ui
|
|
|
|
|
|
import android.accounts.Account
|
|
|
import android.app.ProgressDialog
|
|
|
import android.content.Context
|
|
|
import android.content.Intent
|
|
|
import android.os.Bundle
|
|
|
import android.view.View
|
|
|
import androidx.appcompat.app.AlertDialog
|
|
|
import com.etebase.client.Client
|
|
|
import com.etesync.syncadapter.AccountSettings
|
|
|
import com.etesync.syncadapter.HttpClient
|
|
|
import com.etesync.syncadapter.R
|
|
|
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
|
|
|
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
|
|
import org.jetbrains.anko.doAsync
|
|
|
import org.jetbrains.anko.uiThread
|
|
|
import java.util.*
|
|
|
|
|
|
open class ChangeEncryptionPasswordActivity : BaseActivity() {
|
|
|
|
|
|
protected lateinit var account: Account
|
|
|
lateinit var progress: ProgressDialog
|
|
|
|
|
|
override fun onCreate(savedInstanceState: Bundle?) {
|
|
|
super.onCreate(savedInstanceState)
|
|
|
|
|
|
account = intent.extras!!.getParcelable(EXTRA_ACCOUNT)!!
|
|
|
|
|
|
supportActionBar!!.setDisplayHomeAsUpEnabled(true)
|
|
|
|
|
|
setContentView(R.layout.change_encryption_password)
|
|
|
}
|
|
|
|
|
|
fun onCancelClicked(v: View) {
|
|
|
finish()
|
|
|
}
|
|
|
|
|
|
fun changePasswordError(e: Exception) {
|
|
|
progress.dismiss()
|
|
|
AlertDialog.Builder(this)
|
|
|
.setTitle(R.string.wrong_encryption_password)
|
|
|
.setIcon(R.drawable.ic_error_dark)
|
|
|
.setMessage(e.localizedMessage)
|
|
|
.setPositiveButton(android.R.string.ok) { _, _ ->
|
|
|
// dismiss
|
|
|
}.show()
|
|
|
}
|
|
|
|
|
|
fun changePasswordDo(old_password: String, new_password: String) {
|
|
|
val settings = AccountSettings(this, account)
|
|
|
|
|
|
if (settings.isLegacy) {
|
|
|
legacyChangePasswordDo(settings, old_password, new_password)
|
|
|
return
|
|
|
}
|
|
|
|
|
|
doAsync {
|
|
|
val httpClient = HttpClient.Builder(this@ChangeEncryptionPasswordActivity).setForeground(true).build().okHttpClient
|
|
|
|
|
|
try {
|
|
|
Logger.log.info("Loging in with old password")
|
|
|
val client = Client.create(httpClient, settings.uri?.toString())
|
|
|
val etebase = com.etebase.client.Account.login(client, account.name, old_password)
|
|
|
Logger.log.info("Login successful")
|
|
|
|
|
|
etebase.changePassword(new_password)
|
|
|
|
|
|
settings.etebaseSession = etebase.save(null)
|
|
|
|
|
|
uiThread {
|
|
|
progress.dismiss()
|
|
|
AlertDialog.Builder(this@ChangeEncryptionPasswordActivity)
|
|
|
.setTitle(R.string.change_encryption_password_success_title)
|
|
|
.setMessage(R.string.change_encryption_password_success_body)
|
|
|
.setPositiveButton(android.R.string.ok) { _, _ ->
|
|
|
this@ChangeEncryptionPasswordActivity.finish()
|
|
|
}.show()
|
|
|
|
|
|
requestSync(applicationContext, account)
|
|
|
}
|
|
|
} catch (e: Exception) {
|
|
|
uiThread {
|
|
|
changePasswordError(e)
|
|
|
}
|
|
|
return@doAsync
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
fun legacyChangePasswordDo(settings: AccountSettings, old_password: String, new_password: String) {
|
|
|
doAsync {
|
|
|
val httpClient = HttpClient.Builder(this@ChangeEncryptionPasswordActivity, settings).setForeground(false).build().okHttpClient
|
|
|
|
|
|
Logger.log.info("Started deriving old key")
|
|
|
val old_key = Crypto.deriveKey(account.name, old_password)
|
|
|
Logger.log.info("Finished deriving old key")
|
|
|
|
|
|
var cryptoManager: Crypto.CryptoManager
|
|
|
val principal = settings.uri?.toHttpUrlOrNull()!!
|
|
|
|
|
|
try {
|
|
|
val userInfoManager = UserInfoManager(httpClient, principal)
|
|
|
val userInfo = userInfoManager.fetch(account.name)!!
|
|
|
Logger.log.info("Fetched userInfo for " + account.name)
|
|
|
cryptoManager = Crypto.CryptoManager(userInfo.version!!.toInt(), old_key, "userInfo")
|
|
|
userInfo.verify(cryptoManager)
|
|
|
|
|
|
Logger.log.info("Started deriving new key")
|
|
|
val new_key = Crypto.deriveKey(account.name, new_password)
|
|
|
Logger.log.info("Finished deriving new key")
|
|
|
|
|
|
val userInfoContent = userInfo.getContent(cryptoManager)!!
|
|
|
cryptoManager = Crypto.CryptoManager(userInfo.version!!.toInt(), new_key, "userInfo")
|
|
|
userInfo.setContent(cryptoManager, userInfoContent)
|
|
|
|
|
|
Logger.log.info("Fetching journal list")
|
|
|
val membersToAdd = LinkedList<Pair<JournalManager.Journal, ByteArray?>>()
|
|
|
val journalManager = JournalManager(httpClient, principal)
|
|
|
val journals = journalManager.list()
|
|
|
for (journal in journals) {
|
|
|
if (journal.owner != account.name) {
|
|
|
continue
|
|
|
}
|
|
|
|
|
|
if (journal.key != null) {
|
|
|
// We don't need to handle those cases, as they are already encrypted using pubkey
|
|
|
continue
|
|
|
} else {
|
|
|
cryptoManager = Crypto.CryptoManager(journal.version, old_key, journal.uid!!)
|
|
|
}
|
|
|
|
|
|
Logger.log.info("Converting journal ${journal.uid}")
|
|
|
journal.verify(cryptoManager)
|
|
|
|
|
|
membersToAdd.add(Pair(journal, cryptoManager.getEncryptedKey(settings.keyPair!!, userInfo.pubkey!!)))
|
|
|
}
|
|
|
|
|
|
Logger.log.info("Finished converting account. Uploading changes")
|
|
|
userInfoManager.update(userInfo)
|
|
|
|
|
|
for ((journal, encryptedKey) in membersToAdd) {
|
|
|
if (journal.owner != account.name) {
|
|
|
continue
|
|
|
}
|
|
|
|
|
|
Logger.log.info("Uploading journal ${journal.uid}")
|
|
|
val member = JournalManager.Member(account.name, encryptedKey!!)
|
|
|
journalManager.addMember(journal, member)
|
|
|
}
|
|
|
|
|
|
settings.password(new_key)
|
|
|
Logger.log.info("Finished uploading changes. Encryption password changed successfully.")
|
|
|
|
|
|
uiThread {
|
|
|
progress.dismiss()
|
|
|
AlertDialog.Builder(this@ChangeEncryptionPasswordActivity)
|
|
|
.setTitle(R.string.change_encryption_password_success_title)
|
|
|
.setMessage(R.string.change_encryption_password_success_body)
|
|
|
.setPositiveButton(android.R.string.ok) { _, _ ->
|
|
|
this@ChangeEncryptionPasswordActivity.finish()
|
|
|
}.show()
|
|
|
|
|
|
requestSync(applicationContext, account)
|
|
|
}
|
|
|
} catch (e: Exception) {
|
|
|
uiThread {
|
|
|
changePasswordError(e)
|
|
|
}
|
|
|
return@doAsync
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
fun changePasswordClicked(v: View) {
|
|
|
val old_password_view = findViewById<TextInputLayout>(R.id.encryption_password)
|
|
|
val new_password_view = findViewById<TextInputLayout>(R.id.new_encryption_password)
|
|
|
|
|
|
var valid = true
|
|
|
val old_password = old_password_view.editText?.text.toString()
|
|
|
if (old_password.isEmpty()) {
|
|
|
old_password_view.error = getString(R.string.login_password_required)
|
|
|
valid = false
|
|
|
} else {
|
|
|
old_password_view.error = null
|
|
|
}
|
|
|
val new_password = new_password_view.editText?.text.toString()
|
|
|
if (new_password.isEmpty()) {
|
|
|
new_password_view.error = getString(R.string.login_password_required)
|
|
|
valid = false
|
|
|
} else {
|
|
|
new_password_view.error = null
|
|
|
}
|
|
|
|
|
|
if (!valid) {
|
|
|
return
|
|
|
}
|
|
|
|
|
|
AlertDialog.Builder(this)
|
|
|
.setTitle(R.string.delete_collection_confirm_title)
|
|
|
.setMessage(R.string.change_encryption_password_are_you_sure)
|
|
|
.setPositiveButton(android.R.string.yes) { _, _ ->
|
|
|
changePasswordDo(old_password, new_password)
|
|
|
progress = ProgressDialog(this)
|
|
|
progress.setTitle(R.string.setting_up_encryption)
|
|
|
progress.setMessage(getString(R.string.setting_up_encryption_content))
|
|
|
progress.isIndeterminate = true
|
|
|
progress.setCanceledOnTouchOutside(false)
|
|
|
progress.setCancelable(false)
|
|
|
progress.show()
|
|
|
}
|
|
|
.setNegativeButton(android.R.string.no) { _, _ -> }
|
|
|
.create().show()
|
|
|
}
|
|
|
|
|
|
companion object {
|
|
|
internal val EXTRA_ACCOUNT = "account"
|
|
|
|
|
|
fun newIntent(context: Context, account: Account): Intent {
|
|
|
val intent = Intent(context, ChangeEncryptionPasswordActivity::class.java)
|
|
|
intent.putExtra(CreateCollectionActivity.EXTRA_ACCOUNT, account)
|
|
|
return intent
|
|
|
}
|
|
|
}
|
|
|
}
|