mirror of
https://github.com/Kunzisoft/KeePassDX.git
synced 2025-12-04 15:49:33 +01:00
Add temp advanced service to store encrypted elements
This commit is contained in:
@@ -174,13 +174,17 @@
|
|||||||
android:enabled="true"
|
android:enabled="true"
|
||||||
android:exported="false" />
|
android:exported="false" />
|
||||||
<service
|
<service
|
||||||
android:name=".notifications.AttachmentFileNotificationService"
|
android:name="com.kunzisoft.keepass.notifications.AttachmentFileNotificationService"
|
||||||
android:enabled="true"
|
android:enabled="true"
|
||||||
android:exported="false" />
|
android:exported="false" />
|
||||||
<service
|
<service
|
||||||
android:name="com.kunzisoft.keepass.notifications.ClipboardEntryNotificationService"
|
android:name="com.kunzisoft.keepass.notifications.ClipboardEntryNotificationService"
|
||||||
android:enabled="true"
|
android:enabled="true"
|
||||||
android:exported="false" />
|
android:exported="false" />
|
||||||
|
<service
|
||||||
|
android:name="com.kunzisoft.keepass.notifications.AdvancedUnlockNotificationService"
|
||||||
|
android:enabled="true"
|
||||||
|
android:exported="false" />
|
||||||
<!-- Receiver for Autofill -->
|
<!-- Receiver for Autofill -->
|
||||||
<service
|
<service
|
||||||
android:name="com.kunzisoft.keepass.autofill.KeeAutofillService"
|
android:name="com.kunzisoft.keepass.autofill.KeeAutofillService"
|
||||||
|
|||||||
@@ -19,27 +19,78 @@
|
|||||||
*/
|
*/
|
||||||
package com.kunzisoft.keepass.app.database
|
package com.kunzisoft.keepass.app.database
|
||||||
|
|
||||||
|
import android.content.ComponentName
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.content.ServiceConnection
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
|
import android.os.IBinder
|
||||||
|
import com.kunzisoft.keepass.notifications.AdvancedUnlockNotificationService
|
||||||
|
import com.kunzisoft.keepass.settings.PreferencesUtil
|
||||||
import com.kunzisoft.keepass.utils.SingletonHolderParameter
|
import com.kunzisoft.keepass.utils.SingletonHolderParameter
|
||||||
|
|
||||||
class CipherDatabaseAction(applicationContext: Context) {
|
class CipherDatabaseAction(context: Context) {
|
||||||
|
|
||||||
|
private val applicationContext = context.applicationContext
|
||||||
private val cipherDatabaseDao =
|
private val cipherDatabaseDao =
|
||||||
AppDatabase
|
AppDatabase
|
||||||
.getDatabase(applicationContext)
|
.getDatabase(applicationContext)
|
||||||
.cipherDatabaseDao()
|
.cipherDatabaseDao()
|
||||||
|
|
||||||
|
// Temp DAO to easily remove content if object no longer in memory
|
||||||
|
private val useTempDao = PreferencesUtil.isTempAdvancedUnlockEnable(applicationContext)
|
||||||
|
|
||||||
|
private val mIntentAdvancedUnlockService = Intent(applicationContext,
|
||||||
|
AdvancedUnlockNotificationService::class.java)
|
||||||
|
private var mBinder: AdvancedUnlockNotificationService.AdvancedUnlockBinder? = null
|
||||||
|
private var mServiceConnection: ServiceConnection? = null
|
||||||
|
|
||||||
|
fun initialize() {
|
||||||
|
applicationContext.startService(mIntentAdvancedUnlockService)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Synchronized
|
||||||
|
private fun getTempCipherDao(tempCipherDaoRetrieved: (MutableList<CipherDatabaseEntity>?) -> Unit) {
|
||||||
|
// Check if a service is currently running else do nothing
|
||||||
|
if (mBinder != null) {
|
||||||
|
tempCipherDaoRetrieved.invoke(mBinder?.getTempCipherDao())
|
||||||
|
} else if (mServiceConnection == null) {
|
||||||
|
mServiceConnection = object : ServiceConnection {
|
||||||
|
override fun onServiceConnected(name: ComponentName?, serviceBinder: IBinder?) {
|
||||||
|
mBinder = (serviceBinder as AdvancedUnlockNotificationService.AdvancedUnlockBinder)
|
||||||
|
tempCipherDaoRetrieved.invoke(mBinder?.getTempCipherDao())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onServiceDisconnected(name: ComponentName?) {
|
||||||
|
mBinder = null
|
||||||
|
mServiceConnection = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// bind Service
|
||||||
|
mServiceConnection?.let {
|
||||||
|
applicationContext.bindService(mIntentAdvancedUnlockService,
|
||||||
|
it,
|
||||||
|
Context.BIND_ABOVE_CLIENT)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun getCipherDatabase(databaseUri: Uri,
|
fun getCipherDatabase(databaseUri: Uri,
|
||||||
cipherDatabaseResultListener: (CipherDatabaseEntity?) -> Unit) {
|
cipherDatabaseResultListener: (CipherDatabaseEntity?) -> Unit) {
|
||||||
IOActionTask(
|
if (useTempDao) {
|
||||||
{
|
getTempCipherDao { tempCipherDao ->
|
||||||
cipherDatabaseDao.getByDatabaseUri(databaseUri.toString())
|
cipherDatabaseResultListener.invoke(tempCipherDao?.firstOrNull { it.databaseUri == databaseUri.toString()})
|
||||||
},
|
}
|
||||||
{
|
} else {
|
||||||
cipherDatabaseResultListener.invoke(it)
|
IOActionTask(
|
||||||
}
|
{
|
||||||
).execute()
|
cipherDatabaseDao.getByDatabaseUri(databaseUri.toString())
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cipherDatabaseResultListener.invoke(it)
|
||||||
|
}
|
||||||
|
).execute()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun containsCipherDatabase(databaseUri: Uri,
|
fun containsCipherDatabase(databaseUri: Uri,
|
||||||
@@ -51,25 +102,38 @@ class CipherDatabaseAction(applicationContext: Context) {
|
|||||||
|
|
||||||
fun addOrUpdateCipherDatabase(cipherDatabaseEntity: CipherDatabaseEntity,
|
fun addOrUpdateCipherDatabase(cipherDatabaseEntity: CipherDatabaseEntity,
|
||||||
cipherDatabaseResultListener: (() -> Unit)? = null) {
|
cipherDatabaseResultListener: (() -> Unit)? = null) {
|
||||||
IOActionTask(
|
if (useTempDao) {
|
||||||
{
|
getTempCipherDao { tempCipherDao ->
|
||||||
val cipherDatabaseRetrieve = cipherDatabaseDao.getByDatabaseUri(cipherDatabaseEntity.databaseUri)
|
val cipherDatabaseRetrieve = tempCipherDao?.firstOrNull { it.databaseUri == cipherDatabaseEntity.databaseUri }
|
||||||
|
cipherDatabaseRetrieve?.replaceContent(cipherDatabaseEntity)
|
||||||
// Update values if element not yet in the database
|
?: tempCipherDao?.add(cipherDatabaseEntity)
|
||||||
if (cipherDatabaseRetrieve == null) {
|
cipherDatabaseResultListener?.invoke()
|
||||||
cipherDatabaseDao.add(cipherDatabaseEntity)
|
}
|
||||||
} else {
|
} else {
|
||||||
cipherDatabaseDao.update(cipherDatabaseEntity)
|
IOActionTask(
|
||||||
|
{
|
||||||
|
val cipherDatabaseRetrieve = cipherDatabaseDao.getByDatabaseUri(cipherDatabaseEntity.databaseUri)
|
||||||
|
// Update values if element not yet in the database
|
||||||
|
if (cipherDatabaseRetrieve == null) {
|
||||||
|
cipherDatabaseDao.add(cipherDatabaseEntity)
|
||||||
|
} else {
|
||||||
|
cipherDatabaseDao.update(cipherDatabaseEntity)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cipherDatabaseResultListener?.invoke()
|
||||||
}
|
}
|
||||||
},
|
).execute()
|
||||||
{
|
}
|
||||||
cipherDatabaseResultListener?.invoke()
|
|
||||||
}
|
|
||||||
).execute()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun deleteByDatabaseUri(databaseUri: Uri,
|
fun deleteByDatabaseUri(databaseUri: Uri,
|
||||||
cipherDatabaseResultListener: (() -> Unit)? = null) {
|
cipherDatabaseResultListener: (() -> Unit)? = null) {
|
||||||
|
getTempCipherDao { tempCipherDao ->
|
||||||
|
tempCipherDao?.firstOrNull { it.databaseUri == databaseUri.toString() }?.let {
|
||||||
|
tempCipherDao.remove(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
IOActionTask(
|
IOActionTask(
|
||||||
{
|
{
|
||||||
cipherDatabaseDao.deleteByDatabaseUri(databaseUri.toString())
|
cipherDatabaseDao.deleteByDatabaseUri(databaseUri.toString())
|
||||||
@@ -81,6 +145,9 @@ class CipherDatabaseAction(applicationContext: Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun deleteAll() {
|
fun deleteAll() {
|
||||||
|
getTempCipherDao { tempCipherDao ->
|
||||||
|
tempCipherDao?.clear()
|
||||||
|
}
|
||||||
IOActionTask(
|
IOActionTask(
|
||||||
{
|
{
|
||||||
cipherDatabaseDao.deleteAll()
|
cipherDatabaseDao.deleteAll()
|
||||||
|
|||||||
@@ -43,6 +43,11 @@ data class CipherDatabaseEntity(
|
|||||||
parcel.readString()!!,
|
parcel.readString()!!,
|
||||||
parcel.readString()!!)
|
parcel.readString()!!)
|
||||||
|
|
||||||
|
fun replaceContent(copy: CipherDatabaseEntity) {
|
||||||
|
this.encryptedValue = copy.encryptedValue
|
||||||
|
this.specParameters = copy.specParameters
|
||||||
|
}
|
||||||
|
|
||||||
override fun writeToParcel(parcel: Parcel, flags: Int) {
|
override fun writeToParcel(parcel: Parcel, flags: Int) {
|
||||||
parcel.writeString(databaseUri)
|
parcel.writeString(databaseUri)
|
||||||
parcel.writeString(encryptedValue)
|
parcel.writeString(encryptedValue)
|
||||||
|
|||||||
@@ -78,6 +78,7 @@ class AdvancedUnlockedManager(var context: FragmentActivity,
|
|||||||
// Add old listener to enable the button, only be call here because of onCheckedChange bug
|
// Add old listener to enable the button, only be call here because of onCheckedChange bug
|
||||||
onCheckedPasswordChangeListener?.onCheckedChanged(compoundButton, checked)
|
onCheckedPasswordChangeListener?.onCheckedChanged(compoundButton, checked)
|
||||||
}
|
}
|
||||||
|
cipherDatabaseAction.initialize()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -0,0 +1,74 @@
|
|||||||
|
package com.kunzisoft.keepass.notifications
|
||||||
|
|
||||||
|
import android.app.PendingIntent
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Binder
|
||||||
|
import android.os.IBinder
|
||||||
|
import com.kunzisoft.keepass.R
|
||||||
|
import com.kunzisoft.keepass.app.database.CipherDatabaseEntity
|
||||||
|
|
||||||
|
class AdvancedUnlockNotificationService : NotificationService() {
|
||||||
|
|
||||||
|
private lateinit var mTempCipherDao: ArrayList<CipherDatabaseEntity>
|
||||||
|
|
||||||
|
private var mActionTaskBinder = AdvancedUnlockBinder()
|
||||||
|
|
||||||
|
inner class AdvancedUnlockBinder: Binder() {
|
||||||
|
fun getTempCipherDao(): MutableList<CipherDatabaseEntity> {
|
||||||
|
return mTempCipherDao
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override val notificationId: Int = 593
|
||||||
|
|
||||||
|
override fun retrieveChannelId(): String {
|
||||||
|
return CHANNEL_ADVANCED_UNLOCK_ID
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBind(intent: Intent): IBinder? {
|
||||||
|
super.onBind(intent)
|
||||||
|
return mActionTaskBinder
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||||
|
super.onStartCommand(intent, flags, startId)
|
||||||
|
|
||||||
|
val deleteIntent = Intent(this, AdvancedUnlockNotificationService::class.java).apply {
|
||||||
|
action = ACTION_REMOVE_KEYS
|
||||||
|
}
|
||||||
|
val pendingDeleteIntent = PendingIntent.getService(this, 0, deleteIntent, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||||
|
val notificationBuilder = buildNewNotification().apply {
|
||||||
|
setSmallIcon(R.drawable.bolt)
|
||||||
|
intent?.let {
|
||||||
|
setContentTitle(getString(R.string.advanced_unlock))
|
||||||
|
}
|
||||||
|
setContentText(getString(R.string.advanced_unlock_tap_delete))
|
||||||
|
setContentIntent(pendingDeleteIntent)
|
||||||
|
// Unfortunately swipe is disabled in lollipop+
|
||||||
|
setDeleteIntent(pendingDeleteIntent)
|
||||||
|
}
|
||||||
|
startForeground(notificationId, notificationBuilder.build())
|
||||||
|
|
||||||
|
if (intent?.action == ACTION_REMOVE_KEYS) {
|
||||||
|
stopSelf()
|
||||||
|
}
|
||||||
|
|
||||||
|
return START_STICKY
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreate() {
|
||||||
|
super.onCreate()
|
||||||
|
mTempCipherDao = ArrayList()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
mTempCipherDao.clear()
|
||||||
|
super.onDestroy()
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val CHANNEL_ADVANCED_UNLOCK_ID = "com.kunzisoft.keepass.notification.channel.unlock"
|
||||||
|
|
||||||
|
const val ACTION_REMOVE_KEYS = "ACTION_REMOVE_KEYS"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -319,6 +319,7 @@
|
|||||||
<string name="lock_database_show_button_summary">Displays the lock button in the user interface</string>
|
<string name="lock_database_show_button_summary">Displays the lock button in the user interface</string>
|
||||||
<string name="content">Content</string>
|
<string name="content">Content</string>
|
||||||
<string name="advanced_unlock">Advanced unlock</string>
|
<string name="advanced_unlock">Advanced unlock</string>
|
||||||
|
<string name="advanced_unlock_tap_delete">Tap to delete advanced unlocking keys</string>
|
||||||
<string name="advanced_unlock_explanation_summary">Use advanced unlocking to open a database more easily</string>
|
<string name="advanced_unlock_explanation_summary">Use advanced unlocking to open a database more easily</string>
|
||||||
<string name="biometric_unlock_enable_title">Biometric unlocking</string>
|
<string name="biometric_unlock_enable_title">Biometric unlocking</string>
|
||||||
<string name="biometric_unlock_enable_summary">Lets you scan your biometric to open the database</string>
|
<string name="biometric_unlock_enable_summary">Lets you scan your biometric to open the database</string>
|
||||||
|
|||||||
@@ -54,7 +54,7 @@
|
|||||||
android:dependency="@string/temp_advanced_unlock_enable_key"
|
android:dependency="@string/temp_advanced_unlock_enable_key"
|
||||||
android:entries="@array/timeout_options"
|
android:entries="@array/timeout_options"
|
||||||
android:entryValues="@array/timeout_values"
|
android:entryValues="@array/timeout_values"
|
||||||
android:dialogTitle="@string/clipboard_timeout"
|
android:dialogTitle="@string/advanced_unlock_timeout"
|
||||||
android:defaultValue="@string/temp_advanced_unlock_timeout_default"/>
|
android:defaultValue="@string/temp_advanced_unlock_timeout_default"/>
|
||||||
<Preference
|
<Preference
|
||||||
android:key="@string/biometric_delete_all_key_key"
|
android:key="@string/biometric_delete_all_key_key"
|
||||||
|
|||||||
Reference in New Issue
Block a user